~profzoom/ubuntu/quantal/wmaker/bug-1079925

« back to all changes in this revision

Viewing changes to src/xmodifier.c

  • Committer: Bazaar Package Importer
  • Author(s): Marcelo E. Magallon
  • Date: 2004-11-10 14:05:30 UTC
  • Revision ID: james.westby@ubuntu.com-20041110140530-qpd66b5lm38x7apk
Tags: upstream-0.91.0
ImportĀ upstreamĀ versionĀ 0.91.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
/* 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.
 
12
 
 
13
 This file is part of XEmacs.
 
14
 
 
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.
 
19
 
 
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.
 
24
 
 
25
 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.  */
 
29
 
 
30
#include "wconfig.h"
 
31
 
 
32
#include <string.h>
 
33
#include <X11/Xlib.h>
 
34
#include <X11/keysym.h>
 
35
 
 
36
#include <WINGs/WUtil.h>
 
37
 
 
38
 
 
39
extern Display *dpy;
 
40
 
 
41
/************************************************************************/
 
42
/*                            keymap handling                           */
 
43
/************************************************************************/
 
44
 
 
45
/* X bogusly doesn't define the interpretations of any bits besides
 
46
 ModControl, ModShift, and ModLock; so the Interclient Communication
 
47
 Conventions Manual says that we have to bend over backwards to figure
 
48
 out what the other modifier bits mean.  According to ICCCM:
 
49
 
 
50
 - Any keycode which is assigned ModControl is a "control" key.
 
51
 
 
52
 - Any modifier bit which is assigned to a keycode which generates Meta_L
 
53
 or Meta_R is the modifier bit meaning "meta".  Likewise for Super, Hyper,
 
54
 etc.
 
55
 
 
56
 - Any keypress event which contains ModControl in its state should be
 
57
 interpreted as a "control" character.
 
58
 
 
59
 - Any keypress event which contains a modifier bit in its state which is
 
60
 generated by a keycode whose corresponding keysym is Meta_L or Meta_R
 
61
 should be interpreted as a "meta" character.  Likewise for Super, Hyper,
 
62
 etc.
 
63
 
 
64
 - It is illegal for a keysym to be associated with more than one modifier
 
65
 bit.
 
66
 
 
67
 This means that the only thing that emacs can reasonably interpret as a
 
68
 "meta" key is a key whose keysym is Meta_L or Meta_R, and which generates
 
69
 one of the modifier bits Mod1-Mod5.
 
70
 
 
71
 Unfortunately, many keyboards don't have Meta keys in their default
 
72
 configuration.  So, if there are no Meta keys, but there are "Alt" keys,
 
73
 emacs will interpret Alt as Meta.  If there are both Meta and Alt keys,
 
74
 then the Meta keys mean "Meta", and the Alt keys mean "Alt" (it used to
 
75
 mean "Symbol," but that just confused the hell out of way too many people).
 
76
 
 
77
 This works with the default configurations of the 19 keyboard-types I've
 
78
 checked.
 
79
 
 
80
 Emacs detects keyboard configurations which violate the above rules, and
 
81
 prints an error message on the standard-error-output.  (Perhaps it should
 
82
 use a pop-up-window instead.)
 
83
 */
 
84
 
 
85
static int MetaMask, HyperMask, SuperMask, AltMask, ModeMask;
 
86
 
 
87
static const char *
 
88
index_to_name (int indice)
 
89
{
 
90
    switch (indice)
 
91
    {
 
92
    case ShiftMapIndex:   return "ModShift";
 
93
    case LockMapIndex:    return "ModLock";
 
94
    case ControlMapIndex: return "ModControl";
 
95
    case Mod1MapIndex:    return "Mod1";
 
96
    case Mod2MapIndex:    return "Mod2";
 
97
    case Mod3MapIndex:    return "Mod3";
 
98
    case Mod4MapIndex:    return "Mod4";
 
99
    case Mod5MapIndex:    return "Mod5";
 
100
    default:              return "???";
 
101
    }
 
102
}
 
