Blame src/tests/ibus-keypress.c

Packit Service 1d8f1c
#include <gtk/gtk.h>
Packit Service 1d8f1c
#include <gdk/gdkx.h>
Packit Service 1d8f1c
#include "ibus.h"
Packit Service 1d8f1c
#include <stdlib.h>
Packit Service 1d8f1c
#include <X11/Xlib.h>
Packit Service 1d8f1c
#include <X11/extensions/XTest.h>
Packit Service 1d8f1c
Packit Service 1d8f1c
#define GREEN "\033[0;32m"
Packit Service 1d8f1c
#define RED   "\033[0;31m"
Packit Service 1d8f1c
#define NC    "\033[0m"
Packit Service 1d8f1c
Packit Service 1d8f1c
typedef struct _KeyData {
Packit Service 1d8f1c
    guint keyval;
Packit Service 1d8f1c
    guint modifiers;
Packit Service 1d8f1c
} KeyData;
Packit Service 1d8f1c
Packit Service 1d8f1c
static const KeyData test_cases[][30] = {
Packit Service 1d8f1c
   { { IBUS_KEY_a, 0 }, { IBUS_KEY_comma, IBUS_SHIFT_MASK },
Packit Service 1d8f1c
     { IBUS_KEY_b, 0 }, { IBUS_KEY_period, IBUS_SHIFT_MASK },
Packit Service 1d8f1c
     { IBUS_KEY_c, 0 }, { IBUS_KEY_slash, IBUS_SHIFT_MASK },
Packit Service 1d8f1c
     { IBUS_KEY_d, 0 }, { IBUS_KEY_semicolon, IBUS_SHIFT_MASK },
Packit Service 1d8f1c
     { IBUS_KEY_e, 0 }, { IBUS_KEY_apostrophe, IBUS_SHIFT_MASK },
Packit Service 1d8f1c
     { IBUS_KEY_f, 0 }, { IBUS_KEY_bracketleft, IBUS_SHIFT_MASK },
Packit Service 1d8f1c
     { IBUS_KEY_g, 0 }, { IBUS_KEY_backslash, IBUS_SHIFT_MASK },
Packit Service 1d8f1c
     { 0, 0 } },
Packit Service 1d8f1c
   { { IBUS_KEY_grave, IBUS_SHIFT_MASK }, { IBUS_KEY_a, IBUS_SHIFT_MASK },
Packit Service 1d8f1c
     { IBUS_KEY_1, IBUS_SHIFT_MASK }, { IBUS_KEY_b, IBUS_SHIFT_MASK  },
Packit Service 1d8f1c
     { IBUS_KEY_2, IBUS_SHIFT_MASK }, { IBUS_KEY_c, IBUS_SHIFT_MASK  },
Packit Service 1d8f1c
     { IBUS_KEY_3, IBUS_SHIFT_MASK }, { IBUS_KEY_d, IBUS_SHIFT_MASK },
Packit Service 1d8f1c
     { IBUS_KEY_9, IBUS_SHIFT_MASK }, { IBUS_KEY_e, IBUS_SHIFT_MASK },
Packit Service 1d8f1c
     { IBUS_KEY_0, IBUS_SHIFT_MASK }, { IBUS_KEY_f, IBUS_SHIFT_MASK },
Packit Service 1d8f1c
     { IBUS_KEY_equal, IBUS_SHIFT_MASK }, { IBUS_KEY_g, IBUS_SHIFT_MASK },
Packit Service 1d8f1c
     { 0, 0 } },
Packit Service 1d8f1c
   { { 0, 0 } }
Packit Service 1d8f1c
};
Packit Service 1d8f1c
Packit Service 1d8f1c
KeyData test_end_key = { IBUS_KEY_z, IBUS_SHIFT_MASK };
Packit Service 1d8f1c
Packit Service 1d8f1c
static const gunichar test_results[][60] = {
Packit Service 1d8f1c
   { 'a', '<', 'b', '>', 'c', '?', 'd', ':', 'e', '"', 'f', '{', 'g', '|', 0 },
Packit Service 1d8f1c
   { '~', 'A', '!', 'B', '@', 'C', '#', 'D', '(', 'E', ')', 'F', '+', 'G', 0 },
Packit Service 1d8f1c
   { 0 }
Packit Service 1d8f1c
};
Packit Service 1d8f1c
Packit Service 1d8f1c
Packit Service 1d8f1c
IBusBus *m_bus;
Packit Service 1d8f1c
IBusEngine *m_engine;
Packit Service 1d8f1c
Packit Service 1d8f1c
static gboolean window_focus_in_event_cb (GtkWidget     *entry,
Packit Service 1d8f1c
                                          GdkEventFocus *event,
Packit Service 1d8f1c
                                          gpointer       data);
