Initial check-in
[him-cellwriter] / src / keyevent.c
1
2 /*
3
4 cellwriter -- a character recognition input method
5 Copyright (C) 2007 Michael Levin <risujin@risujin.org>
6
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License
9 as published by the Free Software Foundation; either version 2
10 of the License, or (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20
21 */
22
23 #include "hildon-im-ui.h"
24
25 #include "common.h"
26 #include "keys.h"
27 #include <string.h>
28 #include <stdlib.h>
29 #include <X11/X.h>
30 #include <X11/Xlib.h>
31 #include <X11/keysym.h>
32 #include <X11/extensions/XTest.h>
33 #include <gdk/gdkx.h>
34
35 /* Define this to always overwrite an unused KeyCode to send any KeySym */
36 /* #define ALWAYS_OVERWRITE */
37
38 /* Define this to print key events without actually generating them */
39 /* #define DEBUG_KEY_EVENTS */
40
41 /*
42         X11 KeyCodes
43 */
44
45 enum {
46         KEY_TAKEN = 0,   /* Has KeySyms, cannot be overwritten */
47         KEY_BAD,         /* Manually marked as unusable */
48         KEY_USABLE,      /* Has no KeySyms, can be overwritten */
49         KEY_ALLOCATED,   /* Normally usable, but currently allocated */
50         /* Values greater than this represent multiple allocations */
51 };
52
53 extern HildonIMUI *ui;
54
55 static char usable[256], pressed[256];
56 static int key_min, key_max, key_offset, key_codes;
57 //static KeySym *keysyms = NULL;
58 //static XModifierKeymap *modmap = NULL;
59
60 /* Bad keycodes: Despite having no KeySym entries, certain KeyCodes will
61    generate special KeySyms even if their KeySym entries have been overwritten.
62    For instance, KeyCode 204 attempts to eject the CD-ROM even if there is no
63    CD-ROM device present! KeyCode 229 will launch GNOME file search even if
64    there is no search button on the physical keyboard. There is no programatic
65    way around this but to keep a list of commonly used "bad" KeyCodes. */
66
67 void bad_keycodes_read(void)
68 {
69   /*
70         int keycode;
71
72         while (!profile_sync_int(&keycode)) {
73                 if (keycode < key_min || keycode > key_max) {
74                         g_warning("Cannot block bad keycode %d, out of range",
75                                   keycode);
76                         continue;
77                 }
78                 usable[keycode] = KEY_BAD;
79         }
80   */
81 }
82
83 void bad_keycodes_write(void)
84 {
85   /*
86         int i;
87
88         profile_write("bad_keycodes");
89         for (i = key_min; i < key_max; i++)
90                 if (usable[i] == KEY_BAD)
91                         profile_write(va(" %d", i));
92         profile_write("\n");
93   */
94 }
95
96 static void press_keycode(KeyCode k)
97 /* Called from various places to generate a key-down event */
98 {
99   //if (k >= key_min && k <= key_max)
100   //              XTestFakeKeyEvent(GDK_DISPLAY(), k, True, 1);
101 }
102
103 static void release_keycode(KeyCode k)
104 /* Called from various places to generate a key-up event */
105 {
106   //        if (k >= key_min && k <= key_max)
107   //            XTestFakeKeyEvent(GDK_DISPLAY(), k, False, 1);
108 }
109
110 static void type_keycode(KeyCode k)
111 /* Key-down + key-up */
112 {
113         press_keycode(k);
114         release_keycode(k);
115 }
116
117 static void setup_usable(void)
118 /* Find unused slots in the key mapping */
119 {
120   /*
121         int i, found;
122
123         /* Find all free keys 
124         memset(usable, 0, sizeof (usable));
125         for (i = key_min, found = 0; i <= key_max; i++) {
126                 int j;
127
128                 for (j = 0; j < key_codes &&
129                      keysyms[(i - key_min) * key_codes + j] == NoSymbol; j++);
130                 if (j < key_codes) {
131                         usable[i] = KEY_TAKEN;
132                         continue;
133                 }
134                 usable[i] = KEY_USABLE;
135                 found++;
136         }
137         key_offset = 0;
138
139         /* If we haven't found a usable key, it's probably because we have
140            already ran once ad used them all up without setting them back 
141         if (!found) {
142                 usable[key_max - key_min - 1] = KEY_USABLE;
143                 g_warning("Found no usable KeyCodes, restart the X server!");
144         } else
145                 g_debug("Found %d usable KeyCodes", found);
146   */
147 }
148
149 static void cleanup_usable(void)
150 /* Clear all the usable KeyCodes or we won't have any when we run again! */
151 {
152   /*
153         int i, bad, unused = 0, freed;
154
155         for (i = 0, freed = 0, bad = 0; i <= key_max; i++)
156                 if (usable[i] >= KEY_USABLE) {
157                         int j, kc_used = FALSE;
158
159                         for (j = 0; j < key_codes; j++) {
160                                 int index = (i - key_min) * key_codes + j;
161
162                                 if (keysyms[index] != NoSymbol)
163                                         kc_used = TRUE;
164                                 keysyms[index] = NoSymbol;
165                         }
166                         if (kc_used)
167                                 freed++;
168                         else
169                                 unused++;
170                 } else if (usable[i] == KEY_BAD)
171                         bad++;
172         if (freed) {
173                 XChangeKeyboardMapping(GDK_DISPLAY(), key_min, key_codes,
174                                        keysyms, key_max - key_min + 1);
175                 XFlush(GDK_DISPLAY());
176         }
177         g_debug("Free'd %d KeyCode(s), %d unused, %d marked bad",
178                 freed, unused, bad);
179   */
180 }
181
182 static void release_held_keys(void)
183 /* Release all held keys that were not pressed by us */
184 {
185   /*
186         int i;
187         char keys[32];
188
189         XQueryKeymap(GDK_DISPLAY(), keys);
190         for (i = 0; i < 32; i++) {
191                 int j;
192
193                 for (j = 0; j < 8; j++) {
194                         KeyCode keycode;
195
196                         keycode = i * 8 + j;
197                         if (keys[i] & (1 << j) && !pressed[keycode]) {
198                                 g_debug("Released held KeyCode %d", keycode);
199                                 release_keycode(keycode);
200                         }
201                 }
202         }
203   */
204 }
205
206 /*
207         Key Events
208 */
209
210 int key_overwrites = 0, key_recycles = 0,
211     key_shifted = 0, key_num_locked = FALSE, key_caps_locked = FALSE,
212     key_disable_overwrite = FALSE;
213
214 static int alt_mask, num_lock_mask, meta_mask;
215 static KeyEvent ke_shift, ke_enter, ke_num_lock, ke_caps_lock;
216
217 static void reset_keyboard(void)
218 /* In order to reliably predict key event behavior we need to be able to
219    reset the keyboard modifier and pressed state */
220 {
221   /*
222   Window root, child;
223         int root_x, root_y, win_x, win_y;
224         unsigned int mask;
225
226         release_held_keys();
227         XQueryPointer(GDK_DISPLAY(), GDK_WINDOW_XWINDOW(GDK_ROOT_PARENT()),
228                       &root, &child, &root_x, &root_y, &win_x, &win_y, &mask);
229         if (mask & LockMask)
230                 type_keycode(ke_caps_lock.keycode);
231         if (mask & num_lock_mask)
232                 type_keycode(ke_num_lock.keycode);
233   */
234 }
235
236 static int is_modifier(unsigned int keysym)
237 /* Returns TRUE for KeySyms that are tracked internally */
238 {
239         switch (keysym) {
240         case XK_Shift_L:
241         case XK_Shift_R:
242         case XK_Num_Lock:
243         case XK_Caps_Lock:
244                 return TRUE;
245         default:
246                 return FALSE;
247         }
248 }
249
250 static void key_event_allocate(KeyEvent *key_event, unsigned int keysym)
251 /* Either finds the KeyCode associated with the given keysym or overwrites
252    a usable one to generate it */
253 {
254   /*
255         int i, start;
256
257         //* Invalid KeySym 
258         if (!keysym) {
259                 key_event->keycode = -1;
260                 key_event->keysym = 0;
261                 return;
262         }
263
264         /* First see if our KeySym is already in the mapping 
265         key_event->shift = FALSE;
266 #ifndef ALWAYS_OVERWRITE
267         for (i = 0; i <= key_max - key_min; i++) {
268                 if (keysyms[i * key_codes + 1] == keysym)
269                         key_event->shift = TRUE;
270                 if (keysyms[i * key_codes] == keysym || key_event->shift) {
271                         key_event->keycode = key_min + i;
272                         key_recycles++;
273
274                         /* Bump the allocation count if this is an
275                            allocateable KeyCode 
276                         if (usable[key_event->keycode] >= KEY_USABLE)
277                                 usable[key_event->keycode]++;
278
279                         return;
280                 }
281         }
282 #endif
283
284         /* Key overwrites may be disabled, in which case we're out of luck 
285         if (key_disable_overwrite) {
286                 key_event->keycode = -1;
287                 key_event->keysym = 0;
288                 g_warning("Not allowed to overwrite KeyCode for %s",
289                           XKeysymToString(keysym));
290                 return;
291         }
292
293         /* If not, find a usable KeyCode in the mapping 
294         for (start = key_offset++; ; key_offset++) {
295                 if (key_offset > key_max - key_min)
296                         key_offset = 0;
297                 if (usable[key_min + key_offset] == KEY_USABLE &&
298                     !pressed[key_min + key_offset])
299                         break;
300
301                 /* If we can't find one, invalidate the event 
302                 if (key_offset == start) {
303                         key_event->keycode = -1;
304                         key_event->keysym = 0;
305                         g_warning("Failed to allocate KeyCode for %s",
306                                   XKeysymToString(keysym));
307                         return;
308                 }
309         }
310         key_overwrites++;
311         key_event->keycode = key_min + key_offset;
312         usable[key_event->keycode] = KEY_ALLOCATED;
313
314         /* Modify the slot to hold our character 
315         keysyms[key_offset * key_codes] = keysym;
316         keysyms[key_offset * key_codes + 1] = keysym;
317         XChangeKeyboardMapping(GDK_DISPLAY(), key_event->keycode, key_codes,
318                                keysyms + key_offset * key_codes, 1);
319         XSync(GDK_DISPLAY(), False);
320
321         g_debug("Overwrote KeyCode %d for %s", key_event->keycode,
322                 XKeysymToString(keysym));
323   */
324 }
325
326 void key_event_new(KeyEvent *key_event, unsigned int keysym)
327 /* Filters locks and shifts but allocates other keys normally */
328 {
329         key_event->keysym = keysym;
330         /*
331         if (is_modifier(keysym))
332                 return;
333         key_event_allocate(key_event, keysym);
334         */
335 }
336
337 void key_event_free(KeyEvent *key_event)
338 /* Release resources associated with and invalidate a key event */
339 {
340   /*
341         if (key_event->keycode >= key_min && key_event->keycode <= key_max &&
342             usable[key_event->keycode] == KEY_ALLOCATED)
343                 usable[key_event->keycode] = KEY_USABLE;
344         key_event->keycode = -1;
345         key_event->keysym = 0;
346   */
347 }
348
349 void key_event_press(KeyEvent *key_event)
350 /* Press the KeyCode specified in the event */
351 {
352   /*
353         /* Track modifiers without actually using them 
354         if (key_event->keysym == XK_Shift_L ||
355             key_event->keysym == XK_Shift_R) {
356                 key_shifted++;
357                 return;
358         } else if (key_event->keysym == XK_Caps_Lock) {
359                 key_caps_locked = !key_caps_locked;
360                 return;
361         } else if (key_event->keysym == XK_Num_Lock) {
362                 key_num_locked = !key_num_locked;
363                 return;
364         }
365
366         /* Invalid event 
367         if (key_event->keycode < key_min || key_event->keycode > key_max)
368                 return;
369
370         /* If this KeyCode is already pressed, something is wrong 
371         if (pressed[key_event->keycode]) {
372                 g_debug("KeyCode %d is already pressed", key_event->keycode);
373                 return;
374         }
375
376         /* Keep track of what KeyCodes we pressed down 
377         pressed[key_event->keycode] = TRUE;
378
379         /* Press our keycode 
380         if (key_event->shift)
381                 press_keycode(ke_shift.keycode);
382         press_keycode(key_event->keycode);
383         XSync(GDK_DISPLAY(), False);
384   */
385 }
386
387 void key_event_release(KeyEvent *key_event)
388 {
389   /*
390         /* Track modifiers without actually using them 
391         if (key_event->keysym == XK_Shift_L ||
392             key_event->keysym == XK_Shift_R) {
393                 key_shifted--;
394                 return;
395         }
396
397         /* Invalid key event 
398         if (key_event->keycode < key_min || key_event->keycode > key_max)
399                 return;
400
401         /* Keep track of what KeyCodes are pressed because of us 
402         pressed[key_event->keycode] = FALSE;
403
404         /* Release our keycode 
405         release_keycode(key_event->keycode);
406         if (key_event->shift)
407                 release_keycode(ke_shift.keycode);
408         XSync(GDK_DISPLAY(), False);
409   */
410 }
411
412 void unicode_to_utf8(unsigned int code, char *out){
413   // little endian
414   unsigned char *c = (unsigned char*)&code;
415   if(code < 0x80){
416     out[0] = c[0];
417     out[1] = 0;
418   }else if(code < 0x800){
419     out[0] = 0xC0 | (c[1] << 2) | (c[0] >> 6);
420     out[1] = 0x80 | (0x3F & c[0]);
421     out[2] = 0;
422   }else *out = 0; // todo
423 }
424
425 void key_event_send_char(int unichar)
426 {
427   char string[6];
428
429   unicode_to_utf8((unsigned int)unichar, string);
430   
431   if(ui){
432     if(unichar == '\n')
433       hildon_im_ui_send_communication_message(ui, HILDON_IM_CONTEXT_HANDLE_ENTER);
434     else
435       hildon_im_ui_send_utf8(ui, string);
436   }
437
438   /*
439         KeyEvent key_event;
440         KeySym keysym;
441
442         /* Get the keysym for the unichar (may be unsupported) 
443         keysym = XStringToKeysym(va("U%04X", unichar));
444         if (!keysym) {
445                 g_warning("XStringToKeysym failed to get Keysym for '%C'",
446                           unichar);
447                 return;
448         }
449
450         key_event_new(&key_event, keysym);
451         key_event_press(&key_event);
452         key_event_release(&key_event);
453         key_event_free(&key_event);
454         */
455 }
456
457 void key_event_send_enter()
458 {
459   //type_keycode(ke_enter.keycode);
460 }
461
462 int key_event_init()
463 {
464
465         /* Clear the array that keeps track of our pressed keys */
466         memset(pressed, 0, sizeof (pressed));
467
468         return 0;
469 }
470
471 void key_event_cleanup(void)
472 {
473 }