Fix some keys' behavior, XKB-ify the whole lookup process and handle groups
authorThibaut Girka <thib@sitedethib.com>
Thu, 21 Jul 2011 17:49:33 +0200
changeset 12 d83eef518a33
parent 11 a4087b9e0406
child 13 9a705eabfa7d
Fix some keys' behavior, XKB-ify the whole lookup process and handle groups
keyboard.h
ui.c
--- a/keyboard.h	Thu Jul 21 15:49:33 2011 +0200
+++ b/keyboard.h	Thu Jul 21 17:49:33 2011 +0200
@@ -38,6 +38,7 @@
     VirtualKey      *keys;
 
     int             mods;
+    int             group;
 
     VirtualKey      *pressed_key;
 } VirtualKeyboard;
--- a/ui.c	Thu Jul 21 15:49:33 2011 +0200
+++ b/ui.c	Thu Jul 21 17:49:33 2011 +0200
@@ -97,7 +97,7 @@
     XSelectInput(ui->vkb->display,  ui->xwin_root, 
                  SubstructureNotifyMask|StructureNotifyMask|PropertyChangeMask);
 
-    XkbSelectEvents(ui->vkb->display, XkbUseCoreKbd, XkbStateNotifyMask, XkbStateNotifyMask);
+    XkbSelectEvents(ui->vkb->display, XkbUseCoreKbd, XkbAllEventsMask, XkbAllEventsMask);
 
     ui->visible = False;
     ui->backbuffer = 0;
