Refine keysym handling.
This commit is contained in:
		@ -71,18 +71,14 @@ static void
 | 
				
			|||||||
on_context_destroyed (EekboardContext *context,
 | 
					on_context_destroyed (EekboardContext *context,
 | 
				
			||||||
                      gpointer         user_data)
 | 
					                      gpointer         user_data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    GMainLoop *loop = user_data;
 | 
					    gtk_main_quit ();
 | 
				
			||||||
 | 
					 | 
				
			||||||
    g_main_loop_quit (loop);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
on_destroyed (EekboardClient *eekboard,
 | 
					on_destroyed (EekboardClient *eekboard,
 | 
				
			||||||
              gpointer          user_data)
 | 
					              gpointer          user_data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    GMainLoop *loop = user_data;
 | 
					    gtk_main_quit ();
 | 
				
			||||||
 | 
					 | 
				
			||||||
    g_main_loop_quit (loop);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum FocusListenerType {
 | 
					enum FocusListenerType {
 | 
				
			||||||
@ -121,7 +117,6 @@ main (int argc, char **argv)
 | 
				
			|||||||
    GDBusConnection *connection;
 | 
					    GDBusConnection *connection;
 | 
				
			||||||
    GError *error;
 | 
					    GError *error;
 | 
				
			||||||
    GOptionContext *option_context;
 | 
					    GOptionContext *option_context;
 | 
				
			||||||
    GMainLoop *loop = NULL;
 | 
					 | 
				
			||||||
    gint focus;
 | 
					    gint focus;
 | 
				
			||||||
    GSettings *settings = NULL;
 | 
					    GSettings *settings = NULL;
 | 
				
			||||||
    gchar **keyboards = NULL;
 | 
					    gchar **keyboards = NULL;
 | 
				
			||||||
@ -283,12 +278,10 @@ main (int argc, char **argv)
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
#endif  /* HAVE_XTEST */
 | 
					#endif  /* HAVE_XTEST */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    loop = g_main_loop_new (NULL, FALSE);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (!opt_focus) {
 | 
					    if (!opt_focus) {
 | 
				
			||||||
        g_object_get (client, "context", &context, NULL);
 | 
					        g_object_get (client, "context", &context, NULL);
 | 
				
			||||||
        g_signal_connect (context, "destroyed",
 | 
					        g_signal_connect (context, "destroyed",
 | 
				
			||||||
                          G_CALLBACK(on_context_destroyed), loop);
 | 
					                          G_CALLBACK(on_context_destroyed), NULL);
 | 
				
			||||||
        g_object_unref (context);
 | 
					        g_object_unref (context);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -301,7 +294,7 @@ main (int argc, char **argv)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    g_object_get (client, "eekboard", &eekboard, NULL);
 | 
					    g_object_get (client, "eekboard", &eekboard, NULL);
 | 
				
			||||||
    g_signal_connect (eekboard, "destroyed",
 | 
					    g_signal_connect (eekboard, "destroyed",
 | 
				
			||||||
                      G_CALLBACK(on_destroyed), loop);
 | 
					                      G_CALLBACK(on_destroyed), NULL);
 | 
				
			||||||
    g_object_unref (eekboard);
 | 
					    g_object_unref (eekboard);
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    if (opt_keyboards != NULL) {
 | 
					    if (opt_keyboards != NULL) {
 | 
				
			||||||
@ -315,11 +308,9 @@ main (int argc, char **argv)
 | 
				
			|||||||
        g_strfreev (keyboards);
 | 
					        g_strfreev (keyboards);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    g_main_loop_run (loop);
 | 
					    gtk_main ();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 out:
 | 
					 out:
 | 
				
			||||||
    if (loop)
 | 
					 | 
				
			||||||
        g_main_loop_unref (loop);
 | 
					 | 
				
			||||||
    if (client)
 | 
					    if (client)
 | 
				
			||||||
        g_object_unref (client);
 | 
					        g_object_unref (client);
 | 
				
			||||||
    if (settings)
 | 
					    if (settings)
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										119
									
								
								src/client.c
									
									
									
									
									
								
							
							
						
						
									
										119
									
								
								src/client.c
									
									
									
									
									
								
							@ -92,8 +92,6 @@ struct _Client {
 | 
				
			|||||||
#ifdef HAVE_XTEST
 | 
					#ifdef HAVE_XTEST
 | 
				
			||||||
    guint modifier_keycodes[8]; 
 | 
					    guint modifier_keycodes[8]; 
 | 
				
			||||||
    XkbDescRec *xkb;
 | 
					    XkbDescRec *xkb;
 | 
				
			||||||
    GSList *replaced_keycodes;
 | 
					 | 
				
			||||||
    gulong reset_replaced_keycodes_timeout_handler;
 | 
					 | 
				
			||||||
#endif  /* HAVE_XTEST */
 | 
					#endif  /* HAVE_XTEST */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    GSettings *settings;
 | 
					    GSettings *settings;
 | 
				
			||||||
@ -837,19 +835,6 @@ on_xkl_state_changed (XklEngine           *xklengine,
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef HAVE_XTEST
 | 
					#ifdef HAVE_XTEST
 | 
				
			||||||
struct _KeycodeReplacement {
 | 
					 | 
				
			||||||
    guint keycode;
 | 
					 | 
				
			||||||
    guint new_keysym;
 | 
					 | 
				
			||||||
    guint old_keysym;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
typedef struct _KeycodeReplacement KeycodeReplacement;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
keycode_replacement_free (KeycodeReplacement *replacement)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    g_slice_free (KeycodeReplacement, replacement);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* The following functions for keyboard mapping change are direct
 | 
					/* The following functions for keyboard mapping change are direct
 | 
				
			||||||
   translation of the code in Caribou (in libcaribou/xadapter.vala):
 | 
					   translation of the code in Caribou (in libcaribou/xadapter.vala):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -868,13 +853,6 @@ get_replaced_keycode (Client *client)
 | 
				
			|||||||
        guint offset = client->xkb->map->key_sym_map[keycode].offset;
 | 
					        guint offset = client->xkb->map->key_sym_map[keycode].offset;
 | 
				
			||||||
        if (client->xkb->map->key_sym_map[keycode].kt_index[0] == XkbOneLevelIndex &&
 | 
					        if (client->xkb->map->key_sym_map[keycode].kt_index[0] == XkbOneLevelIndex &&
 | 
				
			||||||
            client->xkb->map->syms[offset] != NoSymbol) {
 | 
					            client->xkb->map->syms[offset] != NoSymbol) {
 | 
				
			||||||
            GSList *head;
 | 
					 | 
				
			||||||
            for (head = client->replaced_keycodes; head; head = head->next) {
 | 
					 | 
				
			||||||
                KeycodeReplacement *replacement = head->data;
 | 
					 | 
				
			||||||
                if (replacement->keycode == keycode)
 | 
					 | 
				
			||||||
                    break;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            if (head == NULL)
 | 
					 | 
				
			||||||
            return keycode;
 | 
					            return keycode;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -896,26 +874,21 @@ replace_keycode (Client *client,
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    GdkDisplay *display = gdk_display_get_default ();
 | 
					    GdkDisplay *display = gdk_display_get_default ();
 | 
				
			||||||
    Display *xdisplay = GDK_DISPLAY_XDISPLAY (display);
 | 
					    Display *xdisplay = GDK_DISPLAY_XDISPLAY (display);
 | 
				
			||||||
    guint offset;
 | 
					 | 
				
			||||||
    XkbMapChangesRec changes;
 | 
					 | 
				
			||||||
    guint old_keysym;
 | 
					    guint old_keysym;
 | 
				
			||||||
 | 
					    int keysyms_per_keycode;
 | 
				
			||||||
 | 
					    KeySym *syms;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    g_return_val_if_fail (client->xkb->min_key_code <= keycode &&
 | 
					    g_return_val_if_fail (client->xkb->min_key_code <= keycode &&
 | 
				
			||||||
                          client->xkb->max_key_code,
 | 
					                          keycode <= client->xkb->max_key_code,
 | 
				
			||||||
                          FALSE);
 | 
					                          FALSE);
 | 
				
			||||||
    g_return_val_if_fail (keysym != NULL, FALSE);
 | 
					    g_return_val_if_fail (keysym != NULL, FALSE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    offset = client->xkb->map->key_sym_map[keycode].offset;
 | 
					    syms = XGetKeyboardMapping (xdisplay, keycode, 1, &keysyms_per_keycode);
 | 
				
			||||||
    old_keysym = client->xkb->map->syms[offset];
 | 
					    old_keysym = syms[0];
 | 
				
			||||||
    client->xkb->map->syms[offset] = *keysym;
 | 
					    syms[0] = *keysym;
 | 
				
			||||||
 | 
					    XChangeKeyboardMapping (xdisplay, keycode, 1, syms, 1);
 | 
				
			||||||
    changes.changed = XkbKeySymsMask;
 | 
					 | 
				
			||||||
    changes.first_key_sym = keycode;
 | 
					 | 
				
			||||||
    changes.num_key_syms = 1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    XkbChangeMap (xdisplay, client->xkb, &changes);
 | 
					 | 
				
			||||||
    XSync (xdisplay, False);
 | 
					    XSync (xdisplay, False);
 | 
				
			||||||
 | 
					    XFree (syms);
 | 
				
			||||||
    *keysym = old_keysym;
 | 
					    *keysym = old_keysym;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return TRUE;
 | 
					    return TRUE;
 | 
				
			||||||
@ -956,6 +929,7 @@ send_fake_modifier_key_event (Client         *client,
 | 
				
			|||||||
                              gboolean        is_pressed)
 | 
					                              gboolean        is_pressed)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    GdkDisplay *display = gdk_display_get_default ();
 | 
					    GdkDisplay *display = gdk_display_get_default ();
 | 
				
			||||||
 | 
					    Display *xdisplay = GDK_DISPLAY_XDISPLAY (display);
 | 
				
			||||||
    gint i;
 | 
					    gint i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (i = 0; i < G_N_ELEMENTS(client->modifier_keycodes); i++) {
 | 
					    for (i = 0; i < G_N_ELEMENTS(client->modifier_keycodes); i++) {
 | 
				
			||||||
@ -964,80 +938,40 @@ send_fake_modifier_key_event (Client         *client,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            g_return_if_fail (keycode > 0);
 | 
					            g_return_if_fail (keycode > 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            XTestFakeKeyEvent (GDK_DISPLAY_XDISPLAY (display),
 | 
					            XTestFakeKeyEvent (xdisplay,
 | 
				
			||||||
                               keycode,
 | 
					                               keycode,
 | 
				
			||||||
                               is_pressed,
 | 
					                               is_pressed,
 | 
				
			||||||
                               CurrentTime);
 | 
					                               CurrentTime);
 | 
				
			||||||
 | 
					            XSync (xdisplay, False);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static gboolean
 | 
					 | 
				
			||||||
reset_replaced_keycodes (gpointer data)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    Client *client = data;
 | 
					 | 
				
			||||||
    GSList *head;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for (head = client->replaced_keycodes; head; head = head->next) {
 | 
					 | 
				
			||||||
        KeycodeReplacement *replacement = head->data;
 | 
					 | 
				
			||||||
        guint keysym = replacement->old_keysym;
 | 
					 | 
				
			||||||
        replace_keycode (client, replacement->keycode, &keysym);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    g_slist_free_full (client->replaced_keycodes,
 | 
					 | 
				
			||||||
                       (GDestroyNotify) keycode_replacement_free);
 | 
					 | 
				
			||||||
    client->replaced_keycodes = NULL;
 | 
					 | 
				
			||||||
    client->reset_replaced_keycodes_timeout_handler = 0;
 | 
					 | 
				
			||||||
    return FALSE;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
send_fake_key_event (Client  *client,
 | 
					send_fake_key_event (Client  *client,
 | 
				
			||||||
                     guint    xkeysym,
 | 
					                     guint    xkeysym,
 | 
				
			||||||
                     guint    keyboard_modifiers,
 | 
					                     guint    keyboard_modifiers)
 | 
				
			||||||
                     gboolean is_pressed)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    GdkDisplay *display = gdk_display_get_default ();
 | 
					    GdkDisplay *display = gdk_display_get_default ();
 | 
				
			||||||
    Display *xdisplay = GDK_DISPLAY_XDISPLAY (display);
 | 
					    Display *xdisplay = GDK_DISPLAY_XDISPLAY (display);
 | 
				
			||||||
    EekModifierType modifiers;
 | 
					    EekModifierType modifiers;
 | 
				
			||||||
    guint keycode;
 | 
					    guint keycode;
 | 
				
			||||||
    guint old_keysym = 0;
 | 
					    guint old_keysym = xkeysym;
 | 
				
			||||||
    GSList *head;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    g_return_if_fail (xkeysym > 0);
 | 
					    g_return_if_fail (xkeysym > 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    keycode = 0;
 | 
					 | 
				
			||||||
    for (head = client->replaced_keycodes; head; head = head->next) {
 | 
					 | 
				
			||||||
        KeycodeReplacement *replacement = head->data;
 | 
					 | 
				
			||||||
        if (replacement->new_keysym == xkeysym) {
 | 
					 | 
				
			||||||
            keycode = replacement->keycode;
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    modifiers = 0;
 | 
					    modifiers = 0;
 | 
				
			||||||
    if (keycode == 0) {
 | 
					 | 
				
			||||||
    if (!get_keycode_from_gdk_keymap (client, xkeysym, &keycode, &modifiers)) {
 | 
					    if (!get_keycode_from_gdk_keymap (client, xkeysym, &keycode, &modifiers)) {
 | 
				
			||||||
            KeycodeReplacement *replacement;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        keycode = get_replaced_keycode (client);
 | 
					        keycode = get_replaced_keycode (client);
 | 
				
			||||||
        if (keycode == 0) {
 | 
					        if (keycode == 0) {
 | 
				
			||||||
            g_warning ("no available keycode to replace");
 | 
					            g_warning ("no available keycode to replace");
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            old_keysym = xkeysym;
 | 
					 | 
				
			||||||
        if (!replace_keycode (client, keycode, &old_keysym)) {
 | 
					        if (!replace_keycode (client, keycode, &old_keysym)) {
 | 
				
			||||||
            g_warning ("failed to lookup X keysym %X", xkeysym);
 | 
					            g_warning ("failed to lookup X keysym %X", xkeysym);
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					 | 
				
			||||||
            replacement = g_slice_new0 (KeycodeReplacement);
 | 
					 | 
				
			||||||
            replacement->keycode = keycode;
 | 
					 | 
				
			||||||
            replacement->new_keysym = xkeysym;
 | 
					 | 
				
			||||||
            replacement->old_keysym = old_keysym;
 | 
					 | 
				
			||||||
            client->replaced_keycodes =
 | 
					 | 
				
			||||||
                g_slist_prepend (client->replaced_keycodes, replacement);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Clear level shift modifiers */
 | 
					    /* Clear level shift modifiers */
 | 
				
			||||||
@ -1052,18 +986,15 @@ send_fake_key_event (Client  *client,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    modifiers |= keyboard_modifiers;
 | 
					    modifiers |= keyboard_modifiers;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    send_fake_modifier_key_event (client, modifiers, is_pressed);
 | 
					    send_fake_modifier_key_event (client, modifiers, TRUE);
 | 
				
			||||||
    XTestFakeKeyEvent (xdisplay, keycode, is_pressed, CurrentTime);
 | 
					    XTestFakeKeyEvent (xdisplay, keycode, TRUE, 20);
 | 
				
			||||||
 | 
					    XSync (xdisplay, False);
 | 
				
			||||||
 | 
					    XTestFakeKeyEvent (xdisplay, keycode, FALSE, 20);
 | 
				
			||||||
 | 
					    XSync (xdisplay, False);
 | 
				
			||||||
 | 
					    send_fake_modifier_key_event (client, modifiers, FALSE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (client->reset_replaced_keycodes_timeout_handler == 0 &&
 | 
					    if (old_keysym != xkeysym)
 | 
				
			||||||
        old_keysym != 0) {
 | 
					        replace_keycode (client, keycode, &old_keysym);
 | 
				
			||||||
        /* Queue a timer to restore the old keycode.  Ugly, but
 | 
					 | 
				
			||||||
         * required due to races / asynchronous X delivery.  Long-term
 | 
					 | 
				
			||||||
         * fix is to extend the X keymap here instead of replace
 | 
					 | 
				
			||||||
         * entries. */
 | 
					 | 
				
			||||||
        client->reset_replaced_keycodes_timeout_handler =
 | 
					 | 
				
			||||||
            g_timeout_add (500, reset_replaced_keycodes, client);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
@ -1102,8 +1033,7 @@ send_fake_key_events (Client    *client,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    if (EEK_IS_KEYSYM(symbol)) {
 | 
					    if (EEK_IS_KEYSYM(symbol)) {
 | 
				
			||||||
        guint xkeysym = eek_keysym_get_xkeysym (EEK_KEYSYM(symbol));
 | 
					        guint xkeysym = eek_keysym_get_xkeysym (EEK_KEYSYM(symbol));
 | 
				
			||||||
        send_fake_key_event (client, xkeysym, keyboard_modifiers, TRUE);
 | 
					        send_fake_key_event (client, xkeysym, keyboard_modifiers);
 | 
				
			||||||
        send_fake_key_event (client, xkeysym, keyboard_modifiers, FALSE);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1210,10 +1140,5 @@ client_disable_xtest (Client *client)
 | 
				
			|||||||
        XkbFreeKeyboard (client->xkb, 0, TRUE);	/* free_all = TRUE */
 | 
					        XkbFreeKeyboard (client->xkb, 0, TRUE);	/* free_all = TRUE */
 | 
				
			||||||
        client->xkb = NULL;
 | 
					        client->xkb = NULL;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (client->replaced_keycodes) {
 | 
					 | 
				
			||||||
        g_slist_free_full (client->replaced_keycodes,
 | 
					 | 
				
			||||||
                           (GDestroyNotify) keycode_replacement_free);
 | 
					 | 
				
			||||||
        client->replaced_keycodes = NULL;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif  /* HAVE_XTEST */
 | 
					#endif  /* HAVE_XTEST */
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user