File: xmodifier.c

package info (click to toggle)
wmaker 0.96.0-5
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 17,416 kB
  • sloc: ansic: 99,483; sh: 7,068; perl: 3,423; makefile: 1,647; lisp: 219; python: 34
file content (311 lines) | stat: -rw-r--r-- 9,972 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
/* Grok X modifier mappings for shortcuts.

Most of this code was taken from src/event-Xt.c in XEmacs 20.3-b17.
The copyright(s) from the original XEmacs code are included below.

Perpetrator: Sudish Joseph <sj@eng.mindspring.net>, Sept. 1997. */

/*
 * More changes for WPrefs by Alfredo Kojima, Aug 1998
 */

/* The event_stream interface for X11 with Xt, and/or tty frames.
 Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
 Copyright (C) 1995 Sun Microsystems, Inc.
 Copyright (C) 1996 Ben Wing.

 This file is part of XEmacs.

 XEmacs is free software; you can redistribute it and/or modify it
 under the terms of the GNU General Public License as published by the
 Free Software Foundation; either version 2, or (at your option) any
 later version.

 XEmacs is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 for more details.

 You should have received a copy of the GNU General Public License along
 with XEmacs; see the file COPYING. if not, write to the
 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 Boston, MA 02110-1301 USA. */

#include <string.h>
#include <strings.h>
#include <X11/Xlib.h>
#include <X11/keysym.h>
#include <X11/XKBlib.h>

#include <WINGs/WUtil.h>

#include "WPrefs.h"

/************************************************************************/
/*                            keymap handling                           */
/************************************************************************/

/* X bogusly doesn't define the interpretations of any bits besides
 ModControl, ModShift, and ModLock; so the Interclient Communication
 Conventions Manual says that we have to bend over backwards to figure
 out what the other modifier bits mean.  According to ICCCM:

 - Any keycode which is assigned ModControl is a "control" key.

 - Any modifier bit which is assigned to a keycode which generates Meta_L
 or Meta_R is the modifier bit meaning "meta".  Likewise for Super, Hyper,
 etc.

 - Any keypress event which contains ModControl in its state should be
 interpreted as a "control" character.

 - Any keypress event which contains a modifier bit in its state which is
 generated by a keycode whose corresponding keysym is Meta_L or Meta_R
 should be interpreted as a "meta" character.  Likewise for Super, Hyper,
 etc.

 - It is illegal for a keysym to be associated with more than one modifier
 bit.

 This means that the only thing that emacs can reasonably interpret as a
 "meta" key is a key whose keysym is Meta_L or Meta_R, and which generates
 one of the modifier bits Mod1-Mod5.

 Unfortunately, many keyboards don't have Meta keys in their default
 configuration.  So, if there are no Meta keys, but there are "Alt" keys,
 emacs will interpret Alt as Meta.  If there are both Meta and Alt keys,
 then the Meta keys mean "Meta", and the Alt keys mean "Alt" (it used to
 mean "Symbol," but that just confused the hell out of way too many people).

 This works with the default configurations of the 19 keyboard-types I've
 checked.

 Emacs detects keyboard configurations which violate the above rules, and
 prints an error message on the standard-error-output.  (Perhaps it should
 use a pop-up-window instead.)
 */

static int MetaIndex, HyperIndex, SuperIndex, AltIndex, ModeIndex;

static const char *index_to_name(int indice)
{
	switch (indice) {
	case ShiftMapIndex:
		return "ModShift";
	case LockMapIndex:
		return "ModLock";
	case ControlMapIndex:
		return "ModControl";
	case Mod1MapIndex:
		return "Mod1";
	case Mod2MapIndex:
		return "Mod2";
	case Mod3MapIndex:
		return "Mod3";
	case Mod4MapIndex:
		return "Mod4";
	case Mod5MapIndex:
		return "Mod5";
	default:
		return "???";
	}
}

