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);