WINGs: Add copy_file() to libWUtil
[wmaker-crm.git] / src / xmodifier.c
blob7bae013f41d646796d1b4dc66e5e76f4106bfac5
1 /* Grok X modifier mappings for shortcuts.
3 Most of this code was taken from src/event-Xt.c in XEmacs 20.3-b17.
4 The copyright(s) from the original XEmacs code are included below.
6 Perpetrator: Sudish Joseph <sj@eng.mindspring.net>, Sept. 1997. */
8 /* The event_stream interface for X11 with Xt, and/or tty frames.
9 Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
10 Copyright (C) 1995 Sun Microsystems, Inc.
11 Copyright (C) 1996 Ben Wing.
13 This file is part of XEmacs.
15 XEmacs is free software; you can redistribute it and/or modify it
16 under the terms of the GNU General Public License as published by the
17 Free Software Foundation; either version 2, or (at your option) any
18 later version.
20 XEmacs is distributed in the hope that it will be useful, but WITHOUT
21 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
22 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
23 for more details.
25 You should have received a copy of the GNU General Public License along
26 with XEmacs; see the file COPYING. if not, write to the
27 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
28 Boston, MA 02110-1301 USA. */
30 #include "wconfig.h"
32 #include <string.h>
33 #include <strings.h>
34 #include <X11/Xlib.h>
35 #include <X11/keysym.h>
37 #include <WINGs/WUtil.h>
38 #include "xmodifier.h"
40 extern Display *dpy;
42 /************************************************************************/
43 /* keymap handling */
44 /************************************************************************/
46 /* X bogusly doesn't define the interpretations of any bits besides
47 ModControl, ModShift, and ModLock; so the Interclient Communication
48 Conventions Manual says that we have to bend over backwards to figure
49 out what the other modifier bits mean. According to ICCCM:
51 - Any keycode which is assigned ModControl is a "control" key.
53 - Any modifier bit which is assigned to a keycode which generates Meta_L
54 or Meta_R is the modifier bit meaning "meta". Likewise for Super, Hyper,
55 etc.
57 - Any keypress event which contains ModControl in its state should be
58 interpreted as a "control" character.
60 - Any keypress event which contains a modifier bit in its state which is
61 generated by a keycode whose corresponding keysym is Meta_L or Meta_R
62 should be interpreted as a "meta" character. Likewise for Super, Hyper,
63 etc.
65 - It is illegal for a keysym to be associated with more than one modifier
66 bit.
68 This means that the only thing that emacs can reasonably interpret as a
69 "meta" key is a key whose keysym is Meta_L or Meta_R, and which generates
70 one of the modifier bits Mod1-Mod5.
72 Unfortunately, many keyboards don't have Meta keys in their default
73 configuration. So, if there are no Meta keys, but there are "Alt" keys,
74 emacs will interpret Alt as Meta. If there are both Meta and Alt keys,
75 then the Meta keys mean "Meta", and the Alt keys mean "Alt" (it used to
76 mean "Symbol," but that just confused the hell out of way too many people).
78 This works with the default configurations of the 19 keyboard-types I've
79 checked.
81 Emacs detects keyboard configurations which violate the above rules, and
82 prints an error message on the standard-error-output. (Perhaps it should
83 use a pop-up-window instead.)
86 static int MetaMask, HyperMask, SuperMask, AltMask, ModeMask;
88 static const char *index_to_name(int indice)
90 switch (indice) {
91 case ShiftMapIndex:
92 return "ModShift";
93 case LockMapIndex:
94 return "ModLock";
95 case ControlMapIndex:
96 return "ModControl";
97 case Mod1MapIndex:
98 return "Mod1";
99 case Mod2MapIndex:
100 return "Mod2";
101 case Mod3MapIndex:
102 return "Mod3";
103 case Mod4MapIndex:
104 return "Mod4";
105 case Mod5MapIndex:
106 return "Mod5";
107 default:
108 return "???";
112 static void x_reset_modifier_mapping(Display * display)
114 int modifier_index, modifier_key, column, mkpm;
115 int meta_bit = 0;
116 int hyper_bit = 0;
117 int super_bit = 0;
118 int alt_bit = 0;
119 int mode_bit = 0;
120 XModifierKeymap *x_modifier_keymap = XGetModifierMapping(display);
122 #define modwarn(name,old,other) \
123 wwarning ("%s (0x%x) generates %s, which is generated by %s.", \
124 name, code, index_to_name (old), other)
126 #define modbarf(name,other) \
127 wwarning ("%s (0x%x) generates %s, which is nonsensical.", \
128 name, code, other)
130 #define check_modifier(name,mask) \
131 if ((1<<modifier_index) != mask) \
132 wwarning ("%s (0x%x) generates %s, which is nonsensical.", \
133 name, code, index_to_name (modifier_index))
135 #define store_modifier(name,old) \
136 if (old && old != modifier_index) \
137 wwarning ("%s (0x%x) generates both %s and %s, which is nonsensical.", \
138 name, code, index_to_name (old), \
139 index_to_name (modifier_index)); \
140 if (modifier_index == ShiftMapIndex) modbarf (name,"ModShift"); \
141 else if (modifier_index == LockMapIndex) modbarf (name,"ModLock"); \
142 else if (modifier_index == ControlMapIndex) modbarf (name,"ModControl"); \
143 else if (sym == XK_Mode_switch) \
144 mode_bit = modifier_index; /* Mode_switch is special, see below... */ \
145 else if (modifier_index == meta_bit && old != meta_bit) \
146 modwarn (name, meta_bit, "Meta"); \
147 else if (modifier_index == super_bit && old != super_bit) \
148 modwarn (name, super_bit, "Super"); \
149 else if (modifier_index == hyper_bit && old != hyper_bit) \
150 modwarn (name, hyper_bit, "Hyper"); \
151 else if (modifier_index == alt_bit && old != alt_bit) \
152 modwarn (name, alt_bit, "Alt"); \
153 else \
154 old = modifier_index;
156 mkpm = x_modifier_keymap->max_keypermod;
157 for (modifier_index = 0; modifier_index < 8; modifier_index++)
158 for (modifier_key = 0; modifier_key < mkpm; modifier_key++) {
159 KeySym last_sym = 0;
160 for (column = 0; column < 4; column += 2) {
161 KeyCode code = x_modifier_keymap->modifiermap[modifier_index * mkpm
162 + modifier_key];
163 KeySym sym = (code ? XKeycodeToKeysym(display, code, column) : 0);
164 if (sym == last_sym)
165 continue;
166 last_sym = sym;
167 switch (sym) {
168 case XK_Mode_switch:
169 store_modifier("Mode_switch", mode_bit);
170 break;
171 case XK_Meta_L:
172 store_modifier("Meta_L", meta_bit);
173 break;
174 case XK_Meta_R:
175 store_modifier("Meta_R", meta_bit);
176 break;
177 case XK_Super_L:
178 store_modifier("Super_L", super_bit);
179 break;
180 case XK_Super_R:
181 store_modifier("Super_R", super_bit);
182 break;
183 case XK_Hyper_L:
184 store_modifier("Hyper_L", hyper_bit);
185 break;
186 case XK_Hyper_R:
187 store_modifier("Hyper_R", hyper_bit);
188 break;
189 case XK_Alt_L:
190 store_modifier("Alt_L", alt_bit);
191 break;
192 case XK_Alt_R:
193 store_modifier("Alt_R", alt_bit);
194 break;
195 case XK_Control_L:
196 check_modifier("Control_L", ControlMask);
197 break;
198 case XK_Control_R:
199 check_modifier("Control_R", ControlMask);
200 break;
201 case XK_Shift_L:
202 check_modifier("Shift_L", ShiftMask);
203 break;
204 case XK_Shift_R:
205 check_modifier("Shift_R", ShiftMask);
206 break;
207 case XK_Shift_Lock:
208 check_modifier("Shift_Lock", LockMask);
209 break;
210 case XK_Caps_Lock:
211 check_modifier("Caps_Lock", LockMask);
212 break;
214 /* It probably doesn't make any sense for a modifier bit to be
215 assigned to a key that is not one of the above, but OpenWindows
216 assigns modifier bits to a couple of random function keys for
217 no reason that I can discern, so printing a warning here would
218 be annoying. */
222 #undef store_modifier
223 #undef check_modifier
224 #undef modwarn
225 #undef modbarf
227 /* If there was no Meta key, then try using the Alt key instead.
228 If there is both a Meta key and an Alt key, then the Alt key
229 is not disturbed and remains an Alt key. */
230 if (!meta_bit && alt_bit)
231 meta_bit = alt_bit, alt_bit = 0;
233 /* mode_bit overrides everything, since it's processed down inside of
234 XLookupString() instead of by us. If Meta and Mode_switch both
235 generate the same modifier bit (which is an error), then we don't
236 interpret that bit as Meta, because we can't make XLookupString()
237 not interpret it as Mode_switch; and interpreting it as both would
238 be totally wrong. */
239 if (mode_bit) {
240 const char *warn = 0;
241 if (mode_bit == meta_bit)
242 warn = "Meta", meta_bit = 0;
243 else if (mode_bit == hyper_bit)
244 warn = "Hyper", hyper_bit = 0;
245 else if (mode_bit == super_bit)
246 warn = "Super", super_bit = 0;
247 else if (mode_bit == alt_bit)
248 warn = "Alt", alt_bit = 0;
249 if (warn) {
250 wwarning("%s is being used for both Mode_switch and %s.",
251 index_to_name(mode_bit), warn);
255 MetaMask = (meta_bit ? (1 << meta_bit) : 0);
256 HyperMask = (hyper_bit ? (1 << hyper_bit) : 0);
257 SuperMask = (super_bit ? (1 << super_bit) : 0);
258 AltMask = (alt_bit ? (1 << alt_bit) : 0);
259 ModeMask = (mode_bit ? (1 << mode_bit) : 0); /* unused */
261 XFreeModifiermap(x_modifier_keymap);
264 int wXModifierFromKey(char *key)
266 if (strcasecmp(key, "SHIFT") == 0 && ShiftMask != 0)
267 return ShiftMask;
268 else if (strcasecmp(key, "CONTROL") == 0 && ControlMask != 0)
269 return ControlMask;
270 else if (strcasecmp(key, "ALT") == 0 && AltMask != 0)
271 return AltMask;
272 else if (strcasecmp(key, "META") == 0 && MetaMask != 0)
273 return MetaMask;
274 else if (strcasecmp(key, "SUPER") == 0 && SuperMask != 0)
275 return SuperMask;
276 else if (strcasecmp(key, "HYPER") == 0 && HyperMask != 0)
277 return HyperMask;
278 else if (strcasecmp(key, "MOD1") == 0 && Mod1Mask != 0)
279 return Mod1Mask;
280 else if (strcasecmp(key, "MOD2") == 0 && Mod2Mask != 0)
281 return Mod2Mask;
282 else if (strcasecmp(key, "MOD3") == 0 && Mod3Mask != 0)
283 return Mod3Mask;
284 else if (strcasecmp(key, "MOD4") == 0 && Mod4Mask != 0)
285 return Mod4Mask;
286 else if (strcasecmp(key, "MOD5") == 0 && Mod5Mask != 0)
287 return Mod5Mask;
288 else
289 return -1;
292 /* Wrapper so that we may fit the WM naming conventions, yet leave the
293 original XEmacs function name in place. */
294 void wXModifierInitialize(void)
296 x_reset_modifier_mapping(dpy);