Update Serbian translation from master branch
[wmaker-crm.git] / src / xmodifier.c
blobe2c0fa2acdd45bce4c310b7e32e3509612006be9
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
18 later version.
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
23 for more details.
25 You should have received a copy of the GNU General Public License along
26 with XEmacs; see the file COPYING. if not, write to the
27 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
28 Boston, MA 02110-1301 USA. */
30 #include "wconfig.h"
32 #include <string.h>
33 #include <strings.h>
34 #include <X11/Xlib.h>
35 #include <X11/keysym.h>
36 #include <X11/XKBlib.h>
38 #include <WINGs/WUtil.h>
39 #include <WINGs/WINGsP.h>
40 #include "WindowMaker.h"
41 #include "xmodifier.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 MetaMask, HyperMask, SuperMask, AltMask, ModeMask;
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 = XGetModifierMapping(display);
124 mkpm = x_modifier_keymap->max_keypermod;
125 for (modifier_index = 0; modifier_index < 8; modifier_index++)
126 for (modifier_key = 0; modifier_key < mkpm; modifier_key++) {
127 KeySym last_sym = 0;
129 for (column = 0; column < 4; column += 2) {
130 KeyCode code;
131 KeySym sym;
133 inline void modwarn(const char *key_name, int old_mod, const char *other_key)
135 wwarning(_("key %s (0x%x) generates %s, which is generated by %s"),
136 key_name, code, index_to_name(old_mod), other_key);
139 inline void modbarf(const char *key_name, const char *other_mod)
141 wwarning(_("key %s (0x%x) generates %s, which is nonsensical"),
142 key_name, code, other_mod);
145 inline void check_modifier(const char *key_name, int mask)
147 if ((1 << modifier_index) != mask)
148 modbarf(key_name, index_to_name(modifier_index));
151 inline void store_modifier(const char *key_name, int *old_mod)
153 if (*old_mod && *old_mod != modifier_index)
154 wwarning(_("key %s (0x%x) generates both %s and %s, which is nonsensical"),
155 key_name, code, index_to_name(*old_mod), index_to_name(modifier_index));
156 if (modifier_index == ShiftMapIndex) {
157 modbarf(key_name, "ModShift");
158 } else if (modifier_index == LockMapIndex) {
159 modbarf(key_name, "ModLock");
160 } else if (modifier_index == ControlMapIndex) {
161 modbarf(key_name, "ModControl");
162 } else if (sym == XK_Mode_switch) {
163 mode_bit = modifier_index; /* Mode_switch is special, see below... */
164 } else if (modifier_index == meta_bit && *old_mod != meta_bit) {
165 modwarn(key_name, meta_bit, "Meta");
166 } else if (modifier_index == super_bit && *old_mod != super_bit) {
167 modwarn(key_name, super_bit, "Super");
168 } else if (modifier_index == hyper_bit && *old_mod != hyper_bit) {
169 modwarn(key_name, hyper_bit, "Hyper");
170 } else if (modifier_index == alt_bit && *old_mod != alt_bit) {
171 modwarn(key_name, alt_bit, "Alt");
172 } else {
173 *(old_mod) = modifier_index;
177 code = x_modifier_keymap->modifiermap[modifier_index * mkpm + modifier_key];
178 sym = W_KeycodeToKeysym(display, code, column);
180 if (sym == last_sym)
181 continue;
182 last_sym = sym;
184 switch (sym) {
185 case XK_Mode_switch:
186 store_modifier("Mode_switch", &mode_bit);
187 break;
188 case XK_Meta_L:
189 store_modifier("Meta_L", &meta_bit);
190 break;
191 case XK_Meta_R:
192 store_modifier("Meta_R", &meta_bit);
193 break;
194 case XK_Super_L:
195 store_modifier("Super_L", &super_bit);
196 break;
197 case XK_Super_R:
198 store_modifier("Super_R", &super_bit);
199 break;
200 case XK_Hyper_L:
201 store_modifier("Hyper_L", &hyper_bit);
202 break;
203 case XK_Hyper_R:
204 store_modifier("Hyper_R", &hyper_bit);
205 break;
206 case XK_Alt_L:
207 store_modifier("Alt_L", &alt_bit);
208 break;
209 case XK_Alt_R:
210 store_modifier("Alt_R", &alt_bit);
211 break;
212 case XK_Control_L:
213 check_modifier("Control_L", ControlMask);
214 break;
215 case XK_Control_R:
216 check_modifier("Control_R", ControlMask);
217 break;
218 case XK_Shift_L:
219 check_modifier("Shift_L", ShiftMask);
220 break;
221 case XK_Shift_R:
222 check_modifier("Shift_R", ShiftMask);
223 break;
224 case XK_Shift_Lock:
225 check_modifier("Shift_Lock", LockMask);
226 break;
227 case XK_Caps_Lock:
228 check_modifier("Caps_Lock", LockMask);
229 break;
231 /* It probably doesn't make any sense for a modifier bit to be
232 assigned to a key that is not one of the above, but OpenWindows
233 assigns modifier bits to a couple of random function keys for
234 no reason that I can discern, so printing a warning here would
235 be annoying. */
240 /* If there was no Meta key, then try using the Alt key instead.
241 If there is both a Meta key and an Alt key, then the Alt key
242 is not disturbed and remains an Alt key. */
243 if (!meta_bit && alt_bit)
244 meta_bit = alt_bit, alt_bit = 0;
246 /* mode_bit overrides everything, since it's processed down inside of
247 XLookupString() instead of by us. If Meta and Mode_switch both
248 generate the same modifier bit (which is an error), then we don't
249 interpret that bit as Meta, because we can't make XLookupString()
250 not interpret it as Mode_switch; and interpreting it as both would
251 be totally wrong. */
252 if (mode_bit) {
253 const char *warn = NULL;
255 if (mode_bit == meta_bit)
256 warn = "Meta", meta_bit = 0;
257 else if (mode_bit == hyper_bit)
258 warn = "Hyper", hyper_bit = 0;
259 else if (mode_bit == super_bit)
260 warn = "Super", super_bit = 0;
261 else if (mode_bit == alt_bit)
262 warn = "Alt", alt_bit = 0;
263 if (warn) {
264 wwarning("%s is being used for both Mode_switch and %s.",
265 index_to_name(mode_bit), warn);
269 MetaMask = (meta_bit ? (1 << meta_bit) : 0);
270 HyperMask = (hyper_bit ? (1 << hyper_bit) : 0);
271 SuperMask = (super_bit ? (1 << super_bit) : 0);
272 AltMask = (alt_bit ? (1 << alt_bit) : 0);
273 ModeMask = (mode_bit ? (1 << mode_bit) : 0); /* unused */
275 XFreeModifiermap(x_modifier_keymap);
278 const char *wXModifierToShortcutLabel(int mask)
280 if (mask < 0)
281 return NULL;
283 if (mask == ShiftMask)
284 return "Sh+";
285 if (mask == ControlMask)
286 return "^";
287 if (mask == AltMask)
288 return "A+";
289 if (mask == Mod1Mask)
290 return "M1+";
291 if (mask == Mod2Mask)
292 return "M2+";
293 if (mask == Mod3Mask)
294 return "M3+";
295 if (mask == Mod4Mask)
296 return "M4+";
297 if (mask == Mod5Mask)
298 return "M5+";
299 if (mask == MetaMask)
300 return "M+";
302 wwarning(_("Can't convert keymask 0x%04X to a shortcut label"), mask);
303 return NULL;
306 int wXModifierFromKey(const char *key)
308 if (strcasecmp(key, "SHIFT") == 0 && ShiftMask != 0)
309 return ShiftMask;
310 else if (strcasecmp(key, "CONTROL") == 0 && ControlMask != 0)
311 return ControlMask;
312 else if (strcasecmp(key, "ALT") == 0 && AltMask != 0)
313 return AltMask;
314 else if (strcasecmp(key, "META") == 0 && MetaMask != 0)
315 return MetaMask;
316 else if (strcasecmp(key, "SUPER") == 0 && SuperMask != 0)
317 return SuperMask;
318 else if (strcasecmp(key, "HYPER") == 0 && HyperMask != 0)
319 return HyperMask;
320 else if (strcasecmp(key, "MOD1") == 0 && Mod1Mask != 0)
321 return Mod1Mask;
322 else if (strcasecmp(key, "MOD2") == 0 && Mod2Mask != 0)
323 return Mod2Mask;
324 else if (strcasecmp(key, "MOD3") == 0 && Mod3Mask != 0)
325 return Mod3Mask;
326 else if (strcasecmp(key, "MOD4") == 0 && Mod4Mask != 0)
327 return Mod4Mask;
328 else if (strcasecmp(key, "MOD5") == 0 && Mod5Mask != 0)
329 return Mod5Mask;
330 else
331 return -1;
334 /* Wrapper so that we may fit the WM naming conventions, yet leave the
335 original XEmacs function name in place. */
336 void wXModifierInitialize(void)
338 x_reset_modifier_mapping(dpy);