|
|
1.1.1.3 ! root 1: /* $Id: gtk-keyboard.c,v 1.10 2007/02/15 02:15:41 fredette Exp $ */ 1.1 root 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> 1.1.1.3 ! root 37: _TME_RCSID("$Id: gtk-keyboard.c,v 1.10 2007/02/15 02:15:41 fredette Exp $"); 1.1 root 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) 1.1.1.3 ! root 193: != tme_keyboard_hash_data_from_keyval((tme_uint32_t) keycode)) { 1.1 root 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, 1.1.1.3 ! root 258: tme_keyboard_hash_data_from_keyval((tme_uint32_t) keycode)); 1.1 root 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 1.1.1.3 ! root 345: = tme_keyboard_hash_data_to_keyval(tme_hash_lookup(display->tme_gtk_display_keyboard_keysym_to_keycode, ! 346: tme_keyboard_hash_data_from_keyval(tme_event.tme_keyboard_event_keyval))); 1.1 root 347: 348: /* remember if the keyboard buffer was empty: */ 349: was_empty 350: = tme_keyboard_buffer_is_empty(display->tme_gtk_display_keyboard_buffer); 351: 352: /* add this tme event to the keyboard buffer: */ 353: rc = tme_keyboard_buffer_copyin(display->tme_gtk_display_keyboard_buffer, 354: &tme_event); 355: assert (rc == TME_OK); 356: 357: /* if the keyboard buffer was empty and now it isn't, 358: call out the keyboard controls: */ 359: if (was_empty 360: && !tme_keyboard_buffer_is_empty(display->tme_gtk_display_keyboard_buffer)) { 361: new_callouts |= TME_GTK_DISPLAY_CALLOUT_KEYBOARD_CTRL; 362: } 363: 364: /* run any callouts: */ 365: _tme_gtk_display_callout(display, new_callouts); 366: 367: /* unlock the mutex: */ 368: tme_mutex_unlock(&display->tme_gtk_display_mutex); 369: 1.1.1.2 root 370: /* don't process this event any further: */ 1.1 root 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; 1.1.1.3 ! root 383: const char *string_other; 1.1 root 384: guint _keysym; 385: 386: /* recover our data structure: */ 387: display = conn_keyboard 388: ->tme_keyboard_connection.tme_connection_element->tme_element_private; 389: 390: /* lock the mutex: */ 391: tme_mutex_lock(&display->tme_gtk_display_mutex); 392: 393: /* if this is the "no more lookups" call, log complaints about all 394: keysyms that we were asked to look up, but have no way of 395: generating: */ 396: if (lookup == NULL) { 397: for (; display->tme_gtk_display_keyboard_keysyms_bad != NULL; ) { 398: keysym_bad 399: = display->tme_gtk_display_keyboard_keysyms_bad; 400: 401: /* log the complaint: */ 402: tme_log(&display->tme_gtk_display_element->tme_element_log_handle, 0, ENOENT, 403: (&display->tme_gtk_display_element->tme_element_log_handle, 404: _("cannot generate keysym '%s' directly%s"), 405: keysym_bad->tme_gtk_keysym_bad_string, 406: (keysym_bad->tme_keysym_bad_flags 1.1.1.2 root 407: == TME_KEYBOARD_LOOKUP_FLAG_OK_DIRECT 1.1 root 408: ? "" 409: : _(", or through a macro")))); 410: 411: /* free this record: */ 412: display->tme_gtk_display_keyboard_keysyms_bad 413: = keysym_bad->tme_gtk_keysym_bad_next; 414: tme_free(keysym_bad->tme_gtk_keysym_bad_string); 415: tme_free(keysym_bad->tme_gtk_keysym_bad_context); 416: tme_free(keysym_bad); 417: } 418: 419: /* unlock the mutex: */ 420: tme_mutex_unlock(&display->tme_gtk_display_mutex); 421: 422: return (TME_OK); 423: } 424: 425: /* if this lookup has context, find any existing bad keysym record 426: with the same context: */ 427: _keysym_bad = NULL; 428: keysym_bad = NULL; 429: if (lookup->tme_keyboard_lookup_context_length > 0) { 430: for (_keysym_bad 431: = &display->tme_gtk_display_keyboard_keysyms_bad; 432: (keysym_bad = *_keysym_bad) != NULL; 433: _keysym_bad 434: = &keysym_bad->tme_gtk_keysym_bad_next) { 435: 436: /* stop if this bad keysym record has this context: */ 437: if ((keysym_bad->tme_gtk_keysym_bad_context_length 438: == lookup->tme_keyboard_lookup_context_length) 439: && !memcmp(keysym_bad->tme_gtk_keysym_bad_context, 440: lookup->tme_keyboard_lookup_context, 441: lookup->tme_keyboard_lookup_context_length)) { 442: break; 443: } 444: } 445: } 446: 447: /* look up this keysym: */ 448: keysym 449: = ((struct tme_gtk_keysym *) 450: tme_hash_lookup(display->tme_gtk_display_keyboard_keysyms, 451: (tme_hash_data_t) lookup->tme_keyboard_lookup_string)); 452: 453: /* if the lookup failed and we're allowed to allocate this keysym: */ 454: if (keysym == NULL 455: && (lookup->tme_keyboard_lookup_flags 456: & TME_KEYBOARD_LOOKUP_FLAG_OK_ALLOC_NOW)) { 457: 458: /* duplicate the lookup string: */ 459: string = tme_strdup(lookup->tme_keyboard_lookup_string); 460: 461: /* create the new keysym: */ 462: keysym = tme_new(struct tme_gtk_keysym, 1); 463: keysym->tme_gtk_keysym_type 464: = TME_KEYBOARD_LOOKUP_FLAG_OK_ALLOC; 465: 466: /* if GDK knows a keysym for this name: */ 467: keysym->tme_gtk_keysym_keysym 468: = gdk_keyval_from_name(string); 469: 1.1.1.3 ! root 470: /* if GDK doesn't know a keysym for this name, or if the string ! 471: for this keysym isn't the same name, find an unused keysym: */ ! 472: if (keysym->tme_gtk_keysym_keysym == GDK_VoidSymbol ! 473: || (string_other = gdk_keyval_name(keysym->tme_gtk_keysym_keysym)) == NULL ! 474: || strcmp(string, string_other)) { 1.1 root 475: 476: /* loop until we have an unused keysym that isn't also 477: TME_KEYBOARD_KEYVAL_UNDEF, or until we have exhausted the 478: GDK keysym space: */ 1.1.1.3 ! root 479: for (_keysym = display->tme_gtk_display_keyboard_keysym_alloc_next;;) { ! 480: if ((_keysym + 1) == 0) { ! 481: abort(); ! 482: } 1.1 root 483: if (_keysym != TME_KEYBOARD_KEYVAL_UNDEF 1.1.1.3 ! root 484: && _keysym != GDK_VoidSymbol 1.1 root 485: && gdk_keyval_name(_keysym) == NULL) { 486: break; 487: } 1.1.1.3 ! root 488: _keysym++; 1.1 root 489: } 1.1.1.3 ! root 490: display->tme_gtk_display_keyboard_keysym_alloc_next = _keysym + 1; 1.1 root 491: 492: /* use this new keysym: */ 493: keysym->tme_gtk_keysym_keysym 494: = _keysym; 495: } 496: 497: /* add this newly allocated keysym: */ 498: tme_hash_insert(display->tme_gtk_display_keyboard_keysyms, 499: (tme_hash_data_t) string, 500: (tme_hash_data_t) keysym); 501: } 502: 503: /* if the lookup failed or didn't give the right kind of keysym: */ 504: if (keysym == NULL 505: || !(keysym->tme_gtk_keysym_type 506: & lookup->tme_keyboard_lookup_flags)) { 507: 508: /* if this lookup has context, and no bad keysym record 509: exists for this context, create a new one: */ 510: if (lookup->tme_keyboard_lookup_context_length > 0 511: && keysym_bad == NULL) { 512: 513: /* create the new bad keysym record: */ 514: keysym_bad = tme_new0(struct tme_gtk_keysym_bad, 1); 515: keysym_bad->tme_gtk_keysym_bad_next 516: = display->tme_gtk_display_keyboard_keysyms_bad; 517: keysym_bad->tme_gtk_keysym_bad_string 518: = tme_strdup(lookup->tme_keyboard_lookup_string); 519: keysym_bad->tme_keysym_bad_flags 520: = lookup->tme_keyboard_lookup_flags; 521: keysym_bad->tme_gtk_keysym_bad_context_length 522: = lookup->tme_keyboard_lookup_context_length; 523: keysym_bad->tme_gtk_keysym_bad_context 524: = tme_dup(tme_uint8_t, 525: lookup->tme_keyboard_lookup_context, 526: lookup->tme_keyboard_lookup_context_length); 527: 528: /* link in the new bad keysym record: */ 529: display->tme_gtk_display_keyboard_keysyms_bad 530: = keysym_bad; 531: } 532: 533: /* unlock the mutex: */ 534: tme_mutex_unlock(&display->tme_gtk_display_mutex); 535: 536: /* return failure: */ 537: return (TME_KEYBOARD_KEYVAL_UNDEF); 538: } 539: 540: /* otherwise, this lookup succeeded. if a bad keysym record existed 541: for this context, forget it - this successful lookup forgives 542: that earlier failure: */ 543: if (keysym_bad != NULL) { 544: *_keysym_bad = keysym_bad->tme_gtk_keysym_bad_next; 545: tme_free(keysym_bad->tme_gtk_keysym_bad_context); 546: tme_free(keysym_bad); 547: } 548: 549: /* unlock the mutex: */ 550: tme_mutex_unlock(&display->tme_gtk_display_mutex); 551: 552: return (keysym->tme_gtk_keysym_keysym); 553: } 554: 555: /* this is called when the keyboard controls change: */ 556: static int 557: _tme_gtk_keyboard_ctrl(struct tme_keyboard_connection *conn_keyboard, 558: unsigned int ctrl) 559: { 560: struct tme_gtk_display *display; 561: 562: /* recover our data structure: */ 563: display = conn_keyboard 564: ->tme_keyboard_connection.tme_connection_element->tme_element_private; 565: 566: /* ring the bell: */ 567: if (ctrl & TME_KEYBOARD_CTRL_BELL) { 568: gdk_beep(); 569: } 570: 571: return (TME_OK); 572: } 573: 574: /* this is called to read the keyboard: */ 575: static int 576: _tme_gtk_keyboard_read(struct tme_keyboard_connection *conn_keyboard, 577: struct tme_keyboard_event *event) 578: { 579: struct tme_gtk_display *display; 580: int rc; 581: 582: /* recover our data structure: */ 583: display = conn_keyboard 584: ->tme_keyboard_connection.tme_connection_element->tme_element_private; 585: 586: /* lock the mutex: */ 587: tme_mutex_lock(&display->tme_gtk_display_mutex); 588: 589: /* copy an event out of the keyboard buffer: */ 590: rc = tme_keyboard_buffer_copyout(display->tme_gtk_display_keyboard_buffer, 591: event); 592: 593: /* unlock the mutex: */ 594: tme_mutex_unlock(&display->tme_gtk_display_mutex); 595: 596: return (rc); 597: } 598: 599: /* this breaks a keyboard connection: */ 600: static int 601: _tme_gtk_keyboard_connection_break(struct tme_connection *conn, unsigned int state) 602: { 603: abort(); 604: } 605: 606: /* this makes a new keyboard connection: */ 607: static int 608: _tme_gtk_keyboard_connection_make(struct tme_connection *conn, 609: unsigned int state) 610: { 611: struct tme_gtk_display *display; 612: 613: /* recover our data structure: */ 614: display = conn->tme_connection_element->tme_element_private; 615: 616: /* both sides must be keyboard connections: */ 617: assert(conn->tme_connection_type 618: == TME_CONNECTION_KEYBOARD); 619: assert(conn->tme_connection_other->tme_connection_type 620: == TME_CONNECTION_KEYBOARD); 621: 622: /* we are always set up to answer calls across the connection, so we 623: only have to do work when the connection has gone full, namely 624: taking the other side of the connection: */ 625: if (state == TME_CONNECTION_FULL) { 626: 627: /* save our connection: */ 628: tme_mutex_lock(&display->tme_gtk_display_mutex); 629: display->tme_gtk_display_keyboard_connection 630: = (struct tme_keyboard_connection *) conn->tme_connection_other; 631: tme_mutex_unlock(&display->tme_gtk_display_mutex); 632: } 633: 634: return (TME_OK); 635: } 636: 637: /* this scores a keyboard connection: */ 638: static int 639: _tme_gtk_keyboard_connection_score(struct tme_connection *conn, 640: unsigned int *_score) 641: { 642: struct tme_keyboard_connection *conn_keyboard; 643: 644: /* both sides must be keyboard connections: */ 645: assert(conn->tme_connection_type == TME_CONNECTION_KEYBOARD); 646: assert(conn->tme_connection_other->tme_connection_type == TME_CONNECTION_KEYBOARD); 647: 648: /* the other side cannot be a real keyboard: */ 649: conn_keyboard 650: = (struct tme_keyboard_connection *) conn->tme_connection_other; 651: *_score = (conn_keyboard->tme_keyboard_connection_read == NULL 652: && conn_keyboard->tme_keyboard_connection_lookup == NULL); 653: return (TME_OK); 654: } 655: 656: /* this makes a new connection side for a GTK keyboard: */ 657: int 658: _tme_gtk_keyboard_connections_new(struct tme_gtk_display *display, 659: struct tme_connection **_conns) 660: { 661: struct tme_keyboard_connection *conn_keyboard; 662: struct tme_connection *conn; 663: 664: /* if we don't have a keyboard connection yet: */ 665: if (display->tme_gtk_display_keyboard_connection == NULL) { 666: 667: /* create our side of a keyboard connection: */ 668: conn_keyboard = tme_new0(struct tme_keyboard_connection, 1); 669: conn = &conn_keyboard->tme_keyboard_connection; 670: 671: /* fill in the generic connection: */ 672: conn->tme_connection_next = *_conns; 673: conn->tme_connection_type = TME_CONNECTION_KEYBOARD; 674: conn->tme_connection_score = _tme_gtk_keyboard_connection_score; 675: conn->tme_connection_make = _tme_gtk_keyboard_connection_make; 676: conn->tme_connection_break = _tme_gtk_keyboard_connection_break; 677: 678: /* fill in the keyboard connection: */ 679: conn_keyboard->tme_keyboard_connection_ctrl = _tme_gtk_keyboard_ctrl; 680: conn_keyboard->tme_keyboard_connection_read = _tme_gtk_keyboard_read; 681: conn_keyboard->tme_keyboard_connection_lookup = _tme_gtk_keyboard_lookup; 682: 683: /* return the connection side possibility: */ 684: *_conns = conn; 685: } 686: 687: /* done: */ 688: return (TME_OK); 689: } 690: 691: /* this attaches the GTK keyboard to a new screen: */ 692: void 693: _tme_gtk_keyboard_attach(struct tme_gtk_screen *screen) 694: { 695: 696: /* make sure the event box for the framebuffer gets enter, key_press 697: and key_release events. we have to add these latter two events 698: to both the event box widget itself, and the top-level window, 699: since GTK 1.x appears to not select KeyRelease events at the 700: top-level: */ 701: gtk_widget_add_events(screen->tme_gtk_screen_event_box, 702: GDK_ENTER_NOTIFY_MASK 703: | GDK_KEY_PRESS_MASK 704: | GDK_KEY_RELEASE_MASK); 705: gtk_widget_add_events (gtk_widget_get_toplevel(screen->tme_gtk_screen_event_box), 706: GDK_KEY_PRESS_MASK 707: | GDK_KEY_RELEASE_MASK); 708: 709: /* set a signal handler for these events: */ 710: gtk_signal_connect(GTK_OBJECT(screen->tme_gtk_screen_event_box), 711: "enter_notify_event", 712: GTK_SIGNAL_FUNC(_tme_gtk_display_enter_focus), 713: NULL); 1.1.1.2 root 714: gtk_signal_connect_after(GTK_OBJECT(screen->tme_gtk_screen_event_box), 715: "key_press_event", 716: GTK_SIGNAL_FUNC(_tme_gtk_keyboard_key_event), 717: screen); 718: gtk_signal_connect_after(GTK_OBJECT(screen->tme_gtk_screen_event_box), 719: "key_release_event", 720: GTK_SIGNAL_FUNC(_tme_gtk_keyboard_key_event), 721: screen); 1.1 root 722: 723: /* the event box can focus, and have it grab the focus now: */ 724: GTK_WIDGET_SET_FLAGS(screen->tme_gtk_screen_event_box, GTK_CAN_FOCUS); 725: gtk_widget_grab_focus(screen->tme_gtk_screen_event_box); 726: } 727: 728: /* this initializes keyboard part of the display: */ 729: void 730: _tme_gtk_keyboard_new(struct tme_gtk_display *display) 731: { 732: 733: /* we have no keyboard connection: */ 734: display->tme_gtk_display_keyboard_connection = NULL; 735: 736: /* allocate the keyboard buffer: */ 737: display->tme_gtk_display_keyboard_buffer 738: = tme_keyboard_buffer_new(1024); 739: display->tme_gtk_display_keyboard_buffer->tme_keyboard_buffer_log_handle 740: = &display->tme_gtk_display_element->tme_element_log_handle; 741: 742: /* allocate the keysyms hash: */ 743: display->tme_gtk_display_keyboard_keysyms 744: = tme_hash_new(tme_string_hash, 745: tme_string_compare, 746: (tme_hash_data_t) 0); 747: 748: /* allocate the keysym-to-keycode hash: */ 749: display->tme_gtk_display_keyboard_keysym_to_keycode 750: = tme_hash_new(tme_direct_hash, 751: tme_direct_compare, 752: (tme_hash_data_t) TME_KEYBOARD_KEYVAL_UNDEF); 753: 754: /* there are no bad keysyms: */ 755: display->tme_gtk_display_keyboard_keysyms_bad = NULL; 756: 757: /* initialize the input stages of the keyboard buffer. this needs 758: information that we can't get from GTK or GDK, like which keysyms 759: are attached to which modifiers, and which keysyms can be 760: generated by the keyboard: */ 761: #ifndef X_DISPLAY_MISSING 762: if (TRUE) { 763: _tme_gtk_keyboard_x11_new(display); 764: } 765: #endif /* !X_DISPLAY_MISSING */ 766: else { 767: abort(); 768: } 769: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.