wrlib: return NULL if XImage could not be taken, for consistency
[wmaker-crm.git] / WPrefs.app / xmodifier.c
blob1845ada4c281ddb2cab58362993b117f5f6fcb34
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 /*
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
22 later version.
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.
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. */
34 #include <string.h>
35 #include <strings.h>
36 #include <X11/Xlib.h>
37 #include <X11/keysym.h>
38 #include <X11/XKBlib.h>
40 #include <WINGs/WUtil.h>
42 #include "WPrefs.h"
44 /************************************************************************/
45 /* keymap handling */
46 /************************************************************************/
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:
53 - Any keycode which is assigned ModControl is a "control" key.
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.
59 - Any keypress event which contains ModControl in its state should be
60 interpreted as a "control" character.
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.
67 - It is illegal for a keysym to be associated with more than one modifier
68 bit.
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.
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).
80 This works with the default configurations of the 19 keyboard-types I've
81 checked.
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.)
88 static int MetaIndex, HyperIndex, SuperIndex, AltIndex, ModeIndex;
90 static const char *index_to_name(int indice)
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 "???";
114 static void x_reset_modifier_mapping(Display * display)
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;
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)
128 #define modbarf(name,other) \
129 wwarning ("%s (0x%x) generates %s, which is nonsensical.", \
130 name, code, other)
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))
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;
158 x_modifier_keymap = XGetModifierMapping(display);
159 if (x_modifier_keymap == NULL) {
160 wwarning("XGetModifierMapping returned NULL, there is no modifiers or no memory.\n");
161 return;
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;
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;
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;
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. */
240 #undef store_modifier
241 #undef check_modifier
242 #undef modwarn
243 #undef modbarf
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;
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 Mode_switch and %s.",
269 index_to_name(mode_bit), warn);
273 MetaIndex = meta_bit;
274 HyperIndex = hyper_bit;
275 SuperIndex = super_bit;
276 AltIndex = alt_bit;
277 ModeIndex = mode_bit;
279 XFreeModifiermap(x_modifier_keymap);
282 int ModifierFromKey(Display * dpy, const char *key)
284 static int eqw = 0;
286 if (!eqw)
287 x_reset_modifier_mapping(dpy);
288 eqw = 1;
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;