103
 
 
104
static void
 
105
x_reset_modifier_mapping (Display *display)
 
106
{
 
107
    int modifier_index, modifier_key, column, mkpm;
 
108
    int warned_about_overlapping_modifiers = 0;
 
109
    int warned_about_predefined_modifiers  = 0;
 
110
    int warned_about_duplicate_modifiers   = 0;
 
111
    int meta_bit  = 0;
 
112
    int hyper_bit = 0;
 
113
    int super_bit = 0;
 
114
    int alt_bit   = 0;
 
115
    int mode_bit  = 0;
 
116
    XModifierKeymap *x_modifier_keymap = XGetModifierMapping (display);
 
117
 
 
118
#define modwarn(name,old,other)                                             \
 
119
    wwarning ("%s (0x%x) generates %s, which is generated by %s.\n\n",        \
 
120
    name, code, index_to_name (old), other),                \
 
121
    warned_about_overlapping_modifiers = 1
 
122
 
 
123
#define modbarf(name,other)                                                 \
 
124
    wwarning ("%s (0x%x) generates %s, which is nonsensical.\n\n",            \
 
125
    name, code, other),                                     \
 
126
    warned_about_predefined_modifiers = 1
 
127
 
 
128
#define check_modifier(name,mask)                                           \
 
129
    if ((1<<modifier_index) != mask)                                        \
 
130
    wwarning ("%s (0x%x) generates %s, which is nonsensical.\n\n",          \
 
131
    name, code, index_to_name (modifier_index)),            \
 
132
    warned_about_predefined_modifiers = 1
 
133
 
 
134
#define store_modifier(name,old)                                           \
 
135
    if (old && old != modifier_index)                                      \
 
136
    wwarning ("%s (0x%x) generates both %s and %s, which is nonsensical.\n\n",\
 
137
    name, code, index_to_name (old),                       \
 
138
    index_to_name (modifier_index)),                       \
 
139
    warned_about_duplicate_modifiers = 1;                                  \
 
140
    if (modifier_index == ShiftMapIndex) modbarf (name,"ModShift");        \
 
141
    else if (modifier_index == LockMapIndex) modbarf (name,"ModLock");     \
 
142
    else if (modifier_index == ControlMapIndex) modbarf (name,"ModControl"); \
 
143
    else if (sym == XK_Mode_switch)                                        \
 
144
    mode_bit = modifier_index; /* Mode_switch is special, see below... */  \
 
145
    else if (modifier_index == meta_bit && old != meta_bit)                \
 
146
    modwarn (name, meta_bit, "Meta");                                      \
 
147
    else if (modifier_index == super_bit && old != super_bit)              \
 
148
    modwarn (name, super_bit, "Super");                                    \
 
149
    else if (modifier_index == hyper_bit && old != hyper_bit)              \
 
150
    modwarn (name, hyper_bit, "Hyper");                                    \
 
151
    else if (modifier_index == alt_bit && old != alt_bit)                          \
 
152
    modwarn (name, alt_bit, "Alt");                                        \
 
153
    else                                                                           \
 
154
    old = modifier_index;
 
155
 
 
156
    mkpm = x_modifier_keymap->max_keypermod;
 
157
    for (modifier_index = 0; modifier_index < 8; modifier_index++)
 
158
        for (modifier_key = 0; modifier_key < mkpm; modifier_key++) {
 
159
            KeySym last_sym = 0;
 
160
            for (column = 0; column < 4; column += 2) {
 
161
                KeyCode code = x_modifier_keymap->modifiermap[modifier_index * mkpm
 
162
                                                              + modifier_key];
 
163
                KeySym sym = (code ? XKeycodeToKeysym (display, code, column) : 0);
 
164
                if (sym == last_sym) continue;
 
165
                last_sym = sym;
 
166
                switch (sym) {
 
167
                case XK_Mode_switch:store_modifier ("Mode_switch", mode_bit); break;
 
168
                case XK_Meta_L:     store_modifier ("Meta_L", meta_bit); break;
 
169
                case XK_Meta_R:     store_modifier ("Meta_R", meta_bit); break;
 
170
                case XK_Super_L:    store_modifier ("Super_L", super_bit); break;
 
171
                case XK_Super_R:    store_modifier ("Super_R", super_bit); break;
 
172
                case XK_Hyper_L:    store_modifier ("Hyper_L", hyper_bit); break;
 
173
                case XK_Hyper_R:    store_modifier ("Hyper_R", hyper_bit); break;
 
174
                case XK_Alt_L:      store_modifier ("Alt_L", alt_bit); break;
 
175
                case XK_Alt_R:      store_modifier ("Alt_R", alt_bit); break;
 
176
                case XK_Control_L:  check_modifier ("Control_L", ControlMask); break;
 
177
                case XK_Control_R:  check_modifier ("Control_R", ControlMask); break;
 
178
                case XK_Shift_L:    check_modifier ("Shift_L", ShiftMask); break;
 
179
                case XK_Shift_R:    check_modifier ("Shift_R", ShiftMask); break;
 
180
                case XK_Shift_Lock: check_modifier ("Shift_Lock", LockMask); break;
 
181
                case XK_Caps_Lock:  check_modifier ("Caps_Lock", LockMask); break;
 
182
 
 
183
                /* It probably doesn't make any sense for a modifier bit to be
 
184
                 assigned to a key that is not one of the above, but OpenWindows
 
185
                 assigns modifier bits to a couple of random function keys for
 
186
                 no reason that I can discern, so printing a warning here would
 
187
                 be annoying. */
 
188
                }
 
189
            }
 
190
        }
 
191
#undef store_modifier
 
192
#undef check_modifier
 
193
#undef modwarn
 
194
#undef modbarf
 
195
 
 
196
    /* If there was no Meta key, then try using the Alt key instead.
 
197
     If there is both a Meta key and an Alt key, then the Alt key
 
198
     is not disturbed and remains an Alt key. */
 
199
    if (! meta_bit && alt_bit)
 
200
        meta_bit = alt_bit, alt_bit = 0;
 
201
 
 
202
    /* mode_bit overrides everything, since it's processed down inside of
 
203
     XLookupString() instead of by us.  If Meta and Mode_switch both
 
204
     generate the same modifier bit (which is an error), then we don't
 
205
     interpret that bit as Meta, because we can't make XLookupString()
 
206
     not interpret it as Mode_switch; and interpreting it as both would
 
207
     be totally wrong. */
 
208
    if (mode_bit)
 
209
    {
 
210
        const char *warn = 0;
 
211
        if      (mode_bit == meta_bit)  warn = "Meta",  meta_bit  = 0;
 
212
        else if (mode_bit == hyper_bit) warn = "Hyper", hyper_bit = 0;
 
213
        else if (mode_bit == super_bit) warn = "Super", super_bit = 0;
 
214
        else if (mode_bit == alt_bit)   warn = "Alt",   alt_bit   = 0;
 
215
        if (warn)
 
216
        {
 
217
            wwarning
 
218
                ("%s is being used for both Mode_switch and %s.\n\n",
 
219
                 index_to_name (mode_bit), warn),
 
220
                 warned_about_overlapping_modifiers = 1;
 
221
        }
 
222
    }
 
223
 
 
224
    MetaMask   = (meta_bit   ? (1 << meta_bit)  : 0);
 
225
    HyperMask  = (hyper_bit  ? (1 << hyper_bit) : 0);
 
226
    SuperMask  = (super_bit  ? (1 << super_bit) : 0);
 
227
    AltMask    = (alt_bit    ? (1 << alt_bit)   : 0);
 
228
    ModeMask   = (mode_bit   ? (1 << mode_bit)  : 0); /* unused */
 
229
 
 
230
#if 0
 
231
    if (warned_about_overlapping_modifiers)
 
232
        wwarning ("\n"
 
233
                  "     Two distinct modifier keys (such as Meta and Hyper) cannot generate\n"
 
234
                  "     the same modifier bit, because Emacs won't be able to tell which\n"
 
235
                  "     modifier was actually held down when some other key is pressed.  It\n"
 
236
                  "     won't be able to tell Meta-x and Hyper-x apart, for example.  Change\n"
 
237
                  "     one of these keys to use some other modifier bit.  If you intend for\n"
 
238
                  "     these keys to have the same behavior, then change them to have the\n"
 
239
                  "     same keysym as well as the same modifier bit.\n");
 
240
 
 
241
    if (warned_about_predefined_modifiers)
 
242
        wwarning ("\n"
 
243
                  "     The semantics of the modifier bits ModShift, ModLock, and ModControl\n"
 
244
                  "     are predefined.  It does not make sense to assign ModControl to any\n"
 
245
                  "     keysym other than Control_L or Control_R, or to assign any modifier\n"
 
246
                  "     bits to the \"control\" keysyms other than ModControl.  You can't\n"
 
247
                  "     turn a \"control\" key into a \"meta\" key (or vice versa) by simply\n"
 
248
                  "     assigning the key a different modifier bit.  You must also make that\n"
 
249
                  "     key generate an appropriate keysym (Control_L, Meta_L, etc).\n");
 
250
 
 
251
    /* No need to say anything more for warned_about_duplicate_modifiers. */
 
252
 
 
253
    if (warned_about_overlapping_modifiers || warned_about_predefined_modifiers)
 
254
        wwarning ("\n"
 
255
                  "     The meanings of the modifier bits Mod1 through Mod5 are determined\n"
 
256
                  "     by the keysyms used to control those bits.  Mod1 does NOT always\n"
 
257
                  "     mean Meta, although some non-ICCCM-compliant programs assume that.\n");
 
258
#endif
 
259
    XFreeModifiermap(x_modifier_keymap);
 
260
}
 
