1 /* Grok X modifier mappings for shortcuts.
2 
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.
5 
6 Perpetrator: Sudish Joseph <sj@eng.mindspring.net>, Sept. 1997. */
7 
8 /*
9  * More changes for WPrefs by Alfredo Kojima, Aug 1998
10  */
11 
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.
16 
17  This file is part of XEmacs.
18 
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
22  later version.
23 
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
27  for more details.
28 
29  You should have received a copy of the GNU General Public License along
30  with XEmacs; see the file COPYING. if not, write to the
31  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
32  Boston, MA 02110-1301 USA. */
33 
34 #include <string.h>
35 #include <strings.h>
36 #include <X11/Xlib.h>
37 #include <X11/keysym.h>
38 #include <X11/XKBlib.h>
39 
40 #include <WINGs/WUtil.h>
41 
42 #include "WPrefs.h"
43 
44 /************************************************************************/
45 /*                            keymap handling                           */
46 /************************************************************************/
47 
48 /* X bogusly doesn't define the interpretations of any bits besides
49  ModControl, ModShift, and ModLock; so the Interclient Communication
50  Conventions Manual says that we have to bend over backwards to figure
51  out what the other modifier bits mean.  According to ICCCM:
52 
53  - Any keycode which is assigned ModControl is a "control" key.
54 
55  - Any modifier bit which is assigned to a keycode which generates Meta_L
56  or Meta_R is the modifier bit meaning "meta".  Likewise for Super, Hyper,
57  etc.
58 
59  - Any keypress event which contains ModControl in its state should be
60  interpreted as a "control" character.
61 
62  - Any keypress event which contains a modifier bit in its state which is
63  generated by a keycode whose corresponding keysym is Meta_L or Meta_R
64  should be interpreted as a "meta" character.  Likewise for Super, Hyper,
65  etc.
66 
67  - It is illegal for a keysym to be associated with more than one modifier
68  bit.
69 
70  This means that the only thing that emacs can reasonably interpret as a
71  "meta" key is a key whose keysym is Meta_L or Meta_R, and which generates
72  one of the modifier bits Mod1-Mod5.
73 
74  Unfortunately, many keyboards don't have Meta keys in their default
75  configuration.  So, if there are no Meta keys, but there are "Alt" keys,
76  emacs will interpret Alt as Meta.  If there are both Meta and Alt keys,
77  then the Meta keys mean "Meta", and the Alt keys mean "Alt" (it used to
78  mean "Symbol," but that just confused the hell out of way too many people).
79 
80  This works with the default configurations of the 19 keyboard-types I've
81  checked.
82 
83  Emacs detects keyboard configurations which violate the above rules, and
84  prints an error message on the standard-error-output.  (Perhaps it should
85  use a pop-up-window instead.)
86  */
87 
88 static int MetaIndex, HyperIndex, SuperIndex, AltIndex, ModeIndex;
89 
index_to_name(int indice)90 static const char *index_to_name(int indice)
91 {
92 	switch (indice) {
93 	case ShiftMapIndex:
94 		return "ModShift";
95 	case LockMapIndex:
96 		return "ModLock";
97 	case ControlMapIndex:
98 		return "ModControl";
99 	case Mod1MapIndex:
100 		return "Mod1";
101 	case Mod2MapIndex:
102 		return "Mod2";
103 	case Mod3MapIndex:
104 		return "Mod3";
105 	case Mod4MapIndex:
106 		return "Mod4";
107 	case Mod5MapIndex:
108 		return "Mod5";
109 	default:
110 		return "???";
111 	}
112 }
113 
x_reset_modifier_mapping(Display * display)114 static void x_reset_modifier_mapping(Display * display)
115 {
116 	int modifier_index, modifier_key, column, mkpm;
117 	int meta_bit = 0;
118 	int hyper_bit = 0;
119 	int super_bit = 0;
120 	int alt_bit = 0;
121 	int mode_bit = 0;
122 	XModifierKeymap *x_modifier_keymap;
123 
124 #define modwarn(name,old,other)							\
125     wwarning(_("%s (0x%x) generates %s which is generated by %s"),		\
126     name, code, index_to_name (old), other)
127 
128 #define modbarf(name,other)							\
129     wwarning(_("%s (0x%x) generates %s which is nonsensical"),			\
130     name, code, other)
131 
132 #define check_modifier(name,mask)						\
133     if ((1<<modifier_index) != mask)						\
134     wwarning(_("%s (0x%x) generates %s which is nonsensical"),			\
135     name, code, index_to_name (modifier_index))
136 
137 #define store_modifier(name,old)						\
138     if (old && old != modifier_index)						\
139     wwarning(_("%s (0x%x) generates both %s and %s which is nonsensical"),	\
140     name, code, index_to_name (old),						\
141     index_to_name (modifier_index));						\
142     if (modifier_index == ShiftMapIndex) modbarf (name,"ModShift");		\
143     else if (modifier_index == LockMapIndex) modbarf (name,"ModLock");		\
144     else if (modifier_index == ControlMapIndex) modbarf (name,"ModControl");	\
145     else if (sym == XK_Mode_switch)						\
146     mode_bit = modifier_index; /* Mode_switch is special, see below... */	\
147     else if (modifier_index == meta_bit && old != meta_bit)			\
148     modwarn (name, meta_bit, "Meta");						\
149     else if (modifier_index == super_bit && old != super_bit)			\
150     modwarn (name, super_bit, "Super");						\
151     else if (modifier_index == hyper_bit && old != hyper_bit)			\
152     modwarn (name, hyper_bit, "Hyper");						\
153     else if (modifier_index == alt_bit && old != alt_bit)			\
154     modwarn (name, alt_bit, "Alt");						\
155     else									\
156     old = modifier_index;
157 
158 	x_modifier_keymap = XGetModifierMapping(display);
159 	if (x_modifier_keymap == NULL) {
160 		wwarning(_("XGetModifierMapping returned NULL, there is no modifier or no memory"));
161 		return;
162 	}
163 
164 	mkpm = x_modifier_keymap->max_keypermod;
165 	for (modifier_index = 0; modifier_index < 8; modifier_index++)
166 		for (modifier_key = 0; modifier_key < mkpm; modifier_key++) {
167 			KeySym last_sym = 0;
168 			for (column = 0; column < 4; column += 2) {
169 				KeyCode code = x_modifier_keymap->modifiermap[modifier_index * mkpm
170 									      + modifier_key];
171 				KeySym sym;
172 
173 				if (code) {
174 					if (xext_xkb_supported)
175 						sym = XkbKeycodeToKeysym(display, code, 0, column);
176 					else
177 						sym = XKeycodeToKeysym(display, code, column);
178 				} else {
179 					sym = NoSymbol;
180 				}
181 
182 				if (sym == last_sym)
183 					continue;
184 				last_sym = sym;
185 				switch (sym) {
186 				case XK_Mode_switch:
187 					store_modifier("Mode_switch", mode_bit);
188 					break;
189 				case XK_Meta_L:
190 					store_modifier("Meta_L", meta_bit);
191 					break;
192 				case XK_Meta_R:
193 					store_modifier("Meta_R", meta_bit);
194 					break;
195 				case XK_Super_L:
196 					store_modifier("Super_L", super_bit);
197 					break;
198 				case XK_Super_R:
199 					store_modifier("Super_R", super_bit);
200 					break;
201 				case XK_Hyper_L:
202 					store_modifier("Hyper_L", hyper_bit);
203 					break;
204 				case XK_Hyper_R:
205 					store_modifier("Hyper_R", hyper_bit);
206 					break;
207 				case XK_Alt_L:
208 					store_modifier("Alt_L", alt_bit);
209 					break;
210 				case XK_Alt_R:
211 					store_modifier("Alt_R", alt_bit);
212 					break;
213 				case XK_Control_L:
214 					check_modifier("Control_L", ControlMask);
215 					break;
216 				case XK_Control_R:
217 					check_modifier("Control_R", ControlMask);
218 					break;
219 				case XK_Shift_L:
220 					check_modifier("Shift_L", ShiftMask);
221 					break;
222 				case XK_Shift_R:
223 					check_modifier("Shift_R", ShiftMask);
224 					break;
225 				case XK_Shift_Lock:
226 					check_modifier("Shift_Lock", LockMask);
227 					break;
228 				case XK_Caps_Lock:
229 					check_modifier("Caps_Lock", LockMask);
230 					break;
231 
232 					/* It probably doesn't make any sense for a modifier bit to be
233 					   assigned to a key that is not one of the above, but OpenWindows
234 					   assigns modifier bits to a couple of random function keys for
235 					   no reason that I can discern, so printing a warning here would
236 					   be annoying. */
237 				}
238 			}
239 		}
240 #undef store_modifier
241 #undef check_modifier
242 #undef modwarn
243 #undef modbarf
244 
245 	/* If there was no Meta key, then try using the Alt key instead.
246 	   If there is both a Meta key and an Alt key, then the Alt key
247 	   is not disturbed and remains an Alt key. */
248 	if (!meta_bit && alt_bit)
249 		meta_bit = alt_bit, alt_bit = 0;
250 
251 	/* mode_bit overrides everything, since it's processed down inside of
252 	   XLookupString() instead of by us.  If Meta and Mode_switch both
253 	   generate the same modifier bit (which is an error), then we don't
254 	   interpret that bit as Meta, because we can't make XLookupString()
255 	   not interpret it as Mode_switch; and interpreting it as both would
256 	   be totally wrong. */
257 	if (mode_bit) {
258 		const char *warn = 0;
259 		if (mode_bit == meta_bit)
260 			warn = "Meta", meta_bit = 0;
261 		else if (mode_bit == hyper_bit)
262 			warn = "Hyper", hyper_bit = 0;
263 		else if (mode_bit == super_bit)
264 			warn = "Super", super_bit = 0;
265 		else if (mode_bit == alt_bit)
266 			warn = "Alt", alt_bit = 0;
267 		if (warn) {
268 			wwarning(_("%s is being used for both %s and %s"),
269 			         index_to_name(mode_bit), "Mode_switch", warn);
270 		}
271 	}
272 
273 	MetaIndex = meta_bit;
274 	HyperIndex = hyper_bit;
275 	SuperIndex = super_bit;
276 	AltIndex = alt_bit;
277 	ModeIndex = mode_bit;
278 
279 	XFreeModifiermap(x_modifier_keymap);
280 }
281 
ModifierFromKey(Display * dpy,const char * key)282 int ModifierFromKey(Display * dpy, const char *key)
283 {
284 	static int eqw = 0;
285 
286 	if (!eqw)
287 		x_reset_modifier_mapping(dpy);
288 	eqw = 1;
289 
290 	if (strcasecmp(key, "SHIFT") == 0)
291 		return ShiftMapIndex;
292 	else if (strcasecmp(key, "CONTROL") == 0)
293 		return ControlMapIndex;
294 	else if (strcasecmp(key, "ALT") == 0)
295 		return AltIndex;
296 	else if (strcasecmp(key, "META") == 0)
297 		return MetaIndex;
298 	else if (strcasecmp(key, "SUPER") == 0)
299 		return SuperIndex;
300 	else if (strcasecmp(key, "HYPER") == 0)
301 		return HyperIndex;
302 	else if (strcasecmp(key, "MOD1") == 0)
303 		return Mod1MapIndex;
304 	else if (strcasecmp(key, "MOD2") == 0)
305 		return Mod2MapIndex;
306 	else if (strcasecmp(key, "MOD3") == 0)
307 		return Mod3MapIndex;
308 	else if (strcasecmp(key, "MOD4") == 0)
309 		return Mod4MapIndex;
310 	else if (strcasecmp(key, "MOD5") == 0)
311 		return Mod5MapIndex;
312 	else
313 		return -1;
314 }
315