Improve dockapp recognition
[wmaker-crm.git] / src / xmodifier.c
blobc6d3e454f709288fe6e4a5f9c6c3f68560d5abc4
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
26 along with XEmacs; see the file COPYING. If not, write to
27 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
28 Boston, MA 02111-1307, USA. */
30 #include "wconfig.h"
32 #include <string.h>
33 #include <X11/Xlib.h>
34 #include <X11/keysym.h>
36 #include <WINGs/WUtil.h>
37 #include "xmodifier.h"
39 extern Display *dpy;
41 /************************************************************************/
42 /* keymap handling */
43 /************************************************************************/
45 /* X bogusly doesn't define the interpretations of any bits besides
46 ModControl, ModShift, and ModLock; so the Interclient Communication
47 Conventions Manual says that we have to bend over backwards to figure
48 out what the other modifier bits mean. According to ICCCM:
50 - Any keycode which is assigned ModControl is a "control" key.
52 - Any modifier bit which is assigned to a keycode which generates Meta_L
53 or Meta_R is the modifier bit meaning "meta". Likewise for Super, Hyper,
54 etc.
56 - Any keypress event which contains ModControl in its state should be
57 interpreted as a "control" character.
59 - Any keypress event which contains a modifier bit in its state which is
60 generated by a keycode whose corresponding keysym is Meta_L or Meta_R
61 should be interpreted as a "meta" character. Likewise for Super, Hyper,
62 etc.
64 - It is illegal for a keysym to be associated with more than one modifier
65 bit.
67 This means that the only thing that emacs can reasonably interpret as a
68 "meta" key is a key whose keysym is Meta_L or Meta_R, and which generates
69 one of the modifier bits Mod1-Mod5.
71 Unfortunately, many keyboards don't have Meta keys in their default
72 configuration. So, if there are no Meta keys, but there are "Alt" keys,
73 emacs will interpret Alt as Meta. If there are both Meta and Alt keys,
74 then the Meta keys mean "Meta", and the Alt keys mean "Alt" (it used to
75 mean "Symbol," but that just confused the hell out of way too many people).
77 This works with the default configurations of the 19 keyboard-types I've
78 checked.
80 Emacs detects keyboard configurations which violate the above rules, and
81 prints an error message on the standard-error-output. (Perhaps it should
82 use a pop-up-window instead.)
85 static int MetaMask, HyperMask, SuperMask, AltMask, ModeMask;
87 static const char *index_to_name(int indice)
89 switch (indice) {
90 case ShiftMapIndex:
91 return "ModShift";
92 case LockMapIndex:
93 return "ModLock";
94 case ControlMapIndex:
95 return "ModControl";
96 case Mod1MapIndex:
97 return "Mod1";
98 case Mod2MapIndex:
99 return "Mod2";
100 case Mod3MapIndex:
101 return "Mod3";
102 case Mod4MapIndex:
103 return "Mod4";
104 case Mod5MapIndex:
105 return "Mod5";
106 default:
107 return "???";
111 static void x_reset_modifier_mapping(Display * display)
113 int modifier_index, modifier_key, column, mkpm;
114 int warned_about_overlapping_modifiers = 0;
115 int warned_about_predefined_modifiers = 0;
116 int warned_about_duplicate_modifiers = 0;
117 int meta_bit = 0;
118 int hyper_bit = 0;
119 int super_bit = 0;
120 int alt_bit = 0;
121 int mode_bit = 0;
122 XModifierKeymap *x_modifier_keymap = XGetModifierMapping(display);
124 #define modwarn(name,old,other) \
125 wwarning ("%s (0x%x) generates %s, which is generated by %s.\n\n", \
126 name, code, index_to_name (old), other), \
127 warned_about_overlapping_modifiers = 1
129 #define modbarf(name,other) \
130 wwarning ("%s (0x%x) generates %s, which is nonsensical.\n\n", \
131 name, code, other), \
132 warned_about_predefined_modifiers = 1
134 #define check_modifier(name,mask) \
135 if ((1<<modifier_index) != mask) \
136 wwarning ("%s (0x%x) generates %s, which is nonsensical.\n\n", \
137 name, code, index_to_name (modifier_index)), \
138 warned_about_predefined_modifiers = 1
140 #define store_modifier(name,old) \
141 if (old && old != modifier_index) \
142 wwarning ("%s (0x%x) generates both %s and %s, which is nonsensical.\n\n",\
143 name, code, index_to_name (old), \
144 index_to_name (modifier_index)), \
145 warned_about_duplicate_modifiers = 1; \
146 if (modifier_index == ShiftMapIndex) modbarf (name,"ModShift"); \
147 else if (modifier_index == LockMapIndex) modbarf (name,"ModLock"); \
148 else if (modifier_index == ControlMapIndex) modbarf (name,"ModControl"); \
149 else if (sym == XK_Mode_switch) \
150 mode_bit = modifier_index; /* Mode_switch is special, see below... */ \
151 else if (modifier_index == meta_bit && old != meta_bit) \
152 modwarn (name, meta_bit, "Meta"); \
153 else if (modifier_index == super_bit && old != super_bit) \
154 modwarn (name, super_bit, "Super"); \
155 else if (modifier_index == hyper_bit && old != hyper_bit) \
156 modwarn (name, hyper_bit, "Hyper"); \
157 else if (modifier_index == alt_bit && old != alt_bit) \
158 modwarn (name, alt_bit, "Alt"); \
159 else \
160 old = modifier_index;
162 mkpm = x_modifier_keymap->max_keypermod;
163 for (modifier_index = 0; modifier_index < 8; modifier_index++)
164 for (modifier_key = 0; modifier_key < mkpm; modifier_key++) {
165 KeySym last_sym = 0;
166 for (column = 0; column < 4; column += 2) {
167 KeyCode code = x_modifier_keymap->modifiermap[modifier_index * mkpm
168 + modifier_key];
169 KeySym sym = (code ? XKeycodeToKeysym(display, code, column) : 0);
170 if (sym == last_sym)
171 continue;
172 last_sym = sym;
173 switch (sym) {
174 case XK_Mode_switch:
175 store_modifier("Mode_switch", mode_bit);
176 break;
177 case XK_Meta_L:
178 store_modifier("Meta_L", meta_bit);
179 break;
180 case XK_Meta_R:
181 store_modifier("Meta_R", meta_bit);
182 break;
183 case XK_Super_L:
184 store_modifier("Super_L", super_bit);
185 break;
186 case XK_Super_R:
187 store_modifier("Super_R", super_bit);
188 break;
189 case XK_Hyper_L:
190 store_modifier("Hyper_L", hyper_bit);
191 break;
192 case XK_Hyper_R:
193 store_modifier("Hyper_R", hyper_bit);
194 break;
195 case XK_Alt_L:
196 store_modifier("Alt_L", alt_bit);
197 break;
198 case XK_Alt_R:
199 store_modifier("Alt_R", alt_bit);
200 break;
201 case XK_Control_L:
202 check_modifier("Control_L", ControlMask);
203 break;
204 case XK_Control_R:
205 check_modifier("Control_R", ControlMask);
206 break;
207 case XK_Shift_L:
208 check_modifier("Shift_L", ShiftMask);
209 break;
210 case XK_Shift_R:
211 check_modifier("Shift_R", ShiftMask);
212 break;
213 case XK_Shift_Lock:
214 check_modifier("Shift_Lock", LockMask);
215 break;
216 case XK_Caps_Lock:
217 check_modifier("Caps_Lock", LockMask);
218 break;
220 /* It probably doesn't make any sense for a modifier bit to be
221 assigned to a key that is not one of the above, but OpenWindows
222 assigns modifier bits to a couple of random function keys for
223 no reason that I can discern, so printing a warning here would
224 be annoying. */
228 #undef store_modifier
229 #undef check_modifier
230 #undef modwarn
231 #undef modbarf
233 /* If there was no Meta key, then try using the Alt key instead.
234 If there is both a Meta key and an Alt key, then the Alt key
235 is not disturbed and remains an Alt key. */
236 if (!meta_bit && alt_bit)
237 meta_bit = alt_bit, alt_bit = 0;
239 /* mode_bit overrides everything, since it's processed down inside of
240 XLookupString() instead of by us. If Meta and Mode_switch both
241 generate the same modifier bit (which is an error), then we don't
242 interpret that bit as Meta, because we can't make XLookupString()
243 not interpret it as Mode_switch; and interpreting it as both would
244 be totally wrong. */
245 if (mode_bit) {
246 const char *warn = 0;
247 if (mode_bit == meta_bit)
248 warn = "Meta", meta_bit = 0;
249 else if (mode_bit == hyper_bit)
250 warn = "Hyper", hyper_bit = 0;
251 else if (mode_bit == super_bit)
252 warn = "Super", super_bit = 0;
253 else if (mode_bit == alt_bit)
254 warn = "Alt", alt_bit = 0;
255 if (warn) {
256 wwarning
257 ("%s is being used for both Mode_switch and %s.\n\n",
258 index_to_name(mode_bit), warn), warned_about_overlapping_modifiers = 1;
262 MetaMask = (meta_bit ? (1 << meta_bit) : 0);
263 HyperMask = (hyper_bit ? (1 << hyper_bit) : 0);
264 SuperMask = (super_bit ? (1 << super_bit) : 0);
265 AltMask = (alt_bit ? (1 << alt_bit) : 0);
266 ModeMask = (mode_bit ? (1 << mode_bit) : 0); /* unused */
268 #if 0
269 if (warned_about_overlapping_modifiers)
270 wwarning("\n"
271 " Two distinct modifier keys (such as Meta and Hyper) cannot generate\n"
272 " the same modifier bit, because Emacs won't be able to tell which\n"
273 " modifier was actually held down when some other key is pressed. It\n"
274 " won't be able to tell Meta-x and Hyper-x apart, for example. Change\n"
275 " one of these keys to use some other modifier bit. If you intend for\n"
276 " these keys to have the same behavior, then change them to have the\n"
277 " same keysym as well as the same modifier bit.\n");
279 if (warned_about_predefined_modifiers)
280 wwarning("\n"
281 " The semantics of the modifier bits ModShift, ModLock, and ModControl\n"
282 " are predefined. It does not make sense to assign ModControl to any\n"
283 " keysym other than Control_L or Control_R, or to assign any modifier\n"
284 " bits to the \"control\" keysyms other than ModControl. You can't\n"
285 " turn a \"control\" key into a \"meta\" key (or vice versa) by simply\n"
286 " assigning the key a different modifier bit. You must also make that\n"
287 " key generate an appropriate keysym (Control_L, Meta_L, etc).\n");
289 /* No need to say anything more for warned_about_duplicate_modifiers. */
291 if (warned_about_overlapping_modifiers || warned_about_predefined_modifiers)
292 wwarning("\n"
293 " The meanings of the modifier bits Mod1 through Mod5 are determined\n"
294 " by the keysyms used to control those bits. Mod1 does NOT always\n"
295 " mean Meta, although some non-ICCCM-compliant programs assume that.\n");
296 #endif
297 XFreeModifiermap(x_modifier_keymap);
300 int wXModifierFromKey(char *key)
302 if (strcasecmp(key, "SHIFT") == 0 && ShiftMask != 0)
303 return ShiftMask;
304 else if (strcasecmp(key, "CONTROL") == 0 && ControlMask != 0)
305 return ControlMask;
306 else if (strcasecmp(key, "ALT") == 0 && AltMask != 0)
307 return AltMask;
308 else if (strcasecmp(key, "META") == 0 && MetaMask != 0)
309 return MetaMask;
310 else if (strcasecmp(key, "SUPER") == 0 && SuperMask != 0)
311 return SuperMask;
312 else if (strcasecmp(key, "HYPER") == 0 && HyperMask != 0)
313 return HyperMask;
314 else if (strcasecmp(key, "MOD1") == 0 && Mod1Mask != 0)
315 return Mod1Mask;
316 else if (strcasecmp(key, "MOD2") == 0 && Mod2Mask != 0)
317 return Mod2Mask;
318 else if (strcasecmp(key, "MOD3") == 0 && Mod3Mask != 0)
319 return Mod3Mask;
320 else if (strcasecmp(key, "MOD4") == 0 && Mod4Mask != 0)
321 return Mod4Mask;
322 else if (strcasecmp(key, "MOD5") == 0 && Mod5Mask != 0)
323 return Mod5Mask;
324 else
325 return -1;
328 /* Wrapper so that we may fit the WM naming conventions, yet leave the
329 original XEmacs function name in place. */
330 void wXModifierInitialize(void)
332 x_reset_modifier_mapping(dpy);