Packit Service 1d8f1c
Packit Service 1d8f1c
static IBusEngine *
Packit Service 1d8f1c
create_engine_cb (IBusFactory *factory, const gchar *name, gpointer data)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    static int i = 1;
Packit Service 1d8f1c
    gchar *engine_path =
Packit Service 1d8f1c
            g_strdup_printf ("/org/freedesktop/IBus/engine/simpletest/%d",
Packit Service 1d8f1c
                             i++);
Packit Service 1d8f1c
Packit Service 1d8f1c
    m_engine = ibus_engine_new_with_type (IBUS_TYPE_ENGINE_SIMPLE,
Packit Service 1d8f1c
                                          name,
Packit Service 1d8f1c
                                          engine_path,
Packit Service 1d8f1c
                                          ibus_bus_get_connection (m_bus));
Packit Service 1d8f1c
    g_free (engine_path);
Packit Service 1d8f1c
    return m_engine;
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static gboolean
Packit Service 1d8f1c
register_ibus_engine ()
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    IBusFactory *factory;
Packit Service 1d8f1c
    IBusComponent *component;
Packit Service 1d8f1c
    IBusEngineDesc *desc;
Packit Service 1d8f1c
Packit Service 1d8f1c
    m_bus = ibus_bus_new ();
Packit Service 1d8f1c
    if (!ibus_bus_is_connected (m_bus)) {
Packit Service 1d8f1c
        g_critical ("ibus-daemon is not running.");
Packit Service 1d8f1c
        return FALSE;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
    factory = ibus_factory_new (ibus_bus_get_connection (m_bus));
Packit Service 1d8f1c
    g_signal_connect (factory, "create-engine",
Packit Service 1d8f1c
                      G_CALLBACK (create_engine_cb), NULL);
Packit Service 1d8f1c
Packit Service 1d8f1c
    component = ibus_component_new (
Packit Service 1d8f1c
            "org.freedesktop.IBus.SimpleTest",
Packit Service 1d8f1c
            "Simple Engine Test",
Packit Service 1d8f1c
            "0.0.1",
Packit Service 1d8f1c
            "GPL",
Packit Service 1d8f1c
            "Takao Fujiwara <takao.fujiwara1@gmail.com>",
Packit Service 1d8f1c
            "https://github.com/ibus/ibus/wiki",
Packit Service 1d8f1c
            "",
Packit Service 1d8f1c
            "ibus");
Packit Service 1d8f1c
    desc = ibus_engine_desc_new (
Packit Service 1d8f1c
            "xkbtest:us::eng",
Packit Service 1d8f1c
            "XKB Test",
Packit Service 1d8f1c
            "XKB Test",
Packit Service 1d8f1c
            "en",
Packit Service 1d8f1c
            "GPL",
Packit Service 1d8f1c
            "Takao Fujiwara <takao.fujiwara1@gmail.com>",
Packit Service 1d8f1c
            "ibus-engine",
Packit Service 1d8f1c
            "us");
Packit Service 1d8f1c
    ibus_component_add_engine (component, desc);
Packit Service 1d8f1c
    ibus_bus_register_component (m_bus, component);
Packit Service 1d8f1c
Packit Service 1d8f1c
    return TRUE;
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static gboolean
Packit Service 1d8f1c
finit (gpointer data)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    g_critical ("time out");
Packit Service 1d8f1c
    gtk_main_quit ();
Packit Service 1d8f1c
    return FALSE;
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static void
Packit Service 1d8f1c
send_key_event (Display *xdisplay,
Packit Service 1d8f1c
                guint    keyval,
Packit Service 1d8f1c
                guint    modifiers)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    static struct {
Packit Service 1d8f1c
        guint   state;
Packit Service 1d8f1c
        KeySym  keysym;
Packit Service 1d8f1c
    } state2keysym[] = {
Packit Service 1d8f1c
        { IBUS_CONTROL_MASK, XK_Control_L } ,
Packit Service 1d8f1c
        { IBUS_MOD1_MASK,    XK_Alt_L },
Packit Service 1d8f1c
        { IBUS_MOD4_MASK,    XK_Super_L },
Packit Service 1d8f1c
        { IBUS_SHIFT_MASK,   XK_Shift_L },
Packit Service 1d8f1c
        { IBUS_LOCK_MASK,    XK_Caps_Lock },
Packit Service 1d8f1c
        { 0,           0L }
Packit Service 1d8f1c
    };
Packit Service 1d8f1c
    int i;
Packit Service 1d8f1c
    guint keycode;
Packit Service 1d8f1c
    guint state = modifiers;
Packit Service 1d8f1c
Packit Service 1d8f1c
    while (state) {
Packit Service 1d8f1c
        for (i = 0; state2keysym[i].state; i++) {
Packit Service 1d8f1c
            if ((state2keysym[i].state & state) != 0) {
Packit Service 1d8f1c
                keycode = XKeysymToKeycode (xdisplay, state2keysym[i].keysym);
Packit Service 1d8f1c
                XTestFakeKeyEvent (xdisplay, keycode, True, CurrentTime);
Packit Service 1d8f1c
                XSync (xdisplay, False);
Packit Service 1d8f1c
                state ^= state2keysym[i].state;
Packit Service 1d8f1c
                break;
Packit Service 1d8f1c
            }
Packit Service 1d8f1c
        }
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
    keycode = XKeysymToKeycode (xdisplay, keyval);
Packit Service 1d8f1c
    XTestFakeKeyEvent (xdisplay, keycode, True, CurrentTime);
Packit Service 1d8f1c
    XSync (xdisplay, False);
Packit Service 1d8f1c
    XTestFakeKeyEvent (xdisplay, keycode, False, CurrentTime);
Packit Service 1d8f1c
    XSync (xdisplay, False);
Packit Service 1d8f1c
Packit Service 1d8f1c
    state = modifiers;
Packit Service 1d8f1c
    while (state) {
Packit Service 1d8f1c
        for (i = G_N_ELEMENTS (state2keysym) - 1; i >= 0; i--) {
Packit Service 1d8f1c
            if ((state2keysym[i].state & state) != 0) {
Packit Service 1d8f1c
                keycode = XKeysymToKeycode (xdisplay, state2keysym[i].keysym);
Packit Service 1d8f1c
                XTestFakeKeyEvent (xdisplay, keycode, False, CurrentTime);
Packit Service 1d8f1c
                XSync (xdisplay, False);
Packit Service 1d8f1c
                state ^= state2keysym[i].state;
Packit Service 1d8f1c
                break;
Packit Service 1d8f1c
            }
Packit Service 1d8f1c
        }
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static void
Packit Service 1d8f1c
set_engine_cb (GObject      *object,
Packit Service 1d8f1c
               GAsyncResult *res,
Packit Service 1d8f1c
               gpointer      data)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    IBusBus *bus = IBUS_BUS (object);
Packit Service 1d8f1c
    GtkWidget *entry = GTK_WIDGET (data);
Packit Service 1d8f1c
    GdkDisplay *display;
Packit Service 1d8f1c
    Display *xdisplay;
Packit Service 1d8f1c
    GError *error = NULL;
Packit Service 1d8f1c
    int i, j;
Packit Service 1d8f1c
Packit Service 1d8f1c
    g_assert (GTK_IS_ENTRY (entry));
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (!ibus_bus_set_global_engine_async_finish (bus, res, &error)) {
Packit Service 1d8f1c
        g_critical ("set engine failed: %s", error->message);
Packit Service 1d8f1c
        g_error_free (error);
Packit Service 1d8f1c
        return;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    display = gtk_widget_get_display (entry);
Packit Service 1d8f1c
    if (GDK_IS_X11_DISPLAY (display)) {
Packit Service 1d8f1c
        xdisplay = gdk_x11_display_get_xdisplay (display);
Packit Service 1d8f1c
    } else {
Packit Service 1d8f1c
#if 0
Packit Service 1d8f1c
        xdisplay = XOpenDisplay (NULL);
Packit Service 1d8f1c
#else
Packit Service 1d8f1c
        g_critical ("No idea to simulate key events in Wayland\n");
Packit Service 1d8f1c
#endif
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
    g_return_if_fail (xdisplay);
Packit Service 1d8f1c
Packit Service 1d8f1c
    for (i = 0; test_cases[i][0].keyval; i++) {
Packit Service 1d8f1c
        for (j = 0; test_cases[i][j].keyval; j++) {
Packit Service 1d8f1c
            send_key_event (xdisplay,
Packit Service 1d8f1c
                            test_cases[i][j].keyval,
Packit Service 1d8f1c
                            test_cases[i][j].modifiers);
Packit Service 1d8f1c
        }
Packit Service 1d8f1c
        send_key_event (xdisplay, test_end_key.keyval, test_end_key.modifiers);
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    g_timeout_add_seconds (10, finit, NULL);
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static gboolean
Packit Service 1d8f1c
window_focus_in_event_cb (GtkWidget *entry, GdkEventFocus *event, gpointer data)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    g_assert (m_bus != NULL);
Packit Service 1d8f1c
    ibus_bus_set_global_engine_async (m_bus,
Packit Service 1d8f1c
                                      "xkbtest:us::eng",
Packit Service 1d8f1c
                                      -1,
Packit Service 1d8f1c
                                      NULL,
Packit Service 1d8f1c
                                      set_engine_cb,
Packit Service 1d8f1c
                                      entry);
Packit Service 1d8f1c
    return FALSE;
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static void
Packit Service 1d8f1c
window_inserted_text_cb (GtkEntryBuffer *buffer,
Packit Service 1d8f1c
                         guint           position,
Packit Service 1d8f1c
                         const gchar    *chars,
Packit Service 1d8f1c
                         guint           nchars,
Packit Service 1d8f1c
                         gpointer        data)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    GtkWidget *entry = data;
Packit Service 1d8f1c
    static int i = 0;
Packit Service 1d8f1c
    static int j = 0;
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (g_utf8_get_char (chars) == 'Z') {
Packit Service 1d8f1c
        int k;
Packit Service 1d8f1c
        g_print ("\n" GREEN "PASS" NC ": ");
Packit Service 1d8f1c
        for (k = 0; k < j; k++)
Packit Service 1d8f1c
            g_print ("%lc(%X) ", test_results[i][k], test_results[i][k]);
Packit Service 1d8f1c
        g_print ("\n");
Packit Service 1d8f1c
        i++;
Packit Service 1d8f1c
        j = 0;
Packit Service 1d8f1c
        if (test_results[i][0] == 0)
Packit Service 1d8f1c
            gtk_main_quit ();
Packit Service 1d8f1c
        else
Packit Service 1d8f1c
            gtk_entry_set_text (GTK_ENTRY (entry), "");
Packit Service 1d8f1c
        return;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
    g_assert (g_utf8_get_char (chars) == test_results[i][j]);
Packit Service 1d8f1c
    j++;
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static void
Packit Service 1d8f1c
create_window ()
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
Packit Service 1d8f1c
    GtkWidget *entry = gtk_entry_new ();
Packit Service 1d8f1c
    GtkEntryBuffer *buffer;
Packit Service 1d8f1c
Packit Service 1d8f1c
    g_signal_connect (window, "destroy",
Packit Service 1d8f1c
                      G_CALLBACK (gtk_main_quit), NULL);
Packit Service 1d8f1c
    g_signal_connect (entry, "focus-in-event",
Packit Service 1d8f1c
                      G_CALLBACK (window_focus_in_event_cb), NULL);
Packit Service 1d8f1c
    buffer = gtk_entry_get_buffer (GTK_ENTRY (entry));
Packit Service 1d8f1c
    g_signal_connect (buffer, "inserted-text",
Packit Service 1d8f1c
                      G_CALLBACK (window_inserted_text_cb), entry);
Packit Service 1d8f1c
    gtk_container_add (GTK_CONTAINER (window), entry);
Packit Service 1d8f1c
    gtk_widget_show_all (window);
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static void
Packit Service 1d8f1c
test_keypress (void)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    int status = 0;
Packit Service 1d8f1c
    GError *error = NULL;
Packit Service 1d8f1c
Packit Service 1d8f1c
    g_spawn_command_line_sync ("setxkbmap -layout us",
Packit Service 1d8f1c
                               NULL, NULL,
Packit Service 1d8f1c
                               &status, &error);
Packit Service 1d8f1c
    g_assert (register_ibus_engine ());
Packit Service 1d8f1c
Packit Service 1d8f1c
    create_window ();
Packit Service 1d8f1c
    gtk_main ();
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
int
Packit Service 1d8f1c
main (int argc, char *argv[])
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    ibus_init ();
Packit Service 1d8f1c
    g_test_init (&argc, &argv, NULL);
Packit Service 1d8f1c
    gtk_init (&argc, &argv);
Packit Service 1d8f1c
Packit Service 1d8f1c
    g_test_add_func ("/ibus/keyrepss", test_keypress);
Packit Service 1d8f1c
Packit Service 1d8f1c
Packit Service 1d8f1c
    return g_test_run ();
Packit Service 1d8f1c
}