1: #include <X/mit-copyright.h>
2:
3: /* $Header: XKeyBind.c,v 10.8 86/02/01 15:35:46 tony Rel $ */
4: /* Copyright 1985, Massachusetts Institute of Technology */
5:
6: #include "XlibInternal.h"
7: #include <sys/file.h>
8: #include <sys/stat.h>
9: #include "Xkeymap.h"
10: #include "Xkeyboard.h"
11: #include <stdio.h>
12: #include <strings.h>
13:
14: #define EMPTY_ENTRY LeftMask
15: /* if the "metabits" field of a runtime table entry contains this,
16: it's an empty entry */
17:
18: static KeyMapElt *keymap = NULL;
19: static Bool inited = FALSE;
20:
21: static ExtensionHeader *ext_begin, *ext_end;
22:
23: /* Runtime table: contains multiple-byte character bindings defined
24: at runtime with XRebindCode */
25:
26: typedef struct {
27: unsigned char keycode;
28: unsigned char metabits;
29: short length;
30: char *value;
31: } RuntimeTableEntry;
32:
33: static RuntimeTableEntry
34: *rt_begin, /* first entry of runtime table */
35: *rt_end, /* this and all succeeding entries are empty */
36: *rt_buf_end;/* points beyond end of allocated storage for table */
37:
38: #define RT_INITIAL_SIZE 100 /* initial size of runtime table */
39: #define RT_INCREMENT 40 /* size to grow by if expanded */
40:
41: static Initialize() {
42: int file = -1;
43: int filesize;
44: unsigned char magic;
45: struct stat filestat;
46: char *getenv();
47: char *filename;
48: char *home = getenv ("HOME");
49: inited = TRUE;
50: if (home) {
51: int homelen = strlen (home);
52: char *keymapstr = "/.Xkeymap";
53: int keymapstrlen = strlen (keymapstr);
54: filename = malloc (homelen + keymapstrlen + 1);
55: strncpy (filename, home, homelen+1);
56: strncat (filename, keymapstr, keymapstrlen);
57: file = open (filename, O_RDONLY, 0);
58: }
59: if (file < 0) {
60: free (filename);
61: return; /* no keymap file found */
62: }
63: fstat (file, &filestat);
64: filesize = filestat.st_size - 1; /* first byte is magic number */
65: if (filesize < 256*sizeof(KeyMapElt)) {
66: fprintf (stderr, "Keymap file %s is too small\n", filename);
67: close (file);
68: free (filename);
69: return;
70: }
71: read (file, &magic, 1);
72: if (magic != X_KEYMAP_MAGIC) {
73: fprintf (stderr,
74: "Keymap file %s doesn't begin with the proper magic number\n",
75: filename);
76: close (file);
77: free (filename);
78: return;
79: }
80: keymap = (KeyMapElt *) malloc (filesize);
81: if (!keymap) {
82: close (file);
83: free (filename);
84: return; /* couldn't malloc; just act like there isn't a keymap */
85: }
86: read (file, (char *) keymap, filesize);
87: ext_begin = (ExtensionHeader *) (keymap + 256);
88: ext_end = (ExtensionHeader *) (((char *) keymap) + filesize);
89: rt_begin = (RuntimeTableEntry *) malloc (RT_INITIAL_SIZE*sizeof(RuntimeTableEntry));
90: if (!rt_begin)
91: _XIOError (_XlibCurrentDisplay);
92: rt_end = rt_begin;
93: rt_buf_end = rt_begin + RT_INITIAL_SIZE;
94: free (filename);
95: close (file);
96: }
97:
98: /* this routine is used when initialization failed to find a
99: valid keymap file */
100: static char *BackstopLookupMapping (event, nbytes)
101: XKeyPressedEvent *event;
102: int *nbytes;
103: {
104: int detail = event->detail;
105: register int keycode = detail & ValueMask;
106: extern KeyMapEntry StdMap[];
107: static char c;
108: short s; /* needed to distinguish a real character (e.g. \0377) from -1 */
109: s = StdMap [keycode] [KeyState(detail)];
110: c = s;
111: if ((detail & ShiftLockMask) && (c >= 'a') && (c <= 'z'))
112: c += ('A' - 'a');
113: if (IsTypewriterKey(keycode)
114: || keycode == KC_ESC || keycode == KC_BS || keycode == KC_LF)
115: *nbytes = (s == -1 ? 0 : 1);
116: else
117: *nbytes = 0;
118: return (&c);
119: }
120:
121: char *XLookupMapping (event, nbytes)
122: XKeyPressedEvent *event;
123: int *nbytes;
124: {
125: int detail = event->detail;
126: unsigned int metabits = FullKeyState (detail);
127: unsigned int key = detail & ValueMask;
128: register unsigned char *the_char;
129:
130: if (!inited)
131: Initialize();
132: if (!keymap)
133: return (BackstopLookupMapping (event, nbytes));
134:
135: the_char = &keymap [key] [metabits];
136:
137: switch (*the_char) {
138:
139: case UNBOUND: {
140: *nbytes = 0;
141: return (NULL);
142: }
143:
144: case EXTENSION_BOUND: {
145: register ExtensionHeader *this;
146: for (this = ext_begin; this < ext_end; NextExtension(this))
147: if ((key == this->keycode)
148: && ((metabits == this->metabits) || (this->metabits == DontCareMetaBits))) {
149: *nbytes = this->length;
150: return ((char *)this + ExtensionHeaderSize);
151: }
152: /* if we get here, no match was found in the table extension */
153: *nbytes = 0;
154: return (NULL);
155: }
156:
157: case RUNTIME_TABLE_BOUND: {
158: register RuntimeTableEntry *entry;
159: for (entry = rt_begin; entry < rt_end; entry++)
160: if ((key == entry->keycode)
161: && ((metabits == entry->metabits) || (entry->metabits == DontCareMetaBits))) {
162: *nbytes = entry->length;
163: return (entry->value);
164: }
165:
166: /* if we get here, no match was found in the runtime table */
167: *nbytes = 0;
168: return (NULL);
169: }
170:
171: default: {
172: *nbytes = 1;
173: return ((char *)the_char);
174: }
175: }
176:
177: }
178:
179:
180: XRebindCode (keycode, metabits, str, nbytes)
181: unsigned int keycode, metabits;
182: char *str;
183: int nbytes;
184: {
185: unsigned char *table_char;
186: metabits = FullKeyState (metabits); /* shift meta bits to rightmost four bits */
187: if (!inited)
188: Initialize();
189: if (!keymap)
190: return; /* no keymap file; what else can I do? */
191: table_char = &keymap [keycode] [metabits];
192: if (nbytes == 0) {
193: if (*table_char == RUNTIME_TABLE_BOUND)
194: Unbind (keycode, metabits);
195: *table_char = UNBOUND;
196: return;
197: }
198: if ((nbytes == 1) && SingleCharBound (*str)) {
199: if (*table_char == RUNTIME_TABLE_BOUND)
200: Unbind (keycode, metabits);
201: *table_char = *str;
202: return;
203: }
204:
205: /* the new binding is either multi-character, or one of the
206: three reserved special characters */
207:
208: if (*table_char == RUNTIME_TABLE_BOUND) {
209: /* entry is already in table; just change its binding */
210: register RuntimeTableEntry *entry;
211: for (entry = rt_begin; entry < rt_end; entry++)
212: if (keycode == entry->keycode && metabits == entry->metabits) {
213: entry->value = str;
214: entry->length = nbytes;
215: return;
216: }
217: /* if we get here, entry wasn't found in table; shouldn't
218: * ever happen! Not much to do but fall through to
219: * the following code. */
220: }
221:
222: /* new binding must go in a new entry in the table */
223: *table_char = RUNTIME_TABLE_BOUND;
224: if (rt_end < rt_buf_end) {
225: rt_end->keycode = keycode;
226: rt_end->metabits = metabits;
227: rt_end->value = str;
228: rt_end++->length = nbytes;
229: return;
230: }
231:
232: /* no room at end of table; look for holes in middle */
233: {
234: register RuntimeTableEntry *entry;
235: for (entry = rt_begin; entry < rt_end; entry++)
236: if (entry->metabits == EMPTY_ENTRY) {
237: entry->keycode = keycode;
238: entry->metabits = metabits;
239: entry->value = str;
240: entry->length = nbytes;
241: return;
242: }
243: }
244:
245: /* no room in table at all. Must expand it. */
246: {
247: int rt_length = rt_end - rt_begin;
248: realloc (&rt_begin, (rt_length+RT_INCREMENT)*sizeof (RuntimeTableEntry));
249: rt_end = rt_begin + rt_length;
250: rt_buf_end = rt_end + RT_INCREMENT;
251: rt_end->keycode = keycode;
252: rt_end->metabits = metabits;
253: rt_end->value = str;
254: rt_end++->length = nbytes;
255: }
256: }
257:
258:
259: static Unbind (keycode, metabits)
260: unsigned int keycode, metabits;
261: {
262: register RuntimeTableEntry *entry;
263: for (entry = rt_begin; entry < rt_end; entry++)
264: if (keycode == entry->keycode && metabits == entry->metabits) {
265: entry->metabits = EMPTY_ENTRY;
266: return;
267: }
268: }
Defined functions
Defined variables
Defined macros