@@ -255,8 +255,7 @@
 {
     PangoLayout *layout;
     cairo_t *context;
-    XKeyEvent evt = {.type=KeyPress, .display=ui->vkb->display, .state=ui->vkb->mods};
-    int i;
+    int i, j, index;
 
     context = cairo_create(ui->cairo_surf);
     layout = pango_cairo_create_layout(context);
@@ -271,88 +270,111 @@
     {
         unsigned int x, y, width, height;
         int utf8_len;
-        char utf8[5];
+        char utf8[8];
         char *text = NULL;
         KeySym keysym;
         VirtualKey vkey = ui->vkb->keys[i];
-        evt.keycode = vkey.keycode;
-
-        /* TODO: find a more "XKB" way and/or use Xutf8LookupString */
-        utf8_len = XLookupString(&evt, utf8, 4, &keysym, NULL);
 
-        x = vkey.effective_x;
-        y = vkey.effective_y;
-        width = vkey.effective_width;
-        height = vkey.effective_height;
+        /* TODO: cleanup */
+#if 1
+        /* Compute shift level. FIXME: there must be a nicer way */
+        unsigned shift_level = 0;
+        unsigned int mask;
+        index = ui->vkb->xkb->map->key_sym_map[vkey.keycode].kt_index[ui->vkb->group];
+        mask = ui->vkb->xkb->map->types[index].mods.mask & ui->vkb->mods;
+        if (mask != 0)
+            shift_level = 1;
+        for (j=0; j < ui->vkb->xkb->map->types[index].map_count; j++)
+        {
+            if (mask == ui->vkb->xkb->map->types[index].map[j].mods.mask)
+                shift_level = ui->vkb->xkb->map->types[index].map[j].level;
+        }
+        if ((keysym = XkbKeycodeToKeysym(ui->vkb->display, vkey.keycode,
+                                ui->vkb->group, shift_level)) != NoSymbol)
+#else
+        /* Unnused since it doesn't seem to handle groups nicely */
+        unsigned int mods_rtn = 0;
+        if (XkbTranslateKeyCode(ui->vkb->xkb, vkey.keycode,
+                                ui->vkb->mods, &mods_rtn, &keysym))
+#endif
+        {
+            utf8_len = XkbTranslateKeySym(ui->vkb->display, &keysym,
+                                          0, /* ui->vkb->mods & ~mods_rtn, */
+                                          utf8, 8, NULL);
 
-        cairo_rectangle(context, x, y, width, height);
-        cairo_set_source_rgb(context, 0.4, 0.4, 0.4);
-        cairo_fill(context);
+            x = vkey.effective_x;
+            y = vkey.effective_y;
+            width = vkey.effective_width;
+            height = vkey.effective_height;
 
-        if (!vkey.state)
-        {
-            cairo_rectangle(context, x + 1, y + 1, width - 2, height - 2);
-            cairo_set_source_rgb(context, 1., 1., 1.);
+            cairo_rectangle(context, x, y, width, height);
+            cairo_set_source_rgb(context, 0.4, 0.4, 0.4);
             cairo_fill(context);
 
-            cairo_rectangle(context, x + 3, y + 3, width - 5, height - 5);
-            cairo_set_source_rgb(context, 0.94, 0.94, 0.94);
-            cairo_fill(context);
-        }
+            if (!vkey.state)
+            {
+                cairo_rectangle(context, x + 1, y + 1, width - 2, height - 2);
+                cairo_set_source_rgb(context, 1., 1., 1.);
+                cairo_fill(context);
 
+                cairo_rectangle(context, x + 3, y + 3, width - 5, height - 5);
+                cairo_set_source_rgb(context, 0.94, 0.94, 0.94);
+                cairo_fill(context);
+            }
 
-        switch (keysym)
-        {
-            case XK_BackSpace:
-                text = "Bksp";
-                break;
-            case XK_Super_L:
-            case XK_Super_R:
-                text = "Super";
-                break;
-            case XK_Alt_L:
-            case XK_Alt_R:
-                text = "Alt";
-                break;
-            case XK_Control_L:
-            case XK_Control_R:
-                text = "Ctrl";
-                break;
-            case XK_Caps_Lock:
-                text = "Caps";
-                break;
-            case XK_Tab:
-            case XK_ISO_Left_Tab:
-                text = "Tab";
-                break;
-            case XK_Return:
-                text = "Ret";
-                break;
-            case XK_Shift_L:
-            case XK_Shift_R:
-                text = "Shift";
-                break;
-            default:
-                if (utf8_len > 0 && !(utf8_len == 1 && !isgraph(utf8[0])))
-                {
-                    text = utf8;
-                    text[utf8_len] = 0;
-                }
-                else
-                {
-                    text = XKeysymToString(keysym);
-                }
-        }
+            switch (keysym)
+            {
+                case XK_BackSpace:
+                    text = "Bksp";
+                    break;
+                case XK_Super_L:
+                case XK_Super_R:
+                    text = "Super";
+                    break;
+                case XK_Alt_L:
+                case XK_Alt_R:
+                    text = "Alt";
+                    break;
+                case XK_Control_L:
+                case XK_Control_R:
+                    text = "Ctrl";
+                    break;
+                case XK_Caps_Lock:
+                    text = "Caps";
+                    break;
+                case XK_Tab:
+                case XK_ISO_Left_Tab:
+                    text = "Tab";
+                    break;
+                case XK_Return:
+                    text = "Ret";
+                    break;
+                case XK_Shift_L:
+                case XK_Shift_R:
+                    text = "Shift";
+                    break;
+                default:
+                    if (utf8_len > 0)
+                    {
+                        text = utf8;
+                        text[utf8_len] = 0;
+                    }
+                    else
+                    {
+                        text = XKeysymToString(keysym);
+                    }
+            }
 
-        if (text != NULL)
-        {
-            int h2;
-            cairo_set_source_rgb (context, 0.0, 0.0, 0.0);
-            pango_layout_set_width(layout, width);
-            pango_layout_set_text(layout, text, -1);
-            pango_layout_get_pixel_size(layout, NULL, &h2);
-            cairo_move_to(context, x + width / 2, y + height / 2 - h2 / 2);
-            pango_cairo_show_layout(context, layout);
+            if (text != NULL)
+            {
+                int h2;
+                cairo_set_source_rgb (context, 0.0, 0.0, 0.0);
+                pango_layout_set_width(layout, width);
+                pango_layout_set_text(layout, text, -1);
+                pango_layout_get_pixel_size(layout, NULL, &h2);
+                cairo_move_to(context, x + width / 2, y + height / 2 - h2 / 2);
+                pango_cairo_show_layout(context, layout);
+            }
         }
     }
 
@@ -428,22 +450,26 @@
                 x = xev.xbutton.x * ui->vkb->width / ui->width;
                 y = xev.xbutton.y * ui->vkb->height / ui->height;
                 vkey = keyboard_locate_key(ui->vkb, x, y);
-                /* TODO: clean up this mess, and handle it in a more "XKB" way */
+                /* TODO: clean up this mess */
                 if (vkey && vkey->keycode)
                 {
-                    if (ui->vkb->xkb->map->modmap[vkey->keycode]) /* modifier */
+                    /* TODO: shift level */
+                    XkbAction *action = XkbKeyActionEntry(ui->vkb->xkb, vkey->keycode, 0, ui->vkb->group);
+
+                    /* TODO: how is compose handled? */
+                    if (action != NULL && (action->any.type == XkbSA_LockMods || action->any.type == XkbSA_SetMods)) /* modifier */
                     {
                         if (vkey->state)
                         {
                             vkey->state = VirtualKeyReleased;
-                            if (ui->vkb->xkb->map->modmap[vkey->keycode] & LockMask)
+                            if (action->any.type == XkbSA_LockMods)
                                 XTestFakeKeyEvent(ui->vkb->display, vkey->keycode, True, 0);
                             XTestFakeKeyEvent(ui->vkb->display, vkey->keycode, False, 0);
                         }
                         else
                         {
                             XTestFakeKeyEvent(ui->vkb->display, vkey->keycode, True, 0);
-                            if (ui->vkb->xkb->map->modmap[vkey->keycode] & LockMask)
+                            if (action->any.type == XkbSA_LockMods)
                             {
                                 vkey->state = VirtualKeyToggled;
                                 XTestFakeKeyEvent(ui->vkb->display, vkey->keycode, False, 0);
@@ -501,10 +527,6 @@
             case Expose:
                 ui_redraw(ui);
                 break;
-            case MappingNotify:
-                XkbGetUpdatedMap(ui->vkb->display, XkbAllMapComponentsMask, ui->vkb->xkb);
-                ui_redraw(ui);
-                break;
             case ClientMessage:
                 if (xev.xclient.message_type == XInternAtom(ui->vkb->display, "_MB_IM_INVOKER_COMMAND", False))
                 {
@@ -558,10 +580,21 @@
             default:
                 if (xev.type == ui->xkb_event_base)
                 {
-                    if (((XkbAnyEvent*) &xev)->xkb_type == XkbStateNotify)
+                    switch (((XkbAnyEvent*) &xev)->xkb_type)
                     {
-                        ui->vkb->mods = ((XkbStateNotifyEvent*) &xev)->mods;
-                        ui_redraw(ui);
+                        case XkbStateNotify:
+                            ui->vkb->mods = ((XkbStateNotifyEvent*) &xev)->mods;
+                            ui->vkb->group = ((XkbStateNotifyEvent*) &xev)->group;
+                            ui_redraw(ui);
+                            break;
+                        case XkbNewKeyboardNotify:
+                        case XkbMapNotify:
+                            XkbGetUpdatedMap(ui->vkb->display, XkbAllMapComponentsMask, ui->vkb->xkb);
+                            ui_redraw(ui);
+                            break;
+                        default:
+                            /* TODO */
+                            break;
                     }
                 }
                 break;