Add Keyboard event support

There are some mouse/touchpad devices that are combined with a keyboard
into a single device. Since mice are now handled by CMT, we will have to
support those devices.
This code is modeled after keyboard handling in xf86-input-evdev.

BUG=chromium:367969
TEST=Plug in a Logitech K400r, then use the device. Keyboard and
touchpad should be working.

Change-Id: I510cbfd81f11d80bd87647edf588f68c1f7b08b3
Reviewed-on: https://chromium-review.googlesource.com/197370
Reviewed-by: Andrew de los Reyes <adlr@chromium.org>
Tested-by: Dennis Kempin <denniskempin@chromium.org>
Commit-Queue: Dennis Kempin <denniskempin@chromium.org>
diff --git a/src/cmt.c b/src/cmt.c
index 070dda5..b692a77 100644
--- a/src/cmt.c
+++ b/src/cmt.c
@@ -19,6 +19,7 @@
 #include <X11/Xatom.h>
 #include <xf86Xinput.h>
 #include <xf86_OSproc.h>
+#include <xkbsrv.h>
 #include <xserver-properties.h>
 
 #include "properties.h"
@@ -353,6 +354,11 @@
 {
 }
 
+static void
+KeyboardCtrl(DeviceIntPtr device, KeybdCtrl *ctrl)
+{
+}
+
 static Atom
 InitAtom(const char* name)
 {
@@ -397,6 +403,7 @@
     InputInfoPtr info = dev->public.devicePrivate;
     CmtDevicePtr cmt = info->private;
 
+    XkbRMLVOSet rmlvo = { 0 };
     Atom axes_labels[CMT_NUM_AXES] = { 0 };
     Atom btn_labels[CMT_NUM_BUTTONS] = { 0 };
     /* Map our button numbers to standard ones. */
@@ -468,6 +475,18 @@
         xf86InitValuatorDefaults(dev, i);
     }
 
+    /* Initialize keyboard device struct. Based on xf86-input-evdev,
+       do not allow any rule/layout/etc changes. */
+    xf86ReplaceStrOption(info->options, "xkb_rules", "evdev");
+    rmlvo.rules = xf86SetStrOption(info->options, "xkb_rules", NULL);
+    rmlvo.model = xf86SetStrOption(info->options, "xkb_model", NULL);
+    rmlvo.layout = xf86SetStrOption(info->options, "xkb_layout", NULL);
+    rmlvo.variant = xf86SetStrOption(info->options, "xkb_variant", NULL);
+    rmlvo.options = xf86SetStrOption(info->options, "xkb_options", NULL);
+
+    InitKeyboardDeviceStruct(dev, &rmlvo, NULL, KeyboardCtrl);
+    XkbFreeRMLVOSet(&rmlvo, FALSE);
+
     return Success;
 }
 
diff --git a/src/cmt.h b/src/cmt.h
index faa4dc2..9a3191f 100644
--- a/src/cmt.h
+++ b/src/cmt.h
@@ -82,6 +82,7 @@
 
     char* device;
     long  handlers;
+    unsigned long prev_key_state[NLONGS(KEY_CNT)];
 } CmtDeviceRec, *CmtDevicePtr;
 
 #endif
diff --git a/src/gesture.c b/src/gesture.c
index f86ab87..81c2b38 100755
--- a/src/gesture.c
+++ b/src/gesture.c
@@ -35,6 +35,9 @@
     {BTN_EXTRA, GESTURES_BUTTON_FORWARD}
 };
 
+// Conversion from kernel key codes to xorg key codes
+#define MIN_KEYCODE 8
+
 /*
  * Gestures timer functions
  */
@@ -205,10 +208,28 @@
     struct HardwareState hwstate = { 0 };
     int current_finger;
     bool has_gesture_fingers = false;
+    unsigned long key_state_diff[NLONGS(KEY_CNT)];
+    int code;
+    int value;
 
     if (!rec->interpreter || ! rec->slot_states)
         return;
 
+    /* handle changed keys */
+    for (i = 0; i < NLONGS(KEY_CNT); ++i) {
+        key_state_diff[i] = evdev->key_state_bitmask[i] ^
+                            cmt->prev_key_state[i];
+    }
+    for (i = 0; i < KEY_CNT; ++i) {
+        if (TestBit(i, key_state_diff)) {
+            code = i + MIN_KEYCODE;
+            value = TestBit(i, evdev->key_state_bitmask);
+            xf86PostKeyboardEvent(dev, code, value);
+        }
+    }
+    for (i = 0; i < NLONGS(KEY_CNT); ++i) {
+        cmt->prev_key_state[i] = evdev->key_state_bitmask[i];
+    }
     /* zero initialize all FingerStates to clear out previous state. */
     memset(rec->fingers, 0,
            Event_Get_Slot_Count(evdev) * sizeof(struct FingerState));