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. */
9 * More changes for WPrefs by Alfredo Kojima, Aug 1998
12 /* The event_stream interface for X11 with Xt, and/or tty frames.
13 Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
14 Copyright (C) 1995 Sun Microsystems, Inc.
15 Copyright (C) 1996 Ben Wing.
17 This file is part of XEmacs.
19 XEmacs is free software; you can redistribute it and/or modify it
20 under the terms of the GNU General Public License as published by the
21 Free Software Foundation; either version 2, or (at your option) any
24 XEmacs is distributed in the hope that it will be useful, but WITHOUT
25 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
26 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
29 You should have received a copy of the GNU General Public License
30 along with XEmacs; see the file COPYING. If not, write to
31 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
32 Boston, MA 02111-1307, USA. */
36 #include <X11/keysym.h>
38 #include <WINGs/WUtil.h>
40 /************************************************************************/
42 /************************************************************************/
44 /* X bogusly doesn't define the interpretations of any bits besides
45 ModControl, ModShift, and ModLock; so the Interclient Communication
46 Conventions Manual says that we have to bend over backwards to figure
47 out what the other modifier bits mean. According to ICCCM:
49 - Any keycode which is assigned ModControl is a "control" key.
51 - Any modifier bit which is assigned to a keycode which generates Meta_L
52 or Meta_R is the modifier bit meaning "meta". Likewise for Super, Hyper,
55 - Any keypress event which contains ModControl in its state should be
56 interpreted as a "control" character.
58 - Any keypress event which contains a modifier bit in its state which is
59 generated by a keycode whose corresponding keysym is Meta_L or Meta_R
60 should be interpreted as a "meta" character. Likewise for Super, Hyper,
63 - It is illegal for a keysym to be associated with more than one modifier
66 This means that the only thing that emacs can reasonably interpret as a
67 "meta" key is a key whose keysym is Meta_L or Meta_R, and which generates
68 one of the modifier bits Mod1-Mod5.
70 Unfortunately, many keyboards don't have Meta keys in their default
71 configuration. So, if there are no Meta keys, but there are "Alt" keys,
72 emacs will interpret Alt as Meta. If there are both Meta and Alt keys,
73 then the Meta keys mean "Meta", and the Alt keys mean "Alt" (it used to
74 mean "Symbol," but that just confused the hell out of way too many people).
76 This works with the default configurations of the 19 keyboard-types I've
79 Emacs detects keyboard configurations which violate the above rules, and
80 prints an error message on the standard-error-output. (Perhaps it should
81 use a pop-up-window instead.)
84 static int MetaIndex
, HyperIndex
, SuperIndex
, AltIndex
, ModeIndex
;
86 static const char *index_to_name(int indice
)
110 static void x_reset_modifier_mapping(Display
* display
)
112 int modifier_index
, modifier_key
, column
, mkpm
;
113 int warned_about_overlapping_modifiers
= 0;
114 int warned_about_predefined_modifiers
= 0;
115 int warned_about_duplicate_modifiers
= 0;
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.\n\n", \
125 name, code, index_to_name (old), other), \
126 warned_about_overlapping_modifiers = 1
128 #define modbarf(name,other) \
129 wwarning ("%s (0x%x) generates %s, which is nonsensical.\n\n", \
130 name, code, other), \
131 warned_about_predefined_modifiers = 1
133 #define check_modifier(name,mask) \
134 if ((1<<modifier_index) != mask) \
135 wwarning ("%s (0x%x) generates %s, which is nonsensical.\n\n", \
136 name, code, index_to_name (modifier_index)), \
137 warned_about_predefined_modifiers = 1
139 #define store_modifier(name,old) \
140 if (old && old != modifier_index) \
141 wwarning ("%s (0x%x) generates both %s and %s, which is nonsensical.\n\n",\
142 name, code, index_to_name (old), \
143 index_to_name (modifier_index)), \
144 warned_about_duplicate_modifiers = 1; \
145 if (modifier_index == ShiftMapIndex) modbarf (name,"ModShift"); \
146 else if (modifier_index == LockMapIndex) modbarf (name,"ModLock"); \
147 else if (modifier_index == ControlMapIndex) modbarf (name,"ModControl"); \
148 else if (sym == XK_Mode_switch) \
149 mode_bit = modifier_index; /* Mode_switch is special, see below... */ \
150 else if (modifier_index == meta_bit && old != meta_bit) \
151 modwarn (name, meta_bit, "Meta"); \
152 else if (modifier_index == super_bit && old != super_bit) \
153 modwarn (name, super_bit, "Super"); \
154 else if (modifier_index == hyper_bit && old != hyper_bit) \
155 modwarn (name, hyper_bit, "Hyper"); \
156 else if (modifier_index == alt_bit && old != alt_bit) \
157 modwarn (name, alt_bit, "Alt"); \
159 old = modifier_index;
161 mkpm
= x_modifier_keymap
->max_keypermod
;
162 for (modifier_index
= 0; modifier_index
< 8; modifier_index
++)
163 for (modifier_key
= 0; modifier_key
< mkpm
; modifier_key
++) {
165 for (column
= 0; column
< 4; column
+= 2) {
166 KeyCode code
= x_modifier_keymap
->modifiermap
[modifier_index
* mkpm
168 KeySym sym
= (code
? XKeycodeToKeysym(display
, code
, column
) : 0);
174 store_modifier("Mode_switch", mode_bit
);
177 store_modifier("Meta_L", meta_bit
);
180 store_modifier("Meta_R", meta_bit
);
183 store_modifier("Super_L", super_bit
);
186 store_modifier("Super_R", super_bit
);
189 store_modifier("Hyper_L", hyper_bit
);
192 store_modifier("Hyper_R", hyper_bit
);
195 store_modifier("Alt_L", alt_bit
);
198 store_modifier("Alt_R", alt_bit
);
201 check_modifier("Control_L", ControlMask
);
204 check_modifier("Control_R", ControlMask
);
207 check_modifier("Shift_L", ShiftMask
);
210 check_modifier("Shift_R", ShiftMask
);
213 check_modifier("Shift_Lock", LockMask
);
216 check_modifier("Caps_Lock", LockMask
);
219 /* It probably doesn't make any sense for a modifier bit to be
220 assigned to a key that is not one of the above, but OpenWindows
221 assigns modifier bits to a couple of random function keys for
222 no reason that I can discern, so printing a warning here would
227 #undef store_modifier
228 #undef check_modifier
232 /* If there was no Meta key, then try using the Alt key instead.
233 If there is both a Meta key and an Alt key, then the Alt key
234 is not disturbed and remains an Alt key. */
235 if (!meta_bit
&& alt_bit
)
236 meta_bit
= alt_bit
, alt_bit
= 0;
238 /* mode_bit overrides everything, since it's processed down inside of
239 XLookupString() instead of by us. If Meta and Mode_switch both
240 generate the same modifier bit (which is an error), then we don't
241 interpret that bit as Meta, because we can't make XLookupString()
242 not interpret it as Mode_switch; and interpreting it as both would
245 const char *warn
= 0;
246 if (mode_bit
== meta_bit
)
247 warn
= "Meta", meta_bit
= 0;
248 else if (mode_bit
== hyper_bit
)
249 warn
= "Hyper", hyper_bit
= 0;
250 else if (mode_bit
== super_bit
)
251 warn
= "Super", super_bit
= 0;
252 else if (mode_bit
== alt_bit
)
253 warn
= "Alt", alt_bit
= 0;
256 ("%s is being used for both Mode_switch and %s.\n\n",
257 index_to_name(mode_bit
), warn
), warned_about_overlapping_modifiers
= 1;
261 MetaIndex
= meta_bit
;
262 HyperIndex
= hyper_bit
;
263 SuperIndex
= super_bit
;
265 ModeIndex
= mode_bit
;
267 if (x_modifier_keymap
!= NULL
)
268 XFreeModifiermap(x_modifier_keymap
);
271 int ModifierFromKey(Display
* dpy
, char *key
)
276 x_reset_modifier_mapping(dpy
);
279 if (strcasecmp(key
, "SHIFT") == 0)
280 return ShiftMapIndex
;
281 else if (strcasecmp(key
, "CONTROL") == 0)
282 return ControlMapIndex
;
283 else if (strcasecmp(key
, "ALT") == 0)
285 else if (strcasecmp(key
, "META") == 0)
287 else if (strcasecmp(key
, "SUPER") == 0)
289 else if (strcasecmp(key
, "HYPER") == 0)
291 else if (strcasecmp(key
, "MOD1") == 0)
293 else if (strcasecmp(key
, "MOD2") == 0)
295 else if (strcasecmp(key
, "MOD3") == 0)
297 else if (strcasecmp(key
, "MOD4") == 0)
299 else if (strcasecmp(key
, "MOD5") == 0)