From 0b8c6f1e18ff28e75bda75d2cc2c1c36c8fae4fb Mon Sep 17 00:00:00 2001
From: Gianni Ceccarelli <gianni.ceccarelli@net-a-porter.com>
Date: Tue, 3 Apr 2012 12:29:03 +0100
Subject: code-remap for 2.9.0

Thanks to Tristan King <tristan.king@gmail.com> for reminding me to do
it and checking that it works.

James: adapted patch to work with xf86-input-evdev-2.10.0.

diff -ur xf86-input-evdev-2.10.0/man/evdev.man xf86-input-evdev-2.10.0-new/man/evdev.man
--- xf86-input-evdev-2.10.0/man/evdev.man	2015-10-27 04:45:58.000000000 +0700
+++ xf86-input-evdev-2.10.0-new/man/evdev.man	2015-12-22 11:08:32.818823866 +0700
@@ -244,6 +244,17 @@
 to scale relative motion events from mouse devices to 1000 DPI resolution. This
 can be used to make high resolution mice less sensitive without turning off
 acceleration. If set to 0 no scaling will be performed. Default: "0".
+.BI "Option \*qevent_key_remap\*q \*q" "integer=integer ..." \*q
+Specifies a set of mappings for key events; the number on the
+left-hand side of the equal sign must be an evdev keycode (look it up
+with
+.B "showkey -k"
+; it can be between 0 and 65535), the number on the right-hand side of
+the equal sign must be an X11 keycode (look it up in the
+.B "__projectroot__/share/X11/xkb/keycodes/evdev"
+file; it can be between 8 and 255). Integers can be specified as in C
+source files (base-10, base-8 if they start with 0, base-16 if they
+start with 0x).
 
 .SH SUPPORTED PROPERTIES
 The following properties are provided by the
diff -ur xf86-input-evdev-2.10.0/src/evdev.c xf86-input-evdev-2.10.0-new/src/evdev.c
--- xf86-input-evdev-2.10.0/src/evdev.c	2015-10-27 04:45:58.000000000 +0700
+++ xf86-input-evdev-2.10.0-new/src/evdev.c	2015-12-22 11:05:02.055485351 +0700
@@ -127,6 +127,46 @@
 static Atom prop_virtual;
 static Atom prop_scroll_dist;
 
+static uint16_t
+remapKey(EvdevPtr ev, uint16_t code)
+{
+    uint8_t slice=code/256;
+    uint8_t offs=code%256;
+
+    if (!ev->keyremap) return code;
+    if (!(ev->keyremap->sl[slice])) return code;
+    if (!(ev->keyremap->sl[slice]->cd[offs])) return code;
+    return ev->keyremap->sl[slice]->cd[offs];
+}
+
+static void
+addRemap(EvdevPtr ev,uint16_t code,uint8_t value)
+{
+    uint8_t slice=code/256;
+    uint8_t offs=code%256;
+
+    if (!ev->keyremap) {
+        ev->keyremap=(EvdevKeyRemapPtr)calloc(sizeof(EvdevKeyRemap),1);
+    }
+    if (!ev->keyremap->sl[slice]) {
+        ev->keyremap->sl[slice]=(EvdevKeyRemapSlice*)calloc(sizeof(EvdevKeyRemapSlice),1);
+     }
+     ev->keyremap->sl[slice]->cd[offs]=value;
+}
+
+static void
+freeRemap(EvdevPtr ev)
+{
+    uint16_t slice;
+    if (!ev->keyremap) return;
+    for (slice=0;slice<256;++slice) {
+        if (!ev->keyremap->sl[slice]) continue;
+        free(ev->keyremap->sl[slice]);
+    }
+    free(ev->keyremap);
+    ev->keyremap=0;
+}
+
 static int EvdevSwitchMode(ClientPtr client, DeviceIntPtr device, int mode)
 {
     InputInfoPtr pInfo;
@@ -259,6 +299,42 @@
 }
 
 
