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
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. */
34 #include <X11/keysym.h>
36 #include <WINGs/WUtil.h>
41 /************************************************************************/
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,
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,
64 - It is illegal for a keysym to be associated with more than one modifier
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
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
;
88 index_to_name (int indice
)
92 case ShiftMapIndex
: return "ModShift";
93 case LockMapIndex
: return "ModLock";
94 case ControlMapIndex
: return "ModControl";
95 case Mod1MapIndex
: return "Mod1";
96 case Mod2MapIndex
: return "Mod2";
97 case Mod3MapIndex
: return "Mod3";
98 case Mod4MapIndex
: return "Mod4";
99 case Mod5MapIndex
: return "Mod5";
100 default: return "???";
105 x_reset_modifier_mapping (Display
*display
)
107 int modifier_index
, modifier_key
, column
, mkpm
;
108 int warned_about_overlapping_modifiers
= 0;
109 int warned_about_predefined_modifiers
= 0;
110 int warned_about_duplicate_modifiers
= 0;
116 XModifierKeymap
*x_modifier_keymap
= XGetModifierMapping (display
);
118 #define modwarn(name,old,other) \
119 wwarning ("%s (0x%x) generates %s, which is generated by %s.\n\n", \
120 name, code, index_to_name (old), other), \
121 warned_about_overlapping_modifiers = 1
123 #define modbarf(name,other) \
124 wwarning ("%s (0x%x) generates %s, which is nonsensical.\n\n", \
125 name, code, other), \
126 warned_about_predefined_modifiers = 1
128 #define check_modifier(name,mask) \
129 if ((1<<modifier_index) != mask) \
130 wwarning ("%s (0x%x) generates %s, which is nonsensical.\n\n", \
131 name, code, index_to_name (modifier_index)), \
132 warned_about_predefined_modifiers = 1
134 #define store_modifier(name,old) \
135 if (old && old != modifier_index) \
136 wwarning ("%s (0x%x) generates both %s and %s, which is nonsensical.\n\n",\
137 name, code, index_to_name (old), \
138 index_to_name (modifier_index)), \
139 warned_about_duplicate_modifiers = 1; \
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"); \
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
++) {
160 for (column
= 0; column
< 4; column
+= 2) {
161 KeyCode code
= x_modifier_keymap
->modifiermap
[modifier_index
* mkpm
163 KeySym sym
= (code
? XKeycodeToKeysym (display
, code
, column
) : 0);
164 if (sym
== last_sym
) continue;
167 case XK_Mode_switch
:store_modifier ("Mode_switch", mode_bit
); break;
168 case XK_Meta_L
: store_modifier ("Meta_L", meta_bit
); break;
169 case XK_Meta_R
: store_modifier ("Meta_R", meta_bit
); break;
170 case XK_Super_L
: store_modifier ("Super_L", super_bit
); break;
171 case XK_Super_R
: store_modifier ("Super_R", super_bit
); break;
172 case XK_Hyper_L
: store_modifier ("Hyper_L", hyper_bit
); break;
173 case XK_Hyper_R
: store_modifier ("Hyper_R", hyper_bit
); break;
174 case XK_Alt_L
: store_modifier ("Alt_L", alt_bit
); break;
175 case XK_Alt_R
: store_modifier ("Alt_R", alt_bit
); break;
176 case XK_Control_L
: check_modifier ("Control_L", ControlMask
); break;
177 case XK_Control_R
: check_modifier ("Control_R", ControlMask
); break;
178 case XK_Shift_L
: check_modifier ("Shift_L", ShiftMask
); break;
179 case XK_Shift_R
: check_modifier ("Shift_R", ShiftMask
); break;
180 case XK_Shift_Lock
: check_modifier ("Shift_Lock", LockMask
); break;
181 case XK_Caps_Lock
: check_modifier ("Caps_Lock", LockMask
); break;
183 /* It probably doesn't make any sense for a modifier bit to be
184 assigned to a key that is not one of the above, but OpenWindows
185 assigns modifier bits to a couple of random function keys for
186 no reason that I can discern, so printing a warning here would
191 #undef store_modifier
192 #undef check_modifier
196 /* If there was no Meta key, then try using the Alt key instead.
197 If there is both a Meta key and an Alt key, then the Alt key
198 is not disturbed and remains an Alt key. */
199 if (! meta_bit
&& alt_bit
)
200 meta_bit
= alt_bit
, alt_bit
= 0;
202 /* mode_bit overrides everything, since it's processed down inside of
203 XLookupString() instead of by us. If Meta and Mode_switch both
204 generate the same modifier bit (which is an error), then we don't
205 interpret that bit as Meta, because we can't make XLookupString()
206 not interpret it as Mode_switch; and interpreting it as both would
210 const char *warn
= 0;
211 if (mode_bit
== meta_bit
) warn
= "Meta", meta_bit
= 0;
212 else if (mode_bit
== hyper_bit
) warn
= "Hyper", hyper_bit
= 0;
213 else if (mode_bit
== super_bit
) warn
= "Super", super_bit
= 0;
214 else if (mode_bit
== alt_bit
) warn
= "Alt", alt_bit
= 0;
218 ("%s is being used for both Mode_switch and %s.\n\n",
219 index_to_name (mode_bit
), warn
),
220 warned_about_overlapping_modifiers
= 1;
224 MetaMask
= (meta_bit
? (1 << meta_bit
) : 0);
225 HyperMask
= (hyper_bit
? (1 << hyper_bit
) : 0);
226 SuperMask
= (super_bit
? (1 << super_bit
) : 0);
227 AltMask
= (alt_bit
? (1 << alt_bit
) : 0);
228 ModeMask
= (mode_bit
? (1 << mode_bit
) : 0); /* unused */
231 if (warned_about_overlapping_modifiers
)
233 " Two distinct modifier keys (such as Meta and Hyper) cannot generate\n"
234 " the same modifier bit, because Emacs won't be able to tell which\n"
235 " modifier was actually held down when some other key is pressed. It\n"
236 " won't be able to tell Meta-x and Hyper-x apart, for example. Change\n"
237 " one of these keys to use some other modifier bit. If you intend for\n"
238 " these keys to have the same behavior, then change them to have the\n"
239 " same keysym as well as the same modifier bit.\n");
241 if (warned_about_predefined_modifiers
)
243 " The semantics of the modifier bits ModShift, ModLock, and ModControl\n"
244 " are predefined. It does not make sense to assign ModControl to any\n"
245 " keysym other than Control_L or Control_R, or to assign any modifier\n"
246 " bits to the \"control\" keysyms other than ModControl. You can't\n"
247 " turn a \"control\" key into a \"meta\" key (or vice versa) by simply\n"
248 " assigning the key a different modifier bit. You must also make that\n"
249 " key generate an appropriate keysym (Control_L, Meta_L, etc).\n");
251 /* No need to say anything more for warned_about_duplicate_modifiers. */
253 if (warned_about_overlapping_modifiers
|| warned_about_predefined_modifiers
)
255 " The meanings of the modifier bits Mod1 through Mod5 are determined\n"
256 " by the keysyms used to control those bits. Mod1 does NOT always\n"
257 " mean Meta, although some non-ICCCM-compliant programs assume that.\n");
259 XFreeModifiermap(x_modifier_keymap
);
264 wXModifierFromKey(char *key
)
266 if (strcasecmp(key
, "SHIFT")==0 && ShiftMask
!=0)
268 else if (strcasecmp(key
, "CONTROL")==0 && ControlMask
!=0)
270 else if (strcasecmp(key
, "ALT")==0 && AltMask
!=0)
272 else if (strcasecmp(key
, "META")==0 && MetaMask
!=0)
274 else if (strcasecmp(key
, "SUPER")==0 && SuperMask
!=0)
276 else if (strcasecmp(key
, "HYPER")==0 && HyperMask
!=0)
278 else if (strcasecmp(key
, "MOD1")==0 && Mod1Mask
!=0)
280 else if (strcasecmp(key
, "MOD2")==0 && Mod2Mask
!=0)
282 else if (strcasecmp(key
, "MOD3")==0 && Mod3Mask
!=0)
284 else if (strcasecmp(key
, "MOD4")==0 && Mod4Mask
!=0)
286 else if (strcasecmp(key
, "MOD5")==0 && Mod5Mask
!=0)
292 /* Wrapper so that we may fit the WM naming conventions, yet leave the
293 original XEmacs function name in place. */
295 wXModifierInitialize(void)
297 x_reset_modifier_mapping(dpy
);