From 30faa38aec228c0b20c665f409b09447f801bcdd Mon Sep 17 00:00:00 2001 From: Owen Taylor Date: Fri, 18 Oct 2002 19:26:43 +0000 Subject: Fix use of uninitialized variable. Thu Oct 17 17:17:05 2002 Owen Taylor * gtk/gtkcheckbutton.c (gtk_check_button_size_request): Fix use of uninitialized variable. Thu Oct 17 14:38:37 2002 Owen Taylor * gtk/gtkaccellabel.c (gtk_accel_label_expose_event): Align the baseline of the accelerator label with the first baseline of the main label of the menu item. (#76593) Wed Oct 16 18:25:24 2002 Owen Taylor * gdk/x11/gdkevents-x11.c (translate_key_event): Use gdk_keymap_translate_keyboard_state() rather than XLookupString() to get the keysymbol, since XLookupString can confuse the input method handling. (#93575) * gdk/x11/gdkkeys-x11.c: Rewrite the handling of key translation for the non-XKB case to properly handle Shift_Lock, Caps_Lock, Num_Lock according to the Xlib spec. (#67066) --- gdk/x11/gdkevents-x11.c | 165 +++++++++++++++++++++++++------------------ gdk/x11/gdkkeys-x11.c | 184 +++++++++++++++++++++++++++++++----------------- 2 files changed, 216 insertions(+), 133 deletions(-) (limited to 'gdk') diff --git a/gdk/x11/gdkevents-x11.c b/gdk/x11/gdkevents-x11.c index e8bedf9e3..c1a44b94b 100644 --- a/gdk/x11/gdkevents-x11.c +++ b/gdk/x11/gdkevents-x11.c @@ -512,6 +512,94 @@ set_screen_from_root (GdkDisplay *display, gdk_event_set_screen (event, screen); } +static void +translate_key_event (GdkDisplay *display, + GdkEvent *event, + XEvent *xevent) +{ + GdkKeymap *keymap = gdk_keymap_get_for_display (display); + gunichar c = 0; + guchar buf[7]; + + event->key.type = xevent->xany.type == KeyPress ? GDK_KEY_PRESS : GDK_KEY_RELEASE; + event->key.time = xevent->xkey.time; + + event->key.state = (GdkModifierType) xevent->xkey.state; + event->key.group = _gdk_x11_get_group_for_state (display, xevent->xkey.state); + event->key.hardware_keycode = xevent->xkey.keycode; + + event->key.keyval = GDK_VoidSymbol; + + gdk_keymap_translate_keyboard_state (keymap, + event->key.hardware_keycode, + event->key.state, + event->key.group, + &event->key.keyval, + NULL, NULL, NULL); + + /* Fill in event->string crudely, since various programs + * depend on it. + */ + event->key.string = NULL; + + if (event->key.keyval != GDK_VoidSymbol) + c = gdk_keyval_to_unicode (event->key.keyval); + + if (c) + { + gsize bytes_written; + gint len; + + /* Apply the control key - Taken from Xlib + */ + if (event->key.state & GDK_CONTROL_MASK) + { + if ((c >= '@' && c < '\177') || c == ' ') c &= 0x1F; + else if (c == '2') + { + event->key.string = g_memdup ("\0\0", 2); + event->key.length = 1; + buf[0] = '\0'; + goto out; + } + else if (c >= '3' && c <= '7') c -= ('3' - '\033'); + else if (c == '8') c = '\177'; + else if (c == '/') c = '_' & 0x1F; + } + + len = g_unichar_to_utf8 (c, buf); + buf[len] = '\0'; + + event->key.string = g_locale_from_utf8 (buf, len, + NULL, &bytes_written, + NULL); + if (event->key.string) + event->key.length = bytes_written; + } + + if (!event->key.string) + { + event->key.length = 0; + event->key.string = g_strdup (""); + } + + out: +#ifdef G_ENABLE_DEBUG + if (_gdk_debug_flags & GDK_DEBUG_EVENTS) + { + g_message ("%s:\t\twindow: %ld key: %12s %d", + event->type == GDK_KEY_PRESS ? "key press " : "key release", + xevent->xkey.window, + event->key.keyval ? gdk_keyval_name (event->key.keyval) : "(none)", + event->key.keyval); + + if (event->key.length > 0) + g_message ("\t\tlength: %4d string: \"%s\"", + event->key.length, buf); + } +#endif /* G_ENABLE_DEBUG */ +} + /* Return the window this has to do with, if any, rather * than the frame or root window that was selecting * for substructure @@ -569,10 +657,6 @@ gdk_event_translate (GdkDisplay *display, GdkWindow *window; GdkWindowObject *window_private; GdkWindowImplX11 *window_impl = NULL; - static XComposeStatus compose; - KeySym keysym; - int charcount; - char buf[16]; gint return_val; gint xoffset, yoffset; GdkScreen *screen = NULL; @@ -750,48 +834,9 @@ gdk_event_translate (GdkDisplay *display, return_val = FALSE; break; } - - /* Lookup the string corresponding to the given keysym. - */ - - charcount = XLookupString (&xevent->xkey, buf, 16, - &keysym, &compose); - event->key.keyval = keysym; - event->key.hardware_keycode = xevent->xkey.keycode; - - if (charcount > 0 && buf[charcount-1] == '\0') - charcount --; - else - buf[charcount] = '\0'; - -#ifdef G_ENABLE_DEBUG - if (_gdk_debug_flags & GDK_DEBUG_EVENTS) - { - g_message ("key press:\twindow: %ld key: %12s %d", - xevent->xkey.window, - event->key.keyval ? XKeysymToString (event->key.keyval) : "(none)", - event->key.keyval); - if (charcount > 0) - g_message ("\t\tlength: %4d string: \"%s\"", - charcount, buf); - } -#endif /* G_ENABLE_DEBUG */ - - event->key.type = GDK_KEY_PRESS; - event->key.window = window; - event->key.time = xevent->xkey.time; - event->key.state = (GdkModifierType) xevent->xkey.state; - event->key.string = g_strdup (buf); - event->key.length = charcount; - - /* bits 13 and 14 in the "state" field are the keyboard group */ -#define KEYBOARD_GROUP_SHIFT 13 -#define KEYBOARD_GROUP_MASK ((1 << 13) | (1 << 14)) - - event->key.group = _gdk_x11_get_group_for_state (display, xevent->xkey.state); - + translate_key_event (display, event, xevent); break; - + case KeyRelease: if (window_private == NULL) { @@ -799,9 +844,6 @@ gdk_event_translate (GdkDisplay *display, break; } - /* Lookup the string corresponding to the given keysym. - */ - /* Emulate detectable auto-repeat by checking to see * if the next event is a key press with the same * keycode and timestamp, and if so, ignoring the event. @@ -816,30 +858,13 @@ gdk_event_translate (GdkDisplay *display, if (next_event.type == KeyPress && next_event.xkey.keycode == xevent->xkey.keycode && next_event.xkey.time == xevent->xkey.time) - break; + { + return_val = FALSE; + break; + } } - - keysym = GDK_VoidSymbol; - charcount = XLookupString (&xevent->xkey, buf, 16, - &keysym, &compose); - event->key.keyval = keysym; - event->key.hardware_keycode = xevent->xkey.keycode; - - GDK_NOTE (EVENTS, - g_message ("key release:\t\twindow: %ld key: %12s %d", - xevent->xkey.window, - XKeysymToString (event->key.keyval), - event->key.keyval)); - - event->key.type = GDK_KEY_RELEASE; - event->key.window = window; - event->key.time = xevent->xkey.time; - event->key.state = (GdkModifierType) xevent->xkey.state; - event->key.length = 0; - event->key.string = NULL; - - event->key.group = (xevent->xkey.state & KEYBOARD_GROUP_MASK) >> KEYBOARD_GROUP_SHIFT; + translate_key_event (display, event, xevent); break; case ButtonPress: diff --git a/gdk/x11/gdkkeys-x11.c b/gdk/x11/gdkkeys-x11.c index cafc03b2b..21cc28fa3 100644 --- a/gdk/x11/gdkkeys-x11.c +++ b/gdk/x11/gdkkeys-x11.c @@ -67,7 +67,9 @@ struct _GdkKeymapX11 KeySym* keymap; gint keysyms_per_keycode; XModifierKeymap* mod_keymap; + guint lock_keysym; GdkModifierType group_switch_mask; + GdkModifierType num_lock_mask; PangoDirection current_direction; gboolean have_direction; guint current_serial; @@ -121,7 +123,9 @@ gdk_keymap_x11_init (GdkKeymapX11 *keymap) keymap->keysyms_per_keycode = 0; keymap->mod_keymap = NULL; + keymap->num_lock_mask = 0; keymap->group_switch_mask = 0; + keymap->lock_keysym = GDK_Caps_Lock; keymap->have_direction = FALSE; #ifdef HAVE_XKB @@ -201,6 +205,8 @@ gdk_keymap_get_for_display (GdkDisplay *display) */ #define KEYSYM_INDEX(keymap_impl, group, level) \ (2 * ((group) % (keymap_impl->keysyms_per_keycode / 2)) + (level)) +#define KEYSYM_IS_KEYPAD(s) (((s) >= 0xff80 && (s) <= 0xffbd) || \ + ((s) >= 0x11000000 && (s) <= 0x1100ffff)) static void update_keymaps (GdkKeymapX11 *keymap_x11) @@ -273,8 +279,9 @@ update_keymaps (GdkKeymapX11 *keymap_x11) keymap_x11->mod_keymap = XGetModifierMapping (xdisplay); - + keymap_x11->lock_keysym = GDK_VoidSymbol; keymap_x11->group_switch_mask = 0; + keymap_x11->num_lock_mask = 0; /* there are 8 modifiers, and the first 3 are shift, shift lock, * and control @@ -292,7 +299,7 @@ update_keymaps (GdkKeymapX11 *keymap_x11) if (keycode >= keymap_x11->min_keycode && keycode <= keymap_x11->max_keycode) { - gint j = 0; + gint j; KeySym *syms = keymap_x11->keymap + (keycode - keymap_x11->min_keycode) * keymap_x11->keysyms_per_keycode; /* GDK_MOD1_MASK is 1 << 3 for example, i.e. the * fourth modifier, i / keyspermod is the modifier @@ -300,6 +307,17 @@ update_keymaps (GdkKeymapX11 *keymap_x11) */ guint mask = 1 << ( i / keymap_x11->mod_keymap->max_keypermod); + if (mask == GDK_LOCK_MASK) + { + for (j = 0; j < keymap_x11->keysyms_per_keycode; j++) + { + if (syms[j] == GDK_Caps_Lock) + keymap_x11->lock_keysym = syms[j]; + else if (syms[j] == GDK_Shift_Lock && keymap_x11->lock_keysym == GDK_VoidSymbol) + keymap_x11->lock_keysym = syms[j]; + } + } + /* Some keyboard maps are known to map Mode_Switch as an extra * Mod1 key. In circumstances like that, it won't be used to * switch groups. @@ -308,17 +326,20 @@ update_keymaps (GdkKeymapX11 *keymap_x11) mask == GDK_LOCK_MASK || mask == GDK_MOD1_MASK) goto next; - while (j < keymap_x11->keysyms_per_keycode) + for (j = 0; j < keymap_x11->keysyms_per_keycode; j++) { if (syms[j] == GDK_Mode_switch) { /* This modifier swaps groups */ keymap_x11->group_switch_mask |= mask; - break; } - - ++j; + if (syms[j] == GDK_Num_Lock) + { + /* This modifier swaps groups */ + + keymap_x11->num_lock_mask |= mask; + } } } @@ -927,6 +948,75 @@ MyEnhancedXkbTranslateKeyCode(register XkbDescPtr xkb, } #endif /* HAVE_XKB */ +/* Translates from keycode/state to keysymbol using the traditional interpretation + * of the keyboard map. See section 12.7 of the Xlib reference manual + */ +static guint +translate_keysym (GdkKeymapX11 *keymap_x11, + guint hardware_keycode, + gint group, + GdkModifierType state, + guint *effective_group, + guint *effective_level) +{ + const KeySym *map = get_keymap (keymap_x11); + const KeySym *syms = map + (hardware_keycode - keymap_x11->min_keycode) * keymap_x11->keysyms_per_keycode; + +#define SYM(k,g,l) syms[KEYSYM_INDEX (k,g,l)] + + GdkModifierType shift_modifiers; + gint shift_level; + guint tmp_keyval; + + shift_modifiers = GDK_SHIFT_MASK; + if (keymap_x11->lock_keysym == GDK_Shift_Lock) + shift_modifiers |= GDK_LOCK_MASK; + + /* Fall back to the first group if the passed in group is empty + */ + if (!(SYM (keymap_x11, group, 0) || SYM (keymap_x11, group, 1)) && + (SYM (keymap_x11, 0, 0) || SYM (keymap_x11, 0, 1))) + group = 0; + + if ((state & GDK_SHIFT_MASK) != 0 && + KEYSYM_IS_KEYPAD (SYM (keymap_x11, group, 1))) + { + /* Shift, Shift_Lock cancel Num_Lock + */ + shift_level = (state & shift_modifiers) ? 0 : 1; + + tmp_keyval = SYM (keymap_x11, group, shift_level); + } + else + { + /* Fall back to the the first level if no symbol for the level + * we were passed. + */ + shift_level = (state & shift_modifiers) ? 1 : 0; + if (!SYM (keymap_x11, group, shift_level) && SYM (keymap_x11, group, 0)) + shift_level = 0; + + tmp_keyval = SYM (keymap_x11, group, shift_level); + + if (keymap_x11->lock_keysym == GDK_Caps_Lock && (state & GDK_SHIFT_MASK) != 0) + { + guint upper = gdk_keyval_to_upper (tmp_keyval); + if (upper != tmp_keyval) + tmp_keyval = upper; + } + } + + if (effective_group) + *effective_group = group; + + if (effective_level) + *effective_level = shift_level; + + return tmp_keyval; + +#undef SYM +} + /** * gdk_keymap_translate_keyboard_state: * @keymap: a #GdkKeymap, or %NULL to use the default @@ -1013,68 +1103,36 @@ gdk_keymap_translate_keyboard_state (GdkKeymap *keymap, else #endif { - const KeySym *map = get_keymap (keymap_x11); - const KeySym *syms; - gint shift_level; - gboolean ignore_shift = FALSE; - gboolean ignore_group = FALSE; + GdkModifierType bit; - if ((state & GDK_SHIFT_MASK) && - (state & GDK_LOCK_MASK)) - shift_level = 0; /* shift disables shift lock */ - else if ((state & GDK_SHIFT_MASK) || - (state & GDK_LOCK_MASK)) - shift_level = 1; - else - shift_level = 0; - - syms = map + (hardware_keycode - keymap_x11->min_keycode) * keymap_x11->keysyms_per_keycode; - -#define SYM(k,g,l) syms[KEYSYM_INDEX (k,g,l)] + tmp_modifiers = 0; - /* Drop group and shift if there are no keysymbols on - * the specified key. + /* We see what modifiers matter by trying the translation with + * and without each possible modifier */ - if (!SYM (keymap_x11, group, shift_level) && SYM (keymap_x11, group, 0)) - { - shift_level = 0; - ignore_shift = TRUE; - } - if (!SYM (keymap_x11, group, shift_level) && SYM (keymap_x11, 0, shift_level)) + for (bit = GDK_SHIFT_MASK; bit < GDK_BUTTON1_MASK; bit <<= 1) { - group = 0; - ignore_group = TRUE; + /* Handling of the group here is a bit funky; a traditional + * X keyboard map can have more than two groups, but no way + * of accessing the extra groups is defined. We allow a + * caller to pass in any group to this function, but we + * only can represent switching between group 0 and 1 in + * consumed modifiers. + */ + if (translate_keysym (keymap_x11, hardware_keycode, + (bit == keymap_x11->group_switch_mask) ? 0 : group, + state & ~bit, + NULL, NULL) != + translate_keysym (keymap_x11, hardware_keycode, + (bit == keymap_x11->group_switch_mask) ? 1 : group, + state | bit, + NULL, NULL)) + tmp_modifiers |= bit; } - if (!SYM (keymap_x11, group, shift_level) && SYM (keymap_x11, 0, 0)) - { - shift_level = 0; - group = 0; - ignore_group = TRUE; - ignore_shift = TRUE; - } - - /* See whether the group and shift level actually mattered - * to know what to put in consumed_modifiers - */ - if (!SYM (keymap_x11, group, 1) || - SYM (keymap_x11, group, 0) == SYM (keymap_x11, group, 1)) - ignore_shift = TRUE; - - if (!SYM (keymap_x11, 1, shift_level) || - SYM (keymap_x11, 0, shift_level) == SYM (keymap_x11, 1, shift_level)) - ignore_group = TRUE; - - tmp_keyval = SYM (keymap_x11, group, shift_level); - - tmp_modifiers = ignore_group ? 0 : keymap_x11->group_switch_mask; - tmp_modifiers |= ignore_shift ? 0 : (GDK_SHIFT_MASK | GDK_LOCK_MASK); - - if (effective_group) - *effective_group = group; - - if (level) - *level = shift_level; -#undef SYM + + tmp_keyval = translate_keysym (keymap_x11, hardware_keycode, + group, state, + level, effective_group); } if (consumed_modifiers) -- cgit v1.2.1