Change to the linux kernel coding style
[wmaker-crm.git] / src / xmodifier.c
Commit [+]AuthorDateLineData
9d2e6ef9 scottc1998-09-29 22:36:29 +00001/* Grok X modifier mappings for shortcuts.
9d2e6ef9 scottc1998-09-29 22:36:29 +00002
6830b057 dan2004-10-12 21:28:27 +00003Most of this code was taken from src/event-Xt.c in XEmacs 20.3-b17.
4The copyright(s) from the original XEmacs code are included below.
5
6Perpetrator: Sudish Joseph <sj@eng.mindspring.net>, Sept. 1997. */
9d2e6ef9 scottc1998-09-29 22:36:29 +00007
8/* The event_stream interface for X11 with Xt, and/or tty frames.
6830b057 dan2004-10-12 21:28:27 +00009 Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
10 Copyright (C) 1995 Sun Microsystems, Inc.
11 Copyright (C) 1996 Ben Wing.
9d2e6ef9 scottc1998-09-29 22:36:29 +000012
6830b057 dan2004-10-12 21:28:27 +000013 This file is part of XEmacs.
9d2e6ef9 scottc1998-09-29 22:36:29 +000014
6830b057 dan2004-10-12 21:28:27 +000015 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
18 later version.
9d2e6ef9 scottc1998-09-29 22:36:29 +000019
6830b057 dan2004-10-12 21:28:27 +000020 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
23 for more details.
9d2e6ef9 scottc1998-09-29 22:36:29 +000024
6830b057 dan2004-10-12 21:28:27 +000025 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. */
9d2e6ef9 scottc1998-09-29 22:36:29 +000029
30#include "wconfig.h"
31
32#include <string.h>
33#include <X11/Xlib.h>
34#include <X11/keysym.h>
35
a20aebde dan2001-01-18 19:21:56 +000036#include <WINGs/WUtil.h>
9d2e6ef9 scottc1998-09-29 22:36:29 +000037
9d2e6ef9 scottc1998-09-29 22:36:29 +000038extern Display *dpy;
39
40/************************************************************************/
41/* keymap handling */
42/************************************************************************/
43
44/* X bogusly doesn't define the interpretations of any bits besides
6830b057 dan2004-10-12 21:28:27 +000045 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:
9d2e6ef9 scottc1998-09-29 22:36:29 +000048
6830b057 dan2004-10-12 21:28:27 +000049 - Any keycode which is assigned ModControl is a "control" key.
9d2e6ef9 scottc1998-09-29 22:36:29 +000050
6830b057 dan2004-10-12 21:28:27 +000051 - 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,
53 etc.
9d2e6ef9 scottc1998-09-29 22:36:29 +000054
6830b057 dan2004-10-12 21:28:27 +000055 - Any keypress event which contains ModControl in its state should be
56 interpreted as a "control" character.
9d2e6ef9 scottc1998-09-29 22:36:29 +000057
6830b057 dan2004-10-12 21:28:27 +000058 - 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,
61 etc.
9d2e6ef9 scottc1998-09-29 22:36:29 +000062
6830b057 dan2004-10-12 21:28:27 +000063 - It is illegal for a keysym to be associated with more than one modifier
64 bit.
9d2e6ef9 scottc1998-09-29 22:36:29 +000065
6830b057 dan2004-10-12 21:28:27 +000066 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.
9d2e6ef9 scottc1998-09-29 22:36:29 +000069
6830b057 dan2004-10-12 21:28:27 +000070 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).
9d2e6ef9 scottc1998-09-29 22:36:29 +000075
6830b057 dan2004-10-12 21:28:27 +000076 This works with the default configurations of the 19 keyboard-types I've
77 checked.
9d2e6ef9 scottc1998-09-29 22:36:29 +000078
6830b057 dan2004-10-12 21:28:27 +000079 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.)
9d2e6ef9 scottc1998-09-29 22:36:29 +000082 */
83
84static int MetaMask, HyperMask, SuperMask, AltMask, ModeMask;
85
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020086static const char *index_to_name(int indice)
9d2e6ef9 scottc1998-09-29 22:36:29 +000087{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020088 switch (indice) {
89 case ShiftMapIndex:
90 return "ModShift";
91 case LockMapIndex:
92 return "ModLock";
93 case ControlMapIndex:
94 return "ModControl";
95 case Mod1MapIndex:
96 return "Mod1";
97 case Mod2MapIndex:
98 return "Mod2";
99 case Mod3MapIndex:
100 return "Mod3";
101 case Mod4MapIndex:
102 return "Mod4";
103 case Mod5MapIndex:
104 return "Mod5";
105 default:
106 return "???";
107 }
9d2e6ef9 scottc1998-09-29 22:36:29 +0000108}
109
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200110static void x_reset_modifier_mapping(Display * display)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000111{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200112 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;
116 int meta_bit = 0;
117 int hyper_bit = 0;
118 int super_bit = 0;
119 int alt_bit = 0;
120 int mode_bit = 0;
121 XModifierKeymap *x_modifier_keymap = XGetModifierMapping(display);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000122
123#define modwarn(name,old,other) \
6830b057 dan2004-10-12 21:28:27 +0000124 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
9d2e6ef9 scottc1998-09-29 22:36:29 +0000127
128#define modbarf(name,other) \
6830b057 dan2004-10-12 21:28:27 +0000129 wwarning ("%s (0x%x) generates %s, which is nonsensical.\n\n", \
130 name, code, other), \
131 warned_about_predefined_modifiers = 1
9d2e6ef9 scottc1998-09-29 22:36:29 +0000132
133#define check_modifier(name,mask) \
6830b057 dan2004-10-12 21:28:27 +0000134 if ((1<<modifier_index) != mask) \
9d2e6ef9 scottc1998-09-29 22:36:29 +0000135 wwarning ("%s (0x%x) generates %s, which is nonsensical.\n\n", \
6830b057 dan2004-10-12 21:28:27 +0000136 name, code, index_to_name (modifier_index)), \
9d2e6ef9 scottc1998-09-29 22:36:29 +0000137 warned_about_predefined_modifiers = 1
138
139#define store_modifier(name,old) \
6830b057 dan2004-10-12 21:28:27 +0000140 if (old && old != modifier_index) \
9d2e6ef9 scottc1998-09-29 22:36:29 +0000141 wwarning ("%s (0x%x) generates both %s and %s, which is nonsensical.\n\n",\
6830b057 dan2004-10-12 21:28:27 +0000142 name, code, index_to_name (old), \
143 index_to_name (modifier_index)), \
9d2e6ef9 scottc1998-09-29 22:36:29 +0000144 warned_about_duplicate_modifiers = 1; \
6830b057 dan2004-10-12 21:28:27 +0000145 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) \
9d2e6ef9 scottc1998-09-29 22:36:29 +0000149 mode_bit = modifier_index; /* Mode_switch is special, see below... */ \
6830b057 dan2004-10-12 21:28:27 +0000150 else if (modifier_index == meta_bit && old != meta_bit) \
9d2e6ef9 scottc1998-09-29 22:36:29 +0000151 modwarn (name, meta_bit, "Meta"); \
6830b057 dan2004-10-12 21:28:27 +0000152 else if (modifier_index == super_bit && old != super_bit) \
9d2e6ef9 scottc1998-09-29 22:36:29 +0000153 modwarn (name, super_bit, "Super"); \
6830b057 dan2004-10-12 21:28:27 +0000154 else if (modifier_index == hyper_bit && old != hyper_bit) \
9d2e6ef9 scottc1998-09-29 22:36:29 +0000155 modwarn (name, hyper_bit, "Hyper"); \
6830b057 dan2004-10-12 21:28:27 +0000156 else if (modifier_index == alt_bit && old != alt_bit) \
9d2e6ef9 scottc1998-09-29 22:36:29 +0000157 modwarn (name, alt_bit, "Alt"); \
6830b057 dan2004-10-12 21:28:27 +0000158 else \
9d2e6ef9 scottc1998-09-29 22:36:29 +0000159 old = modifier_index;
160
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200161 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++) {
164 KeySym last_sym = 0;
165 for (column = 0; column < 4; column += 2) {
166 KeyCode code = x_modifier_keymap->modifiermap[modifier_index * mkpm
167 + modifier_key];
168 KeySym sym = (code ? XKeycodeToKeysym(display, code, column) : 0);
169 if (sym == last_sym)
170 continue;
171 last_sym = sym;
172 switch (sym) {
173 case XK_Mode_switch:
174 store_modifier("Mode_switch", mode_bit);
175 break;
176 case XK_Meta_L:
177 store_modifier("Meta_L", meta_bit);
178 break;
179 case XK_Meta_R:
180 store_modifier("Meta_R", meta_bit);
181 break;
182 case XK_Super_L:
183 store_modifier("Super_L", super_bit);
184 break;
185 case XK_Super_R:
186 store_modifier("Super_R", super_bit);
187 break;
188 case XK_Hyper_L:
189 store_modifier("Hyper_L", hyper_bit);
190 break;
191 case XK_Hyper_R:
192 store_modifier("Hyper_R", hyper_bit);
193 break;
194 case XK_Alt_L:
195 store_modifier("Alt_L", alt_bit);
196 break;
197 case XK_Alt_R:
198 store_modifier("Alt_R", alt_bit);
199 break;
200 case XK_Control_L:
201 check_modifier("Control_L", ControlMask);
202 break;
203 case XK_Control_R:
204 check_modifier("Control_R", ControlMask);
205 break;
206 case XK_Shift_L:
207 check_modifier("Shift_L", ShiftMask);
208 break;
209 case XK_Shift_R:
210 check_modifier("Shift_R", ShiftMask);
211 break;
212 case XK_Shift_Lock:
213 check_modifier("Shift_Lock", LockMask);
214 break;
215 case XK_Caps_Lock:
216 check_modifier("Caps_Lock", LockMask);
217 break;
218
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
223 be annoying. */
224 }
225 }
226 }
9d2e6ef9 scottc1998-09-29 22:36:29 +0000227#undef store_modifier
228#undef check_modifier
229#undef modwarn
230#undef modbarf
231
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200232 /* 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;
237
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
243 be totally wrong. */
244 if (mode_bit) {
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;
254 if (warn) {
255 wwarning
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;
258 }
259 }
260
261 MetaMask = (meta_bit ? (1 << meta_bit) : 0);
262 HyperMask = (hyper_bit ? (1 << hyper_bit) : 0);
263 SuperMask = (super_bit ? (1 << super_bit) : 0);
264 AltMask = (alt_bit ? (1 << alt_bit) : 0);
265 ModeMask = (mode_bit ? (1 << mode_bit) : 0); /* unused */
9d2e6ef9 scottc1998-09-29 22:36:29 +0000266
267#if 0
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200268 if (warned_about_overlapping_modifiers)
269 wwarning("\n"
270 " Two distinct modifier keys (such as Meta and Hyper) cannot generate\n"
271 " the same modifier bit, because Emacs won't be able to tell which\n"
272 " modifier was actually held down when some other key is pressed. It\n"
273 " won't be able to tell Meta-x and Hyper-x apart, for example. Change\n"
274 " one of these keys to use some other modifier bit. If you intend for\n"
275 " these keys to have the same behavior, then change them to have the\n"
276 " same keysym as well as the same modifier bit.\n");
277
278 if (warned_about_predefined_modifiers)
279 wwarning("\n"
280 " The semantics of the modifier bits ModShift, ModLock, and ModControl\n"
281 " are predefined. It does not make sense to assign ModControl to any\n"
282 " keysym other than Control_L or Control_R, or to assign any modifier\n"
283 " bits to the \"control\" keysyms other than ModControl. You can't\n"
284 " turn a \"control\" key into a \"meta\" key (or vice versa) by simply\n"
285 " assigning the key a different modifier bit. You must also make that\n"
286 " key generate an appropriate keysym (Control_L, Meta_L, etc).\n");
287
288 /* No need to say anything more for warned_about_duplicate_modifiers. */
289
290 if (warned_about_overlapping_modifiers || warned_about_predefined_modifiers)
291 wwarning("\n"
292 " The meanings of the modifier bits Mod1 through Mod5 are determined\n"
293 " by the keysyms used to control those bits. Mod1 does NOT always\n"
294 " mean Meta, although some non-ICCCM-compliant programs assume that.\n");
9d2e6ef9 scottc1998-09-29 22:36:29 +0000295#endif
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200296 XFreeModifiermap(x_modifier_keymap);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000297}
298
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200299int wXModifierFromKey(char *key)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000300{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200301 if (strcasecmp(key, "SHIFT") == 0 && ShiftMask != 0)
302 return ShiftMask;
303 else if (strcasecmp(key, "CONTROL") == 0 && ControlMask != 0)
304 return ControlMask;
305 else if (strcasecmp(key, "ALT") == 0 && AltMask != 0)
306 return AltMask;
307 else if (strcasecmp(key, "META") == 0 && MetaMask != 0)
308 return MetaMask;
309 else if (strcasecmp(key, "SUPER") == 0 && SuperMask != 0)
310 return SuperMask;
311 else if (strcasecmp(key, "HYPER") == 0 && HyperMask != 0)
312 return HyperMask;
313 else if (strcasecmp(key, "MOD1") == 0 && Mod1Mask != 0)
314 return Mod1Mask;
315 else if (strcasecmp(key, "MOD2") == 0 && Mod2Mask != 0)
316 return Mod2Mask;
317 else if (strcasecmp(key, "MOD3") == 0 && Mod3Mask != 0)
318 return Mod3Mask;
319 else if (strcasecmp(key, "MOD4") == 0 && Mod4Mask != 0)
320 return Mod4Mask;
321 else if (strcasecmp(key, "MOD5") == 0 && Mod5Mask != 0)
322 return Mod5Mask;
323 else
324 return -1;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000325}
326
6830b057 dan2004-10-12 21:28:27 +0000327/* Wrapper so that we may fit the WM naming conventions, yet leave the
328 original XEmacs function name in place. */
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200329void wXModifierInitialize(void)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000330{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200331 x_reset_modifier_mapping(dpy);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000332}