261
 
 
262
 
 
263
int
 
264
wXModifierFromKey(char *key)
 
265
{
 
266
    if (strcasecmp(key, "SHIFT")==0 && ShiftMask!=0)
 
267
        return ShiftMask;
 
268
    else if (strcasecmp(key, "CONTROL")==0 && ControlMask!=0)
 
269
        return ControlMask;
 
270
    else if (strcasecmp(key, "ALT")==0 && AltMask!=0)
 
271
        return AltMask;
 
272
    else if (strcasecmp(key, "META")==0 && MetaMask!=0)
 
273
        return MetaMask;
 
274
    else if (strcasecmp(key, "SUPER")==0 && SuperMask!=0)
 
275
        return SuperMask;
 
276
    else if (strcasecmp(key, "HYPER")==0 && HyperMask!=0)
 
277
        return HyperMask;
 
278
    else if (strcasecmp(key, "MOD1")==0 && Mod1Mask!=0)
 
279
        return Mod1Mask;
 
280
    else if (strcasecmp(key, "MOD2")==0 && Mod2Mask!=0)
 
281
        return Mod2Mask;
 
282
    else if (strcasecmp(key, "MOD3")==0 && Mod3Mask!=0)
 
283
        return Mod3Mask;
 
284
    else if (strcasecmp(key, "MOD4")==0 && Mod4Mask!=0)
 
285
        return Mod4Mask;
 
286
    else if (strcasecmp(key, "MOD5")==0 && Mod5Mask!=0)
 
287
        return Mod5Mask;
 
288
    else
 
289
        return -1;
 
290
}
 
291
 
 
292
/* Wrapper so that we may fit the WM naming conventions, yet leave the
 
293
 original XEmacs function name in place. */
 
294
void
 
295
wXModifierInitialize(void)
 
296
{
 
297
    x_reset_modifier_mapping(dpy);
 
298
}
 
299