|
|
1.1 ! root 1: /* $Id: gtk-keyboard.c,v 1.6 2003/10/16 02:48:23 fredette Exp $ */ ! 2: ! 3: /* host/gtk/gtk-keyboard.c - GTK keyboard support: */ ! 4: ! 5: /* ! 6: * Copyright (c) 2003 Matt Fredette ! 7: * All rights reserved. ! 8: * ! 9: * Redistribution and use in source and binary forms, with or without ! 10: * modification, are permitted provided that the following conditions ! 11: * are met: ! 12: * 1. Redistributions of source code must retain the above copyright ! 13: * notice, this list of conditions and the following disclaimer. ! 14: * 2. Redistributions in binary form must reproduce the above copyright ! 15: * notice, this list of conditions and the following disclaimer in the ! 16: * documentation and/or other materials provided with the distribution. ! 17: * 3. All advertising materials mentioning features or use of this software ! 18: * must display the following acknowledgement: ! 19: * This product includes software developed by Matt Fredette. ! 20: * 4. The name of the author may not be used to endorse or promote products ! 21: * derived from this software without specific prior written permission. ! 22: * ! 23: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ! 24: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ! 25: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ! 26: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, ! 27: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ! 28: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ! 29: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, ! 31: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ! 32: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ! 33: * POSSIBILITY OF SUCH DAMAGE. ! 34: */ ! 35: ! 36: #include <tme/common.h> ! 37: _TME_RCSID("$Id: gtk-keyboard.c,v 1.6 2003/10/16 02:48:23 fredette Exp $"); ! 38: ! 39: /* includes: */ ! 40: #include "gtk-display.h" ! 41: #include <gdk/gdkkeysyms.h> ! 42: ! 43: /* macros: */ ! 44: ! 45: /* types: */ ! 46: ! 47: /* a GTK keysym: */ ! 48: struct tme_gtk_keysym { ! 49: ! 50: /* the type of this keysym. this is either ! 51: TME_KEYBOARD_LOOKUP_FLAG_OK_DIRECT or ! 52: TME_KEYBOARD_LOOKUP_FLAG_OK_ALLOC, depending on whether or not ! 53: the keysym needed to be allocated: */ ! 54: int tme_gtk_keysym_type; ! 55: ! 56: /* the keysym itself: */ ! 57: tme_keyboard_keyval_t tme_gtk_keysym_keysym; ! 58: }; ! 59: ! 60: /* if X11 support is present: */ ! 61: #ifndef X_DISPLAY_MISSING ! 62: ! 63: /* includes: */ ! 64: #include <gdk/gdkx.h> ! 65: #include <X11/Xlib.h> ! 66: ! 67: #if TME_KEYBOARD_EVENT_TIME_UNDEF != CurrentTime ! 68: #error "TME_KEYBOARD_EVENT_TIME_UNDEF and CurrentTime disagree" ! 69: #endif ! 70: ! 71: /* the X11 half of keyboard initialization: */ ! 72: static void ! 73: _tme_gtk_keyboard_x11_new(struct tme_gtk_display *display) ! 74: { ! 75: struct tme_keyboard_buffer *buffer; ! 76: XModifierKeymap *modifier_keymap; ! 77: int x_modifier, modifier; ! 78: int keycode_to_modifier[(1 << (sizeof(KeyCode) * 8))]; ! 79: tme_keyboard_keyval_t *modifier_keysyms[TME_KEYBOARD_MODIFIER_MAX + 1]; ! 80: int modifier_keysyms_count[TME_KEYBOARD_MODIFIER_MAX + 1]; ! 81: int keycode_min, keycode_max, keycode, keycode_i; ! 82: int keymap_width, keysym_i, keysym_j; ! 83: KeySym *keymap, keysym, keysym_cases[2]; ! 84: const char *string; ! 85: struct tme_gtk_keysym *gtk_keysym; ! 86: int rc; ! 87: ! 88: /* get the keyboard buffer: */ ! 89: buffer = display->tme_gtk_display_keyboard_buffer; ! 90: ! 91: /* note all keycodes that are attached to modifiers: */ ! 92: for (keycode = 0; ! 93: keycode < (int) TME_ARRAY_ELS(keycode_to_modifier); ! 94: keycode++) { ! 95: keycode_to_modifier[keycode] = TME_KEYBOARD_MODIFIER_NONE; ! 96: } ! 97: modifier_keymap = XGetModifierMapping(GDK_DISPLAY()); ! 98: for (x_modifier = 0; ! 99: x_modifier < 8; ! 100: x_modifier++) { ! 101: ! 102: /* turn this X modifier into a tme modifier: */ ! 103: switch (x_modifier) { ! 104: case ShiftMapIndex: modifier = TME_KEYBOARD_MODIFIER_SHIFT ; break; ! 105: case LockMapIndex: modifier = TME_KEYBOARD_MODIFIER_LOCK ; break; ! 106: case ControlMapIndex: modifier = TME_KEYBOARD_MODIFIER_CONTROL ; break; ! 107: case Mod1MapIndex: modifier = TME_KEYBOARD_MODIFIER_MOD1 ; break; ! 108: case Mod2MapIndex: modifier = TME_KEYBOARD_MODIFIER_MOD2 ; break; ! 109: case Mod3MapIndex: modifier = TME_KEYBOARD_MODIFIER_MOD3 ; break; ! 110: case Mod4MapIndex: modifier = TME_KEYBOARD_MODIFIER_MOD4 ; break; ! 111: default: assert (FALSE); ! 112: case Mod5MapIndex: modifier = TME_KEYBOARD_MODIFIER_MOD5 ; break; ! 113: } ! 114: ! 115: /* note all keycodes that are attached to this modifier: */ ! 116: for (keycode_i = 0; ! 117: keycode_i < modifier_keymap->max_keypermod; ! 118: keycode_i++) { ! 119: keycode = *(modifier_keymap->modifiermap ! 120: + (x_modifier * modifier_keymap->max_keypermod) ! 121: + keycode_i); ! 122: if (keycode != 0) { ! 123: keycode_to_modifier[keycode] = modifier; ! 124: } ! 125: } ! 126: } ! 127: XFreeModifiermap(modifier_keymap); ! 128: ! 129: /* get the keycode range: */ ! 130: XDisplayKeycodes(GDK_DISPLAY(), &keycode_min, &keycode_max); ! 131: ! 132: /* get the keyboard mapping: */ ! 133: keymap = XGetKeyboardMapping(GDK_DISPLAY(), ! 134: keycode_min, ! 135: (keycode_max - keycode_min) + 1, ! 136: &keymap_width); ! 137: ! 138: /* initialize the lists of modifiers to keysyms: */ ! 139: memset (modifier_keysyms_count, 0, sizeof(modifier_keysyms_count)); ! 140: ! 141: /* loop over the keycodes in the keyboard mapping: */ ! 142: for (keycode = keycode_min; ! 143: keycode <= keycode_max; ! 144: keycode++) { ! 145: ! 146: /* if this keycode is attached to a modifier, we will take the ! 147: first keysym that this keycode maps to as the keysym attached ! 148: to the modifier: */ ! 149: modifier = keycode_to_modifier[keycode]; ! 150: ! 151: /* loop over the keysyms that this keycode can map to: */ ! 152: for (keysym_i = 0; ! 153: keysym_i < keymap_width; ! 154: keysym_i++) { ! 155: ! 156: /* get this keysym: */ ! 157: keysym = *(keymap ! 158: + ((keycode - keycode_min) ! 159: * keymap_width) ! 160: + keysym_i); ! 161: ! 162: /* ignore NoSymbol: */ ! 163: if (keysym == NoSymbol) { ! 164: continue; ! 165: } ! 166: ! 167: /* get the upper- and lowercase versions of this keysym. if ! 168: this keysym has no case, this sets both keysym_cases[] values ! 169: to keysym: */ ! 170: XConvertCase(keysym, &keysym_cases[0], &keysym_cases[1]); ! 171: ! 172: for (keysym_j = 0; ! 173: keysym_j < (int) TME_ARRAY_ELS(keysym_cases); ! 174: keysym_j++) { ! 175: keysym = keysym_cases[keysym_j]; ! 176: ! 177: /* ignore any keysym that doesn't have a string ! 178: name that GDK knows as the same keysym: */ ! 179: if ((string = XKeysymToString(keysym)) == NULL ! 180: || gdk_keyval_from_name(string) != keysym) { ! 181: continue; ! 182: } ! 183: ! 184: /* skip this keysym if it's already known: */ ! 185: if (tme_hash_lookup(display->tme_gtk_display_keyboard_keysyms, ! 186: (tme_hash_data_t) string) ! 187: != (tme_hash_data_t) NULL) { ! 188: ! 189: /* if there is a keycode associated with this keysym, ! 190: remove it if it's different from this keycode: */ ! 191: if (tme_hash_lookup(display->tme_gtk_display_keyboard_keysym_to_keycode, ! 192: (tme_hash_data_t) keysym) ! 193: != (tme_hash_data_t) keycode) { ! 194: tme_hash_remove(display->tme_gtk_display_keyboard_keysym_to_keycode, ! 195: (tme_hash_data_t) keysym); ! 196: } ! 197: ! 198: continue; ! 199: } ! 200: ! 201: /* if this keysym is attached to a modifier: */ ! 202: if (modifier != TME_KEYBOARD_MODIFIER_NONE) { ! 203: ! 204: /* grow the modifier to keysyms list for this modifier. ! 205: this list always has an extra entry in it, for the ! 206: TME_KEYBOARD_KEYVAL_UNDEF that will terminate the list: */ ! 207: if (modifier_keysyms_count[modifier] == 0) { ! 208: modifier_keysyms[modifier] ! 209: = tme_new(tme_keyboard_keyval_t, 2); ! 210: } ! 211: else { ! 212: modifier_keysyms[modifier] ! 213: = tme_renew(tme_keyboard_keyval_t, ! 214: modifier_keysyms[modifier], ! 215: modifier_keysyms_count[modifier] + 2); ! 216: } ! 217: ! 218: /* store this modifier keysym: */ ! 219: modifier_keysyms[modifier][modifier_keysyms_count[modifier]] ! 220: = keysym; ! 221: modifier_keysyms_count[modifier]++; ! 222: ! 223: /* if this is a modifier that locks, tell the keyboard ! 224: buffer so that it can unlock it: */ ! 225: /* XXX if this X server *doesn't* give these keysyms ! 226: locking behavior, we must *not* unlock them, because ! 227: inferring the extra transitions would be wrong: */ ! 228: /* XXX we shouldn't attach them to the modifier either - ! 229: because the keyboard buffer input stage zero top half ! 230: assumes that keysyms attached to modifiers that it knows ! 231: about all have locking behavior. this is a feature bug ! 232: in the keyboard buffer: */ ! 233: if (!strcmp(string, "Caps_Lock") ! 234: || !strcmp(string, "Shift_Lock") ! 235: || !strcmp(string, "Num_Lock")) { ! 236: rc = tme_keyboard_buffer_in_mode(buffer, ! 237: keysym, ! 238: TME_KEYBOARD_MODE_UNLOCK); ! 239: assert (rc == TME_OK); ! 240: } ! 241: ! 242: /* don't attach more than one keysym per keycode to ! 243: this modifier: */ ! 244: modifier = TME_KEYBOARD_MODIFIER_NONE; ! 245: } ! 246: ! 247: /* remember that this keysym can be generated directly: */ ! 248: gtk_keysym = tme_new0(struct tme_gtk_keysym, 1); ! 249: gtk_keysym->tme_gtk_keysym_type ! 250: = TME_KEYBOARD_LOOKUP_FLAG_OK_DIRECT; ! 251: gtk_keysym->tme_gtk_keysym_keysym ! 252: = keysym; ! 253: tme_hash_insert(display->tme_gtk_display_keyboard_keysyms, ! 254: (tme_hash_data_t) string, ! 255: (tme_hash_data_t) gtk_keysym); ! 256: tme_hash_insert(display->tme_gtk_display_keyboard_keysym_to_keycode, ! 257: (tme_hash_data_t) keysym, ! 258: (tme_hash_data_t) keycode); ! 259: } ! 260: } ! 261: } ! 262: ! 263: /* free the keyboard mapping: */ ! 264: XFree(keymap); ! 265: ! 266: /* add in the modifiers information: */ ! 267: for (modifier = 0; ! 268: modifier < TME_KEYBOARD_MODIFIER_MAX; ! 269: modifier++) { ! 270: if (modifier_keysyms_count[modifier] > 0) { ! 271: modifier_keysyms[modifier][modifier_keysyms_count[modifier]] ! 272: = TME_KEYBOARD_KEYVAL_UNDEF; ! 273: rc = tme_keyboard_buffer_in_modifier(buffer, ! 274: modifier, ! 275: modifier_keysyms[modifier]); ! 276: assert (rc == TME_OK); ! 277: tme_free(modifier_keysyms[modifier]); ! 278: } ! 279: } ! 280: } ! 281: ! 282: #endif /* !X_DISPLAY_MISSING */ ! 283: ! 284: #if 1 ! 285: /* this is used for debugging only: */ ! 286: const char *_tme_gtk_keyboard_keyval_name _TME_P((tme_keyboard_keyval_t)); ! 287: const char * ! 288: _tme_gtk_keyboard_keyval_name(tme_keyboard_keyval_t keyval) ! 289: { ! 290: return (gdk_keyval_name(keyval)); ! 291: } ! 292: #endif ! 293: ! 294: /* this is a GTK callback for a key press or release event: */ ! 295: static int ! 296: _tme_gtk_keyboard_key_event(GtkWidget *widget, ! 297: GdkEvent *gdk_event_raw, ! 298: struct tme_gtk_screen *screen) ! 299: { ! 300: struct tme_gtk_display *display; ! 301: GdkEventKey *gdk_event; ! 302: struct tme_keyboard_event tme_event; ! 303: int was_empty; ! 304: int new_callouts; ! 305: int rc; ! 306: ! 307: /* make a tme event from this gdk event: */ ! 308: gdk_event = &gdk_event_raw->key; ! 309: tme_event.tme_keyboard_event_type ! 310: = (gdk_event->type == GDK_KEY_PRESS ! 311: ? TME_KEYBOARD_EVENT_PRESS ! 312: : TME_KEYBOARD_EVENT_RELEASE); ! 313: tme_event.tme_keyboard_event_modifiers ! 314: = gdk_event->state; ! 315: tme_event.tme_keyboard_event_keyval ! 316: = gdk_event->keyval; ! 317: tme_event.tme_keyboard_event_time ! 318: = gdk_event->time; ! 319: ! 320: /* assume that we won't need any new callouts: */ ! 321: new_callouts = 0; ! 322: ! 323: /* recover our data structure: */ ! 324: display = screen->tme_gtk_screen_display; ! 325: ! 326: /* lock the mutex: */ ! 327: tme_mutex_lock(&display->tme_gtk_display_mutex); ! 328: ! 329: /* if this is a press of the mouse mode off key, turn mouse mode off ! 330: and return now: */ ! 331: if (gdk_event->type == GDK_KEY_PRESS ! 332: && (gdk_event->keyval ! 333: == screen->tme_gtk_screen_mouse_keyval)) { ! 334: _tme_gtk_mouse_mode_off(screen, ! 335: gdk_event->time); ! 336: ! 337: /* unlock the mutex: */ ! 338: tme_mutex_unlock(&display->tme_gtk_display_mutex); ! 339: ! 340: return (TRUE); ! 341: } ! 342: ! 343: /* get any keycode associated with this keysym: */ ! 344: tme_event.tme_keyboard_event_keycode ! 345: = ((tme_keyboard_keyval_t) ! 346: tme_hash_lookup(display->tme_gtk_display_keyboard_keysym_to_keycode, ! 347: (tme_hash_data_t) tme_event.tme_keyboard_event_keyval)); ! 348: ! 349: /* remember if the keyboard buffer was empty: */ ! 350: was_empty ! 351: = tme_keyboard_buffer_is_empty(display->tme_gtk_display_keyboard_buffer); ! 352: ! 353: /* add this tme event to the keyboard buffer: */ ! 354: rc = tme_keyboard_buffer_copyin(display->tme_gtk_display_keyboard_buffer, ! 355: &tme_event); ! 356: assert (rc == TME_OK); ! 357: ! 358: /* if the keyboard buffer was empty and now it isn't, ! 359: call out the keyboard controls: */ ! 360: if (was_empty ! 361: && !tme_keyboard_buffer_is_empty(display->tme_gtk_display_keyboard_buffer)) { ! 362: new_callouts |= TME_GTK_DISPLAY_CALLOUT_KEYBOARD_CTRL; ! 363: } ! 364: ! 365: /* run any callouts: */ ! 366: _tme_gtk_display_callout(display, new_callouts); ! 367: ! 368: /* unlock the mutex: */ ! 369: tme_mutex_unlock(&display->tme_gtk_display_mutex); ! 370: ! 371: return (TRUE); ! 372: } ! 373: ! 374: /* this is called to look up a keysym: */ ! 375: static tme_keyboard_keyval_t ! 376: _tme_gtk_keyboard_lookup(struct tme_keyboard_connection *conn_keyboard, ! 377: const struct tme_keyboard_lookup *lookup) ! 378: { ! 379: struct tme_gtk_display *display; ! 380: struct tme_gtk_keysym *keysym; ! 381: struct tme_gtk_keysym_bad **_keysym_bad, *keysym_bad; ! 382: char *string; ! 383: guint _keysym; ! 384: ! 385: /* recover our data structure: */ ! 386: display = conn_keyboard ! 387: ->tme_keyboard_connection.tme_connection_element->tme_element_private; ! 388: ! 389: /* lock the mutex: */ ! 390: tme_mutex_lock(&display->tme_gtk_display_mutex); ! 391: ! 392: /* if this is the "no more lookups" call, log complaints about all ! 393: keysyms that we were asked to look up, but have no way of ! 394: generating: */ ! 395: if (lookup == NULL) { ! 396: for (; display->tme_gtk_display_keyboard_keysyms_bad != NULL; ) { ! 397: keysym_bad ! 398: = display->tme_gtk_display_keyboard_keysyms_bad; ! 399: ! 400: /* log the complaint: */ ! 401: tme_log(&display->tme_gtk_display_element->tme_element_log_handle, 0, ENOENT, ! 402: (&display->tme_gtk_display_element->tme_element_log_handle, ! 403: _("cannot generate keysym '%s' directly%s"), ! 404: keysym_bad->tme_gtk_keysym_bad_string, ! 405: (keysym_bad->tme_keysym_bad_flags ! 406: != TME_KEYBOARD_LOOKUP_FLAG_OK_DIRECT ! 407: ? "" ! 408: : _(", or through a macro")))); ! 409: ! 410: /* free this record: */ ! 411: display->tme_gtk_display_keyboard_keysyms_bad ! 412: = keysym_bad->tme_gtk_keysym_bad_next; ! 413: tme_free(keysym_bad->tme_gtk_keysym_bad_string); ! 414: tme_free(keysym_bad->tme_gtk_keysym_bad_context); ! 415: tme_free(keysym_bad); ! 416: } ! 417: ! 418: /* unlock the mutex: */ ! 419: tme_mutex_unlock(&display->tme_gtk_display_mutex); ! 420: ! 421: return (TME_OK); ! 422: } ! 423: ! 424: /* if this lookup has context, find any existing bad keysym record ! 425: with the same context: */ ! 426: _keysym_bad = NULL; ! 427: keysym_bad = NULL; ! 428: if (lookup->tme_keyboard_lookup_context_length > 0) { ! 429: for (_keysym_bad ! 430: = &display->tme_gtk_display_keyboard_keysyms_bad; ! 431: (keysym_bad = *_keysym_bad) != NULL; ! 432: _keysym_bad ! 433: = &keysym_bad->tme_gtk_keysym_bad_next) { ! 434: ! 435: /* stop if this bad keysym record has this context: */ ! 436: if ((keysym_bad->tme_gtk_keysym_bad_context_length ! 437: == lookup->tme_keyboard_lookup_context_length) ! 438: && !memcmp(keysym_bad->tme_gtk_keysym_bad_context, ! 439: lookup->tme_keyboard_lookup_context, ! 440: lookup->tme_keyboard_lookup_context_length)) { ! 441: break; ! 442: } ! 443: } ! 444: } ! 445: ! 446: /* look up this keysym: */ ! 447: keysym ! 448: = ((struct tme_gtk_keysym *) ! 449: tme_hash_lookup(display->tme_gtk_display_keyboard_keysyms, ! 450: (tme_hash_data_t) lookup->tme_keyboard_lookup_string)); ! 451: ! 452: /* if the lookup failed and we're allowed to allocate this keysym: */ ! 453: if (keysym == NULL ! 454: && (lookup->tme_keyboard_lookup_flags ! 455: & TME_KEYBOARD_LOOKUP_FLAG_OK_ALLOC_NOW)) { ! 456: ! 457: /* duplicate the lookup string: */ ! 458: string = tme_strdup(lookup->tme_keyboard_lookup_string); ! 459: ! 460: /* create the new keysym: */ ! 461: keysym = tme_new(struct tme_gtk_keysym, 1); ! 462: keysym->tme_gtk_keysym_type ! 463: = TME_KEYBOARD_LOOKUP_FLAG_OK_ALLOC; ! 464: ! 465: /* if GDK knows a keysym for this name: */ ! 466: keysym->tme_gtk_keysym_keysym ! 467: = gdk_keyval_from_name(string); ! 468: ! 469: /* if GDK doesn't know a keysym for this name, else find an ! 470: unused keysym: */ ! 471: if (keysym->tme_gtk_keysym_keysym ! 472: == GDK_VoidSymbol) { ! 473: ! 474: /* loop until we have an unused keysym that isn't also ! 475: TME_KEYBOARD_KEYVAL_UNDEF, or until we have exhausted the ! 476: GDK keysym space: */ ! 477: for (_keysym = 0;; ) { ! 478: if (_keysym != TME_KEYBOARD_KEYVAL_UNDEF ! 479: && gdk_keyval_name(_keysym) == NULL) { ! 480: break; ! 481: } ! 482: if (++_keysym == 0) { ! 483: abort(); ! 484: } ! 485: } ! 486: ! 487: /* use this new keysym: */ ! 488: keysym->tme_gtk_keysym_keysym ! 489: = _keysym; ! 490: } ! 491: ! 492: /* add this newly allocated keysym: */ ! 493: tme_hash_insert(display->tme_gtk_display_keyboard_keysyms, ! 494: (tme_hash_data_t) string, ! 495: (tme_hash_data_t) keysym); ! 496: } ! 497: ! 498: /* if the lookup failed or didn't give the right kind of keysym: */ ! 499: if (keysym == NULL ! 500: || !(keysym->tme_gtk_keysym_type ! 501: & lookup->tme_keyboard_lookup_flags)) { ! 502: ! 503: /* if this lookup has context, and no bad keysym record ! 504: exists for this context, create a new one: */ ! 505: if (lookup->tme_keyboard_lookup_context_length > 0 ! 506: && keysym_bad == NULL) { ! 507: ! 508: /* create the new bad keysym record: */ ! 509: keysym_bad = tme_new0(struct tme_gtk_keysym_bad, 1); ! 510: keysym_bad->tme_gtk_keysym_bad_next ! 511: = display->tme_gtk_display_keyboard_keysyms_bad; ! 512: keysym_bad->tme_gtk_keysym_bad_string ! 513: = tme_strdup(lookup->tme_keyboard_lookup_string); ! 514: keysym_bad->tme_keysym_bad_flags ! 515: = lookup->tme_keyboard_lookup_flags; ! 516: keysym_bad->tme_gtk_keysym_bad_context_length ! 517: = lookup->tme_keyboard_lookup_context_length; ! 518: keysym_bad->tme_gtk_keysym_bad_context ! 519: = tme_dup(tme_uint8_t, ! 520: lookup->tme_keyboard_lookup_context, ! 521: lookup->tme_keyboard_lookup_context_length); ! 522: ! 523: /* link in the new bad keysym record: */ ! 524: display->tme_gtk_display_keyboard_keysyms_bad ! 525: = keysym_bad; ! 526: } ! 527: ! 528: /* unlock the mutex: */ ! 529: tme_mutex_unlock(&display->tme_gtk_display_mutex); ! 530: ! 531: /* return failure: */ ! 532: return (TME_KEYBOARD_KEYVAL_UNDEF); ! 533: } ! 534: ! 535: /* otherwise, this lookup succeeded. if a bad keysym record existed ! 536: for this context, forget it - this successful lookup forgives ! 537: that earlier failure: */ ! 538: if (keysym_bad != NULL) { ! 539: *_keysym_bad = keysym_bad->tme_gtk_keysym_bad_next; ! 540: tme_free(keysym_bad->tme_gtk_keysym_bad_context); ! 541: tme_free(keysym_bad); ! 542: } ! 543: ! 544: /* unlock the mutex: */ ! 545: tme_mutex_unlock(&display->tme_gtk_display_mutex); ! 546: ! 547: return (keysym->tme_gtk_keysym_keysym); ! 548: } ! 549: ! 550: /* this is called when the keyboard controls change: */ ! 551: static int ! 552: _tme_gtk_keyboard_ctrl(struct tme_keyboard_connection *conn_keyboard, ! 553: unsigned int ctrl) ! 554: { ! 555: struct tme_gtk_display *display; ! 556: ! 557: /* recover our data structure: */ ! 558: display = conn_keyboard ! 559: ->tme_keyboard_connection.tme_connection_element->tme_element_private; ! 560: ! 561: /* ring the bell: */ ! 562: if (ctrl & TME_KEYBOARD_CTRL_BELL) { ! 563: gdk_beep(); ! 564: } ! 565: ! 566: return (TME_OK); ! 567: } ! 568: ! 569: /* this is called to read the keyboard: */ ! 570: static int ! 571: _tme_gtk_keyboard_read(struct tme_keyboard_connection *conn_keyboard, ! 572: struct tme_keyboard_event *event) ! 573: { ! 574: struct tme_gtk_display *display; ! 575: int rc; ! 576: ! 577: /* recover our data structure: */ ! 578: display = conn_keyboard ! 579: ->tme_keyboard_connection.tme_connection_element->tme_element_private; ! 580: ! 581: /* lock the mutex: */ ! 582: tme_mutex_lock(&display->tme_gtk_display_mutex); ! 583: ! 584: /* copy an event out of the keyboard buffer: */ ! 585: rc = tme_keyboard_buffer_copyout(display->tme_gtk_display_keyboard_buffer, ! 586: event); ! 587: ! 588: /* unlock the mutex: */ ! 589: tme_mutex_unlock(&display->tme_gtk_display_mutex); ! 590: ! 591: return (rc); ! 592: } ! 593: ! 594: /* this breaks a keyboard connection: */ ! 595: static int ! 596: _tme_gtk_keyboard_connection_break(struct tme_connection *conn, unsigned int state) ! 597: { ! 598: abort(); ! 599: } ! 600: ! 601: /* this makes a new keyboard connection: */ ! 602: static int ! 603: _tme_gtk_keyboard_connection_make(struct tme_connection *conn, ! 604: unsigned int state) ! 605: { ! 606: struct tme_gtk_display *display; ! 607: ! 608: /* recover our data structure: */ ! 609: display = conn->tme_connection_element->tme_element_private; ! 610: ! 611: /* both sides must be keyboard connections: */ ! 612: assert(conn->tme_connection_type ! 613: == TME_CONNECTION_KEYBOARD); ! 614: assert(conn->tme_connection_other->tme_connection_type ! 615: == TME_CONNECTION_KEYBOARD); ! 616: ! 617: /* we are always set up to answer calls across the connection, so we ! 618: only have to do work when the connection has gone full, namely ! 619: taking the other side of the connection: */ ! 620: if (state == TME_CONNECTION_FULL) { ! 621: ! 622: /* save our connection: */ ! 623: tme_mutex_lock(&display->tme_gtk_display_mutex); ! 624: display->tme_gtk_display_keyboard_connection ! 625: = (struct tme_keyboard_connection *) conn->tme_connection_other; ! 626: tme_mutex_unlock(&display->tme_gtk_display_mutex); ! 627: } ! 628: ! 629: return (TME_OK); ! 630: } ! 631: ! 632: /* this scores a keyboard connection: */ ! 633: static int ! 634: _tme_gtk_keyboard_connection_score(struct tme_connection *conn, ! 635: unsigned int *_score) ! 636: { ! 637: struct tme_keyboard_connection *conn_keyboard; ! 638: ! 639: /* both sides must be keyboard connections: */ ! 640: assert(conn->tme_connection_type == TME_CONNECTION_KEYBOARD); ! 641: assert(conn->tme_connection_other->tme_connection_type == TME_CONNECTION_KEYBOARD); ! 642: ! 643: /* the other side cannot be a real keyboard: */ ! 644: conn_keyboard ! 645: = (struct tme_keyboard_connection *) conn->tme_connection_other; ! 646: *_score = (conn_keyboard->tme_keyboard_connection_read == NULL ! 647: && conn_keyboard->tme_keyboard_connection_lookup == NULL); ! 648: return (TME_OK); ! 649: } ! 650: ! 651: /* this makes a new connection side for a GTK keyboard: */ ! 652: int ! 653: _tme_gtk_keyboard_connections_new(struct tme_gtk_display *display, ! 654: struct tme_connection **_conns) ! 655: { ! 656: struct tme_keyboard_connection *conn_keyboard; ! 657: struct tme_connection *conn; ! 658: ! 659: /* if we don't have a keyboard connection yet: */ ! 660: if (display->tme_gtk_display_keyboard_connection == NULL) { ! 661: ! 662: /* create our side of a keyboard connection: */ ! 663: conn_keyboard = tme_new0(struct tme_keyboard_connection, 1); ! 664: conn = &conn_keyboard->tme_keyboard_connection; ! 665: ! 666: /* fill in the generic connection: */ ! 667: conn->tme_connection_next = *_conns; ! 668: conn->tme_connection_type = TME_CONNECTION_KEYBOARD; ! 669: conn->tme_connection_score = _tme_gtk_keyboard_connection_score; ! 670: conn->tme_connection_make = _tme_gtk_keyboard_connection_make; ! 671: conn->tme_connection_break = _tme_gtk_keyboard_connection_break; ! 672: ! 673: /* fill in the keyboard connection: */ ! 674: conn_keyboard->tme_keyboard_connection_ctrl = _tme_gtk_keyboard_ctrl; ! 675: conn_keyboard->tme_keyboard_connection_read = _tme_gtk_keyboard_read; ! 676: conn_keyboard->tme_keyboard_connection_lookup = _tme_gtk_keyboard_lookup; ! 677: ! 678: /* return the connection side possibility: */ ! 679: *_conns = conn; ! 680: } ! 681: ! 682: /* done: */ ! 683: return (TME_OK); ! 684: } ! 685: ! 686: /* this attaches the GTK keyboard to a new screen: */ ! 687: void ! 688: _tme_gtk_keyboard_attach(struct tme_gtk_screen *screen) ! 689: { ! 690: ! 691: /* make sure the event box for the framebuffer gets enter, key_press ! 692: and key_release events. we have to add these latter two events ! 693: to both the event box widget itself, and the top-level window, ! 694: since GTK 1.x appears to not select KeyRelease events at the ! 695: top-level: */ ! 696: gtk_widget_add_events(screen->tme_gtk_screen_event_box, ! 697: GDK_ENTER_NOTIFY_MASK ! 698: | GDK_KEY_PRESS_MASK ! 699: | GDK_KEY_RELEASE_MASK); ! 700: gtk_widget_add_events (gtk_widget_get_toplevel(screen->tme_gtk_screen_event_box), ! 701: GDK_KEY_PRESS_MASK ! 702: | GDK_KEY_RELEASE_MASK); ! 703: ! 704: /* set a signal handler for these events: */ ! 705: gtk_signal_connect(GTK_OBJECT(screen->tme_gtk_screen_event_box), ! 706: "enter_notify_event", ! 707: GTK_SIGNAL_FUNC(_tme_gtk_display_enter_focus), ! 708: NULL); ! 709: gtk_signal_connect(GTK_OBJECT(screen->tme_gtk_screen_event_box), ! 710: "key_press_event", ! 711: GTK_SIGNAL_FUNC(_tme_gtk_keyboard_key_event), ! 712: screen); ! 713: gtk_signal_connect(GTK_OBJECT(screen->tme_gtk_screen_event_box), ! 714: "key_release_event", ! 715: GTK_SIGNAL_FUNC(_tme_gtk_keyboard_key_event), ! 716: screen); ! 717: ! 718: /* the event box can focus, and have it grab the focus now: */ ! 719: GTK_WIDGET_SET_FLAGS(screen->tme_gtk_screen_event_box, GTK_CAN_FOCUS); ! 720: gtk_widget_grab_focus(screen->tme_gtk_screen_event_box); ! 721: } ! 722: ! 723: /* this initializes keyboard part of the display: */ ! 724: void ! 725: _tme_gtk_keyboard_new(struct tme_gtk_display *display) ! 726: { ! 727: ! 728: /* we have no keyboard connection: */ ! 729: display->tme_gtk_display_keyboard_connection = NULL; ! 730: ! 731: /* allocate the keyboard buffer: */ ! 732: display->tme_gtk_display_keyboard_buffer ! 733: = tme_keyboard_buffer_new(1024); ! 734: display->tme_gtk_display_keyboard_buffer->tme_keyboard_buffer_log_handle ! 735: = &display->tme_gtk_display_element->tme_element_log_handle; ! 736: ! 737: /* allocate the keysyms hash: */ ! 738: display->tme_gtk_display_keyboard_keysyms ! 739: = tme_hash_new(tme_string_hash, ! 740: tme_string_compare, ! 741: (tme_hash_data_t) 0); ! 742: ! 743: /* allocate the keysym-to-keycode hash: */ ! 744: display->tme_gtk_display_keyboard_keysym_to_keycode ! 745: = tme_hash_new(tme_direct_hash, ! 746: tme_direct_compare, ! 747: (tme_hash_data_t) TME_KEYBOARD_KEYVAL_UNDEF); ! 748: ! 749: /* there are no bad keysyms: */ ! 750: display->tme_gtk_display_keyboard_keysyms_bad = NULL; ! 751: ! 752: /* initialize the input stages of the keyboard buffer. this needs ! 753: information that we can't get from GTK or GDK, like which keysyms ! 754: are attached to which modifiers, and which keysyms can be ! 755: generated by the keyboard: */ ! 756: #ifndef X_DISPLAY_MISSING ! 757: if (TRUE) { ! 758: _tme_gtk_keyboard_x11_new(display); ! 759: } ! 760: #endif /* !X_DISPLAY_MISSING */ ! 761: else { ! 762: abort(); ! 763: } ! 764: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.