static void x_reset_modifier_mapping(Display * display)
{
	int modifier_index, modifier_key, column, mkpm;
	int meta_bit = 0;
	int hyper_bit = 0;
	int super_bit = 0;
	int alt_bit = 0;
	int mode_bit = 0;
	XModifierKeymap *x_modifier_keymap;

#define modwarn(name,old,other)							\
    wwarning(_("%s (0x%x) generates %s which is generated by %s"),		\
    name, code, index_to_name (old), other)

#define modbarf(name,other)							\
    wwarning(_("%s (0x%x) generates %s which is nonsensical"),			\
    name, code, other)

#define check_modifier(name,mask)						\
    if ((1<<modifier_index) != mask)						\
    wwarning(_("%s (0x%x) generates %s which is nonsensical"),			\
    name, code, index_to_name (modifier_index))

#define store_modifier(name,old)						\
    if (old && old != modifier_index)						\
    wwarning(_("%s (0x%x) generates both %s and %s which is nonsensical"),	\
    name, code, index_to_name (old),						\
    index_to_name (modifier_index));						\
    if (modifier_index == ShiftMapIndex) modbarf (name,"ModShift");		\
    else if (modifier_index == LockMapIndex) modbarf (name,"ModLock");		\
    else if (modifier_index == ControlMapIndex) modbarf (name,"ModControl");	\
    else if (sym == XK_Mode_switch)						\
    mode_bit = modifier_index; /* Mode_switch is special, see below... */	\
    else if (modifier_index == meta_bit && old != meta_bit)			\
    modwarn (name, meta_bit, "Meta");						\
    else if (modifier_index == super_bit && old != super_bit)			\
    modwarn (name, super_bit, "Super");						\
    else if (modifier_index == hyper_bit && old != hyper_bit)			\
    modwarn (name, hyper_bit, "Hyper");						\
    else if (modifier_index == alt_bit && old != alt_bit)			\
    modwarn (name, alt_bit, "Alt");						\
    else									\
    old = modifier_index;

	x_modifier_keymap = XGetModifierMapping(display);
	if (x_modifier_keymap == NULL) {
		wwarning(_("XGetModifierMapping returned NULL, there is no modifier or no memory"));
		return;
	}

	mkpm = x_modifier_keymap->max_keypermod;
	for (modifier_index = 0; modifier_index < 8; modifier_index++)
		for (modifier_key = 0; modifier_key < mkpm; modifier_key++) {
			KeySym last_sym = 0;
			for (column = 0; column < 4; column += 2) {
				KeyCode code = x_modifier_keymap->modifiermap[modifier_index * mkpm
									      + modifier_key];
				KeySym sym;

				if (code) {
					sym = W_KeycodeToKeysym(display, code, column);
				} else {
					sym = NoSymbol;
				}

				if (sym == last_sym)
					continue;
				last_sym = sym;
				switch (sym) {
				case XK_Mode_switch:
					store_modifier("Mode_switch", mode_bit);
					break;
				case XK_Meta_L:
					store_modifier("Meta_L", meta_bit);
					break;
				case XK_Meta_R:
					store_modifier("Meta_R", meta_bit);
					break;
				case XK_Super_L:
					store_modifier("Super_L", super_bit);
					break;
				case XK_Super_R:
					store_modifier("Super_R", super_bit);
					break;
				case XK_Hyper_L:
					store_modifier("Hyper_L", hyper_bit);
					break;
				case XK_Hyper_R:
					store_modifier("Hyper_R", hyper_bit);
					break;
				case XK_Alt_L:
					store_modifier("Alt_L", alt_bit);
					break;
				case XK_Alt_R:
					store_modifier("Alt_R", alt_bit);
					break;
				case XK_Control_L:
					check_modifier("Control_L", ControlMask);
					break;
				case XK_Control_R:
					check_modifier("Control_R", ControlMask);
					break;
				case XK_Shift_L:
					check_modifier("Shift_L", ShiftMask);
					break;
				case XK_Shift_R:
					check_modifier("Shift_R", ShiftMask);
					break;
				case XK_Shift_Lock:
					check_modifier("Shift_Lock", LockMask);
					break;
				case XK_Caps_Lock:
					check_modifier("Caps_Lock", LockMask);
					break;

					/* It probably doesn't make any sense for a modifier bit to be
					   assigned to a key that is not one of the above, but OpenWindows
					   assigns modifier bits to a couple of random function keys for
					   no reason that I can discern, so printing a warning here would
					   be annoying. */
				}
			}
		}
#undef store_modifier
#undef check_modifier
#undef modwarn
#undef modbarf

	/* If there was no Meta key, then try using the Alt key instead.
	   If there is both a Meta key and an Alt key, then the Alt key
	   is not disturbed and remains an Alt key. */
	if (!meta_bit && alt_bit)
		meta_bit = alt_bit, alt_bit = 0;

	/* mode_bit overrides everything, since it's processed down inside of
	   XLookupString() instead of by us.  If Meta and Mode_switch both
	   generate the same modifier bit (which is an error), then we don't
	   interpret that bit as Meta, because we can't make XLookupString()
	   not interpret it as Mode_switch; and interpreting it as both would
	   be totally wrong. */
	if (mode_bit) {
		const char *warn = 0;
		if (mode_bit == meta_bit)
			warn = "Meta", meta_bit = 0;
		else if (mode_bit == hyper_bit)
			warn = "Hyper", hyper_bit = 0;
		else if (mode_bit == super_bit)
			warn = "Super", super_bit = 0;
		else if (mode_bit == alt_bit)
			warn = "Alt", alt_bit = 0;
		if (warn) {
			wwarning(_("%s is being used for both %s and %s"),
			         index_to_name(mode_bit), "Mode_switch", warn);
		}
	}

	MetaIndex = meta_bit;
	HyperIndex = hyper_bit;
	SuperIndex = super_bit;
	AltIndex = alt_bit;
	ModeIndex = mode_bit;

	XFreeModifiermap(x_modifier_keymap);
}

int ModifierFromKey(Display * dpy, const char *key)
{
	static int eqw = 0;

	if (!eqw)
		x_reset_modifier_mapping(dpy);
	eqw = 1;

	if (strcasecmp(key, "SHIFT") == 0)
		return ShiftMapIndex;
	else if (strcasecmp(key, "CONTROL") == 0)
		return ControlMapIndex;
	else if (strcasecmp(key, "ALT") == 0)
		return AltIndex;
	else if (strcasecmp(key, "META") == 0)
		return MetaIndex;
	else if (strcasecmp(key, "SUPER") == 0)
		return SuperIndex;
	else if (strcasecmp(key, "HYPER") == 0)
		return HyperIndex;
	else if (strcasecmp(key, "MOD1") == 0)
		return Mod1MapIndex;
	else if (strcasecmp(key, "MOD2") == 0)
		return Mod2MapIndex;
	else if (strcasecmp(key, "MOD3") == 0)
		return Mod3MapIndex;
	else if (strcasecmp(key, "MOD4") == 0)
		return Mod4MapIndex;
	else if (strcasecmp(key, "MOD5") == 0)
		return Mod5MapIndex;
	else
		return -1;
}