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
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
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. */
35 #include <X11/keysym.h>
36 #include <X11/XKBlib.h>
38 #include <WINGs/WUtil.h>
39 #include "xmodifier.h"
43 /************************************************************************/
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,
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,
66 - It is illegal for a keysym to be associated with more than one modifier
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
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
)
113 static void x_reset_modifier_mapping(Display
* display
)
115 int modifier_index
, modifier_key
, column
, mkpm
;
121 XModifierKeymap
*x_modifier_keymap
= XGetModifierMapping(display
);
123 #define modwarn(name,old,other) \
124 wwarning ("%s (0x%x) generates %s, which is generated by %s.", \
125 name, code, index_to_name (old), other)
127 #define modbarf(name,other) \
128 wwarning ("%s (0x%x) generates %s, which is nonsensical.", \
131 #define check_modifier(name,mask) \
132 if ((1<<modifier_index) != mask) \
133 wwarning ("%s (0x%x) generates %s, which is nonsensical.", \
134 name, code, index_to_name (modifier_index))
136 #define store_modifier(name,old) \
137 if (old && old != modifier_index) \
138 wwarning ("%s (0x%x) generates both %s and %s, which is nonsensical.", \
139 name, code, index_to_name (old), \
140 index_to_name (modifier_index)); \
141 if (modifier_index == ShiftMapIndex) modbarf (name,"ModShift"); \
142 else if (modifier_index == LockMapIndex) modbarf (name,"ModLock"); \
143 else if (modifier_index == ControlMapIndex) modbarf (name,"ModControl"); \
144 else if (sym == XK_Mode_switch) \
145 mode_bit = modifier_index; /* Mode_switch is special, see below... */ \
146 else if (modifier_index == meta_bit && old != meta_bit) \
147 modwarn (name, meta_bit, "Meta"); \
148 else if (modifier_index == super_bit && old != super_bit) \
149 modwarn (name, super_bit, "Super"); \
150 else if (modifier_index == hyper_bit && old != hyper_bit) \
151 modwarn (name, hyper_bit, "Hyper"); \
152 else if (modifier_index == alt_bit && old != alt_bit) \
153 modwarn (name, alt_bit, "Alt"); \
155 old = modifier_index;
157 mkpm
= x_modifier_keymap
->max_keypermod
;
158 for (modifier_index
= 0; modifier_index
< 8; modifier_index
++)
159 for (modifier_key
= 0; modifier_key
< mkpm
; modifier_key
++) {
161 for (column
= 0; column
< 4; column
+= 2) {
162 KeyCode code
= x_modifier_keymap
->modifiermap
[modifier_index
* mkpm
164 KeySym sym
= (code
? XkbKeycodeToKeysym(display
, code
, 0, column
) : 0);
170 store_modifier("Mode_switch", mode_bit
);
173 store_modifier("Meta_L", meta_bit
);
176 store_modifier("Meta_R", meta_bit
);
179 store_modifier("Super_L", super_bit
);
182 store_modifier("Super_R", super_bit
);
185 store_modifier("Hyper_L", hyper_bit
);
188 store_modifier("Hyper_R", hyper_bit
);
191 store_modifier("Alt_L", alt_bit
);
194 store_modifier("Alt_R", alt_bit
);
197 check_modifier("Control_L", ControlMask
);
200 check_modifier("Control_R", ControlMask
);
203 check_modifier("Shift_L", ShiftMask
);
206 check_modifier("Shift_R", ShiftMask
);
209 check_modifier("Shift_Lock", LockMask
);
212 check_modifier("Caps_Lock", LockMask
);
215 /* It probably doesn't make any sense for a modifier bit to be
216 assigned to a key that is not one of the above, but OpenWindows
217 assigns modifier bits to a couple of random function keys for
218 no reason that I can discern, so printing a warning here would
223 #undef store_modifier
224 #undef check_modifier
228 /* If there was no Meta key, then try using the Alt key instead.
229 If there is both a Meta key and an Alt key, then the Alt key
230 is not disturbed and remains an Alt key. */
231 if (!meta_bit
&& alt_bit
)
232 meta_bit
= alt_bit
, alt_bit
= 0;
234 /* mode_bit overrides everything, since it's processed down inside of
235 XLookupString() instead of by us. If Meta and Mode_switch both
236 generate the same modifier bit (which is an error), then we don't
237 interpret that bit as Meta, because we can't make XLookupString()
238 not interpret it as Mode_switch; and interpreting it as both would
241 const char *warn
= 0;
242 if (mode_bit
== meta_bit
)
243 warn
= "Meta", meta_bit
= 0;
244 else if (mode_bit
== hyper_bit
)
245 warn
= "Hyper", hyper_bit
= 0;
246 else if (mode_bit
== super_bit
)
247 warn
= "Super", super_bit
= 0;
248 else if (mode_bit
== alt_bit
)
249 warn
= "Alt", alt_bit
= 0;
251 wwarning("%s is being used for both Mode_switch and %s.",
252 index_to_name(mode_bit
), warn
);
256 MetaMask
= (meta_bit
? (1 << meta_bit
) : 0);
257 HyperMask
= (hyper_bit
? (1 << hyper_bit
) : 0);
258 SuperMask
= (super_bit
? (1 << super_bit
) : 0);
259 AltMask
= (alt_bit
? (1 << alt_bit
) : 0);
260 ModeMask
= (mode_bit
? (1 << mode_bit
) : 0); /* unused */
262 XFreeModifiermap(x_modifier_keymap
);
265 int wXModifierFromKey(char *key
)
267 if (strcasecmp(key
, "SHIFT") == 0 && ShiftMask
!= 0)
269 else if (strcasecmp(key
, "CONTROL") == 0 && ControlMask
!= 0)
271 else if (strcasecmp(key
, "ALT") == 0 && AltMask
!= 0)
273 else if (strcasecmp(key
, "META") == 0 && MetaMask
!= 0)
275 else if (strcasecmp(key
, "SUPER") == 0 && SuperMask
!= 0)
277 else if (strcasecmp(key
, "HYPER") == 0 && HyperMask
!= 0)
279 else if (strcasecmp(key
, "MOD1") == 0 && Mod1Mask
!= 0)
281 else if (strcasecmp(key
, "MOD2") == 0 && Mod2Mask
!= 0)
283 else if (strcasecmp(key
, "MOD3") == 0 && Mod3Mask
!= 0)
285 else if (strcasecmp(key
, "MOD4") == 0 && Mod4Mask
!= 0)
287 else if (strcasecmp(key
, "MOD5") == 0 && Mod5Mask
!= 0)
293 /* Wrapper so that we may fit the WM naming conventions, yet leave the
294 original XEmacs function name in place. */
295 void wXModifierInitialize(void)
297 x_reset_modifier_mapping(dpy
);