+static void
+SetRemapOption(InputInfoPtr pInfo,const char* name)
+{
+    char *s,*c;
+    unsigned long int code,value;
+    int consumed;
+    EvdevPtr ev = pInfo->private;
+
+    s = xf86SetStrOption(pInfo->options, name, NULL);
+    if (!s) return;
+    if (!s[0]) {
+        free(s);
+        return;
+    }
+
+    c=s;
+    while (sscanf(c," %li = %li %n",&code,&value,&consumed) > 1) {
+        c+=consumed;
+        if (code < 0 || code > 65535L) {
+            xf86Msg(X_ERROR,"%s: input code %ld out of range for option \"event_key_remap\", ignoring.\n",pInfo->name,code);
+            continue;
+        }
+        if (value < MIN_KEYCODE || value > 255) {
+            xf86Msg(X_ERROR,"%s: output value %ld out of range for option \"event_key_remap\", ignoring.\n",pInfo->name,value);
+            continue;
+        }
+        xf86Msg(X_INFO,"%s: remapping %ld into %ld.\n",pInfo->name,code,value);
+        addRemap(ev,code,value-MIN_KEYCODE);
+    }
+
+    if (*c!='\0') {
+        xf86Msg(X_ERROR, "%s: invalid input for option \"event_key_remap\" starting at '%s', ignoring.\n",
+                pInfo->name, c);
+    }
+}
+
 static EventQueuePtr
 EvdevNextInQueue(InputInfoPtr pInfo)
 {
@@ -277,7 +353,7 @@
 void
 EvdevQueueKbdEvent(InputInfoPtr pInfo, struct input_event *ev, int value)
 {
-    int code = ev->code + MIN_KEYCODE;
+    int code = remapKey((EvdevPtr)(pInfo->private),ev->code) + MIN_KEYCODE;
     EventQueuePtr pQueue;
 
     /* Filter all repeated events from device.
@@ -1133,6 +1209,8 @@
     rmlvo.variant = xf86SetStrOption(pInfo->options, "xkb_variant", defaults.variant);
     rmlvo.options = xf86SetStrOption(pInfo->options, "xkb_options", defaults.options);
 
+    SetRemapOption(pInfo,"event_key_remap");
+
     if (!InitKeyboardDeviceStruct(device, &rmlvo, NULL, EvdevKbdCtrl))
         rc = !Success;
 
@@ -2002,6 +2080,7 @@
 	xf86IDrvMsg(pInfo, X_INFO, "Close\n");
         EvdevCloseDevice(pInfo);
         EvdevFreeMasks(pEvdev);
+        freeRemap(pEvdev);
         pEvdev->min_maj = 0;
 	break;
 
diff -ur xf86-input-evdev-2.10.0/src/evdev.h xf86-input-evdev-2.10.0-new/src/evdev.h
--- xf86-input-evdev-2.10.0/src/evdev.h	2015-10-27 04:45:58.000000000 +0700
+++ xf86-input-evdev-2.10.0-new/src/evdev.h	2015-12-22 11:05:02.055485351 +0700
@@ -142,6 +142,14 @@
 } EventQueueRec, *EventQueuePtr;
 
 typedef struct {
+    uint8_t cd[256];
+} EvdevKeyRemapSlice;
+
+typedef struct {
+    EvdevKeyRemapSlice* sl[256];
+} EvdevKeyRemap, *EvdevKeyRemapPtr;
+
+typedef struct {
     struct libevdev *dev;
 
     char *device;
@@ -229,6 +237,8 @@
 
     unsigned char btnmap[32];           /* config-file specified button mapping */
 
+    EvdevKeyRemapPtr keyremap;
+
     int reopen_attempts; /* max attempts to re-open after read failure */
     int reopen_left;     /* number of attempts left to re-open the device */
     OsTimerPtr reopen_timer;
