Change to the linux kernel coding style
[wmaker-crm.git] / WPrefs.app / xmodifier.c
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
30  along with XEmacs; see the file COPYING.  If not, write to
31  the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
32  Boston, MA 02111-1307, USA.  */
33
34 #include <string.h>
35 #include <X11/Xlib.h>
36 #include <X11/keysym.h>
37
38 #include <WINGs/WUtil.h>
39
40 /************************************************************************/
41 /*                            keymap handling                           */
42 /************************************************************************/
43
44 /* X bogusly doesn't define the interpretations of any bits besides
45  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:
48
49  - Any keycode which is assigned ModControl is a "control" key.
50
51  - 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.
54
55  - Any keypress event which contains ModControl in its state should be
56  interpreted as a "control" character.
57
58  - 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.
62
63  - It is illegal for a keysym to be associated with more than one modifier
64  bit.
65
66  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.
69
70  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).
75
76  This works with the default configurations of the 19 keyboard-types I've
77  checked.
78
79  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.)
82  */
83
84 static int MetaIndex, HyperIndex, SuperIndex, AltIndex, ModeIndex;
85
86 static const char *index_to_name(int indice)
87 {
88         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         }
108 }
109
110 static void x_reset_modifier_mapping(Display * display)
111 {
112         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);
122
123 #define modwarn(name,old,other)                                             \
124     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
127
128 #define modbarf(name,other)                                                 \
129     wwarning ("%s (0x%x) generates %s, which is nonsensical.\n\n",            \
130     name, code, other),                                     \
131     warned_about_predefined_modifiers = 1
132
133 #define check_modifier(name,mask)                                           \
134     if ((1<<modifier_index) != mask)                                        \
135     wwarning ("%s (0x%x) generates %s, which is nonsensical.\n\n",          \
136     name, code, index_to_name (modifier_index)),            \
137     warned_about_predefined_modifiers = 1
138
139 #define store_modifier(name,old)                                           \
140     if (old && old != modifier_index)                                      \
141     wwarning ("%s (0x%x) generates both %s and %s, which is nonsensical.\n\n",\
142     name, code, index_to_name (old),                       \
143     index_to_name (modifier_index)),                       \
144     warned_about_duplicate_modifiers = 1;                                  \
145     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)                                        \
149     mode_bit = modifier_index; /* Mode_switch is special, see below... */  \
150     else if (modifier_index == meta_bit && old != meta_bit)                \
151     modwarn (name, meta_bit, "Meta");                                      \
152     else if (modifier_index == super_bit && old != super_bit)              \
153     modwarn (name, super_bit, "Super");                                    \
154     else if (modifier_index == hyper_bit && old != hyper_bit)              \
155     modwarn (name, hyper_bit, "Hyper");                                    \
156     else if (modifier_index == alt_bit && old != alt_bit)                          \
157     modwarn (name, alt_bit, "Alt");                                        \
158     else                                                                           \
159     old = modifier_index;
160
161         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                 }
227 #undef store_modifier
228 #undef check_modifier
229 #undef modwarn
230 #undef modbarf
231
232         /* 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         MetaIndex = meta_bit;
262         HyperIndex = hyper_bit;
263         SuperIndex = super_bit;
264         AltIndex = alt_bit;
265         ModeIndex = mode_bit;
266
267         if (x_modifier_keymap != NULL)
268                 XFreeModifiermap(x_modifier_keymap);
269 }
270
271 int ModifierFromKey(Display * dpy, char *key)
272 {
273         static int eqw = 0;
274
275         if (!eqw)
276                 x_reset_modifier_mapping(dpy);
277         eqw = 1;
278
279         if (strcasecmp(key, "SHIFT") == 0)
280                 return ShiftMapIndex;
281         else if (strcasecmp(key, "CONTROL") == 0)
282                 return ControlMapIndex;
283         else if (strcasecmp(key, "ALT") == 0)
284                 return AltIndex;
285         else if (strcasecmp(key, "META") == 0)
286                 return MetaIndex;
287         else if (strcasecmp(key, "SUPER") == 0)
288                 return SuperIndex;
289         else if (strcasecmp(key, "HYPER") == 0)
290                 return HyperIndex;
291         else if (strcasecmp(key, "MOD1") == 0)
292                 return Mod1MapIndex;
293         else if (strcasecmp(key, "MOD2") == 0)
294                 return Mod2MapIndex;
295         else if (strcasecmp(key, "MOD3") == 0)
296                 return Mod3MapIndex;
297         else if (strcasecmp(key, "MOD4") == 0)
298                 return Mod4MapIndex;
299         else if (strcasecmp(key, "MOD5") == 0)
300                 return Mod5MapIndex;
301         else
302                 return -1;
303 }