wmaker: removed unused constant SCROLL_STEPS in the switchpanel code
[wmaker-crm.git] / src / xmodifier.c
blob2fb246c822d0ec72c63c7e8d12cd0a49ff6bff30
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>
36 #include <X11/XKBlib.h>
38 #include <WINGs/WUtil.h>
39 #include "WindowMaker.h"
40 #include "xmodifier.h"
43 /************************************************************************/
44 /* keymap handling */
45 /************************************************************************/
47 /* X bogusly doesn't define the interpretations of any bits besides
48 ModControl, ModShift, and ModLock; so the Interclient Communication
49 Conventions Manual says that we have to bend over backwards to figure
50 out what the other modifier bits mean. According to ICCCM:
52 - Any keycode which is assigned ModControl is a "control" key.
54 - Any modifier bit which is assigned to a keycode which generates Meta_L
55 or Meta_R is the modifier bit meaning "meta". Likewise for Super, Hyper,
56 etc.
58 - Any keypress event which contains ModControl in its state should be
59 interpreted as a "control" character.
61 - Any keypress event which contains a modifier bit in its state which is
62 generated by a keycode whose corresponding keysym is Meta_L or Meta_R
63 should be interpreted as a "meta" character. Likewise for Super, Hyper,
64 etc.
66 - It is illegal for a keysym to be associated with more than one modifier
67 bit.
69 This means that the only thing that emacs can reasonably interpret as a
70 "meta" key is a key whose keysym is Meta_L or Meta_R, and which generates
71 one of the modifier bits Mod1-Mod5.
73 Unfortunately, many keyboards don't have Meta keys in their default
74 configuration. So, if there are no Meta keys, but there are "Alt" keys,
75 emacs will interpret Alt as Meta. If there are both Meta and Alt keys,
76 then the Meta keys mean "Meta", and the Alt keys mean "Alt" (it used to
77 mean "Symbol," but that just confused the hell out of way too many people).
79 This works with the default configurations of the 19 keyboard-types I've
80 checked.
82 Emacs detects keyboard configurations which violate the above rules, and
83 prints an error message on the standard-error-output. (Perhaps it should
84 use a pop-up-window instead.)
87 static int MetaMask, HyperMask, SuperMask, AltMask, ModeMask;
89 static const char *index_to_name(int indice)
91 switch (indice) {
92 case ShiftMapIndex:
93 return "ModShift";
94 case LockMapIndex:
95 return "ModLock";
96 case ControlMapIndex:
97 return "ModControl";
98 case Mod1MapIndex:
99 return "Mod1";
100 case Mod2MapIndex:
101 return "Mod2";
102 case Mod3MapIndex:
103 return "Mod3";
104 case Mod4MapIndex:
105 return "Mod4";
106 case Mod5MapIndex:
107 return "Mod5";
108 default:
109 return "???";
113 static void x_reset_modifier_mapping(Display * display)
115 int modifier_index, modifier_key, column, mkpm;
116 int meta_bit = 0;
117 int hyper_bit = 0;
118 int super_bit = 0;
119 int alt_bit = 0;
120 int mode_bit = 0;
121 XModifierKeymap *x_modifier_keymap = XGetModifierMapping(display);
123 mkpm = x_modifier_keymap->max_keypermod;
124 for (modifier_index = 0; modifier_index < 8; modifier_index++)
125 for (modifier_key = 0; modifier_key < mkpm; modifier_key++) {
126 KeySym last_sym = 0;
128 for (column = 0; column < 4; column += 2) {
129 KeyCode code;
130 KeySym sym;
132 inline void modwarn(const char *key_name, int old_mod, const char *other_key)
134 wwarning("key %s (0x%x) generates %s, which is generated by %s",
135 key_name, code, index_to_name(old_mod), other_key);
138 inline void modbarf(const char *key_name, const char *other_mod)
140 wwarning("key %s (0x%x) generates %s, which is nonsensical",
141 key_name, code, other_mod);
144 inline void check_modifier(const char *key_name, int mask)
146 if ((1 << modifier_index) != mask)
147 modbarf(key_name, index_to_name(modifier_index));
150 inline void store_modifier(const char *key_name, int *old_mod)
152 if (*old_mod && *old_mod != modifier_index)
153 wwarning("key %s (0x%x) generates both %s and %s, which is nonsensical",
154 key_name, code, index_to_name(*old_mod), index_to_name(modifier_index));
155 if (modifier_index == ShiftMapIndex) {
156 modbarf(key_name, "ModShift");
157 } else if (modifier_index == LockMapIndex) {
158 modbarf(key_name, "ModLock");
159 } else if (modifier_index == ControlMapIndex) {
160 modbarf(key_name, "ModControl");
161 } else if (sym == XK_Mode_switch) {
162 mode_bit = modifier_index; /* Mode_switch is special, see below... */
163 } else if (modifier_index == meta_bit && *old_mod != meta_bit) {
164 modwarn(key_name, meta_bit, "Meta");
165 } else if (modifier_index == super_bit && *old_mod != super_bit) {
166 modwarn(key_name, super_bit, "Super");
167 } else if (modifier_index == hyper_bit && *old_mod != hyper_bit) {
168 modwarn(key_name, hyper_bit, "Hyper");
169 } else if (modifier_index == alt_bit && *old_mod != alt_bit) {
170 modwarn(key_name, alt_bit, "Alt");
171 } else {
172 *(old_mod) = modifier_index;
176 code = x_modifier_keymap->modifiermap[modifier_index * mkpm + modifier_key];
177 sym = (code ? XkbKeycodeToKeysym(display, code, 0, column) : NoSymbol);
179 if (sym == last_sym)
180 continue;
181 last_sym = sym;
183 switch (sym) {
184 case XK_Mode_switch:
185 store_modifier("Mode_switch", &mode_bit);
186 break;
187 case XK_Meta_L:
188 store_modifier("Meta_L", &meta_bit);
189 break;
190 case XK_Meta_R:
191 store_modifier("Meta_R", &meta_bit);
192 break;
193 case XK_Super_L:
194 store_modifier("Super_L", &super_bit);
195 break;
196 case XK_Super_R:
197 store_modifier("Super_R", &super_bit);
198 break;
199 case XK_Hyper_L:
200 store_modifier("Hyper_L", &hyper_bit);
201 break;
202 case XK_Hyper_R:
203 store_modifier("Hyper_R", &hyper_bit);
204 break;
205 case XK_Alt_L:
206 store_modifier("Alt_L", &alt_bit);
207 break;
208 case XK_Alt_R:
209 store_modifier("Alt_R", &alt_bit);
210 break;
211 case XK_Control_L:
212 check_modifier("Control_L", ControlMask);
213 break;
214 case XK_Control_R:
215 check_modifier("Control_R", ControlMask);
216 break;
217 case XK_Shift_L:
218 check_modifier("Shift_L", ShiftMask);
219 break;
220 case XK_Shift_R:
221 check_modifier("Shift_R", ShiftMask);
222 break;
223 case XK_Shift_Lock:
224 check_modifier("Shift_Lock", LockMask);
225 break;
226 case XK_Caps_Lock:
227 check_modifier("Caps_Lock", LockMask);
228 break;
230 /* It probably doesn't make any sense for a modifier bit to be
231 assigned to a key that is not one of the above, but OpenWindows
232 assigns modifier bits to a couple of random function keys for
233 no reason that I can discern, so printing a warning here would
234 be annoying. */
239 /* If there was no Meta key, then try using the Alt key instead.
240 If there is both a Meta key and an Alt key, then the Alt key
241 is not disturbed and remains an Alt key. */
242 if (!meta_bit && alt_bit)
243 meta_bit = alt_bit, alt_bit = 0;
245 /* mode_bit overrides everything, since it's processed down inside of
246 XLookupString() instead of by us. If Meta and Mode_switch both
247 generate the same modifier bit (which is an error), then we don't
248 interpret that bit as Meta, because we can't make XLookupString()
249 not interpret it as Mode_switch; and interpreting it as both would
250 be totally wrong. */
251 if (mode_bit) {
252 const char *warn = NULL;
254 if (mode_bit == meta_bit)
255 warn = "Meta", meta_bit = 0;
256 else if (mode_bit == hyper_bit)
257 warn = "Hyper", hyper_bit = 0;
258 else if (mode_bit == super_bit)
259 warn = "Super", super_bit = 0;
260 else if (mode_bit == alt_bit)
261 warn = "Alt", alt_bit = 0;
262 if (warn) {
263 wwarning("%s is being used for both Mode_switch and %s.",
264 index_to_name(mode_bit), warn);
268 MetaMask = (meta_bit ? (1 << meta_bit) : 0);
269 HyperMask = (hyper_bit ? (1 << hyper_bit) : 0);
270 SuperMask = (super_bit ? (1 << super_bit) : 0);
271 AltMask = (alt_bit ? (1 << alt_bit) : 0);
272 ModeMask = (mode_bit ? (1 << mode_bit) : 0); /* unused */
274 XFreeModifiermap(x_modifier_keymap);
277 const char *wXModifierToShortcutLabel(int mask)
279 if (mask < 0)
280 return NULL;
282 if (mask == ShiftMask)
283 return "Sh+";
284 if (mask == ControlMask)
285 return "^";
286 if (mask == AltMask)
287 return "A+";
288 if (mask == Mod1Mask)
289 return "M1+";
290 if (mask == Mod2Mask)
291 return "M2+";
292 if (mask == Mod3Mask)
293 return "M3+";
294 if (mask == Mod4Mask)
295 return "M4+";
296 if (mask == Mod5Mask)
297 return "M5+";
298 if (mask == MetaMask)
299 return "M+";
301 wwarning("Can't convert keymask %d to shortcut label", mask);
302 return NULL;
305 int wXModifierFromKey(const char *key)
307 if (strcasecmp(key, "SHIFT") == 0 && ShiftMask != 0)
308 return ShiftMask;
309 else if (strcasecmp(key, "CONTROL") == 0 && ControlMask != 0)
310 return ControlMask;
311 else if (strcasecmp(key, "ALT") == 0 && AltMask != 0)
312 return AltMask;
313 else if (strcasecmp(key, "META") == 0 && MetaMask != 0)
314 return MetaMask;
315 else if (strcasecmp(key, "SUPER") == 0 && SuperMask != 0)
316 return SuperMask;
317 else if (strcasecmp(key, "HYPER") == 0 && HyperMask != 0)
318 return HyperMask;
319 else if (strcasecmp(key, "MOD1") == 0 && Mod1Mask != 0)
320 return Mod1Mask;
321 else if (strcasecmp(key, "MOD2") == 0 && Mod2Mask != 0)
322 return Mod2Mask;
323 else if (strcasecmp(key, "MOD3") == 0 && Mod3Mask != 0)
324 return Mod3Mask;
325 else if (strcasecmp(key, "MOD4") == 0 && Mod4Mask != 0)
326 return Mod4Mask;
327 else if (strcasecmp(key, "MOD5") == 0 && Mod5Mask != 0)
328 return Mod5Mask;
329 else
330 return -1;
333 /* Wrapper so that we may fit the WM naming conventions, yet leave the
334 original XEmacs function name in place. */
335 void wXModifierInitialize(void)
337 x_reset_modifier_mapping(dpy);