]> gitweb.factorcode.org Git - factor.git/commitdiff
linux.input-events: Add support for /dev/input/event* devices.
authorDoug Coleman <doug.coleman@gmail.com>
Mon, 22 Feb 2021 07:40:21 +0000 (01:40 -0600)
committerDoug Coleman <doug.coleman@gmail.com>
Mon, 22 Feb 2021 08:15:40 +0000 (02:15 -0600)
Pretty complete but needs integration into the game.input framework
and some examples of force feedback.

! To read a mouse:
get-input-events-mice first second <linux-controller> read-controller-loop

! To read a keyboard:
get-input-events-keyboards first second <linux-controller> read-controller-loop

! Show all devices
all-controller-stats ...

! linux util to do similar stuff
evtest /dev/input/event256

basis/game/input/gtk/gtk.factor
basis/unix/time/time.factor
basis/unix/types/linux/linux.factor
extra/linux/input-events/authors.txt [new file with mode: 0644]
extra/linux/input-events/ffi/authors.txt [new file with mode: 0644]
extra/linux/input-events/ffi/ffi.factor [new file with mode: 0644]
extra/linux/input-events/ffi/platforms.txt [new file with mode: 0644]
extra/linux/input-events/input-events.factor [new file with mode: 0644]
extra/linux/input-events/platforms.txt [new file with mode: 0644]

index 8801610dddd9ecde5622016559f19f2d0e530479..51913dd661e48aada931c12ea38e6ed345f397dc 100644 (file)
@@ -1,8 +1,10 @@
 ! Copyright (C) 2010 Erik Charlebois, William Schlieper.
 ! See http://factorcode.org/license.txt for BSD license.
-USING: accessors alien.c-types alien.data alien.syntax assocs
-bit-arrays game.input gdk.ffi generalizations kernel math
-namespaces sequences system x11.xlib ;
+USING: accessors alien.c-types alien.data alien.syntax arrays
+assocs bit-arrays destructors game.input gdk.ffi
+io.encodings.binary io.files kernel linux.input-events
+linux.input-events.ffi math namespaces sequences
+sequences.extras system unix.ffi x11.xlib ;
 IN: game.input.gtk
 
 SINGLETON: gtk-game-input-backend
@@ -12,6 +14,20 @@ gtk-game-input-backend game-input-backend set-global
 LIBRARY: gdk
 FUNCTION: Display* gdk_x11_display_get_xdisplay ( GdkDisplay* display )
 
+TUPLE: linux-controller < controller path meta state thread fd buttons quit? ;
+: <linux-controller> ( path -- controller )
+    linux-controller new
+        swap >>path
+        dup path>> get-event-device-info >>meta
+        dup meta>> "path" of binary <file-reader> handle>> fd>> >>fd
+        H{ } clone >>state
+        dup meta>> "capabilities" of EV_KEY of keys seq>explode-positions >>buttons ; inline
+        ! swap over state>> '[ _ _ read-events ] in-thread ;
+
+M: linux-controller dispose* fd>> close drop ;
+
+TUPLE: linux-controller-state < controller-state abs ;
+
 : get-dpy ( -- dpy )
     gdk_display_get_default [ gdk_x11_display_get_xdisplay ] [
         "No default display." throw
@@ -27,19 +43,22 @@ M: gtk-game-input-backend (reset-game-input)
     ;
 
 M: gtk-game-input-backend get-controllers
-    { } ;
+    get-input-events-joysticks values [ <linux-controller> ] map ;
 
 M: gtk-game-input-backend product-string
-    drop "" ;
+    meta>> "name" of ;
 
 M: gtk-game-input-backend product-id
-    drop f ;
+    meta>> "id" of ;
 
 M: gtk-game-input-backend instance-id
     drop f ;
 
 M: gtk-game-input-backend read-controller
-    drop controller-state new ;
+    [ linux-controller-state new ] dip
+    [ fd>> ] [ meta>> ] bi
+    [ drop evdev-get-key seq>explode-positions [ <INPUT_KEY> ] map-zip >>buttons ]
+    [ "capabilities" of EV_ABS of [ [ first first evdev-get-abs ] [ first ] bi swap 2array ] with map >>abs ] 2bi ;
 
 M: gtk-game-input-backend calibrate-controller
     drop ;
index ca89cb36c0183c91ba4a226cd0c0a29dc3101bad..71c34046d89dfc1a830a3406c7eb54825e70e143 100644 (file)
@@ -12,6 +12,11 @@ STRUCT: timespec
     { sec time_t }
     { nsec long } ;
 
+: <timeval> ( sec usec -- timeval )
+    timeval <struct>
+        swap >>usec
+        swap >>sec ; inline
+
 : make-timeval ( us -- timeval )
     [ timeval <struct> ] dip [
         1000000 /mod [ >>sec ] [ >>usec ] bi*
index c5de4c2c920187e1ddf03281422728d07ced5c9b..49ea8e17e78009453080079967a1196014d2c2ad 100644 (file)
@@ -6,8 +6,14 @@ TYPEDEF: ulong     __ulongword_type
 TYPEDEF: long      __sword_type
 TYPEDEF: ulong     __uword_type
 TYPEDEF: long      __slongword_type
+TYPEDEF: uchar     __u8
+TYPEDEF: ushort    __u16
 TYPEDEF: uint      __u32
-TYPEDEF: ulonglong __u64
+TYPEDEF: longlong  __u64
+TYPEDEF: char      __s8
+TYPEDEF: short     __s16
+TYPEDEF: int       __s32
+TYPEDEF: longlong  __s64
 TYPEDEF: uint      __u32_type
 TYPEDEF: int       __s32_type
 
diff --git a/extra/linux/input-events/authors.txt b/extra/linux/input-events/authors.txt
new file mode 100644 (file)
index 0000000..7c1b2f2
--- /dev/null
@@ -0,0 +1 @@
+Doug Coleman
diff --git a/extra/linux/input-events/ffi/authors.txt b/extra/linux/input-events/ffi/authors.txt
new file mode 100644 (file)
index 0000000..7c1b2f2
--- /dev/null
@@ -0,0 +1 @@
+Doug Coleman
diff --git a/extra/linux/input-events/ffi/ffi.factor b/extra/linux/input-events/ffi/ffi.factor
new file mode 100644 (file)
index 0000000..b2d07d8
--- /dev/null
@@ -0,0 +1,1026 @@
+! Copyright (C) 2021 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: alien alien.c-types alien.data alien.syntax byte-arrays
+classes.struct combinators continuations io.encodings.string
+io.encodings.utf8 kernel libc math math.vectors sequences
+splitting unix.ffi unix.types ;
+IN: linux.input-events.ffi
+
+! IOCTLs 0x00-0x7f
+STRUCT: input_id
+    { bustype __u16 }
+    { vendor __u16 }
+    { product __u16 }
+    { version __u16 } ;
+
+STRUCT: input_absinfo
+    { value __s32 }
+    { minimum __s32 }
+    { maximum __s32 }
+    { fuzz __s32 }
+    { flat __s32 }
+    { resolution __s32 } ;
+
+STRUCT: input_keymap_entry
+    { flags __u8 }
+    { len __u8 }
+    { index __u16 }
+    { keycode __u32 }
+    { scancode __u8[32] } ;
+
+STRUCT: input_mask
+    { type __u32 }
+    { codes_size __u32 }
+    { codes_ptr __u64 } ;
+
+STRUCT: ff_replay
+    { length __u16 }
+    { delay __u16 } ;
+
+STRUCT: ff_trigger
+    { button __u16 }
+    { interval __u16 } ;
+
+STRUCT: ff_envelope
+    { attack_length __u16 }
+    { attack_level __u16 }
+    { fade_length __u16 }
+    { fade_level __u16 } ;
+
+STRUCT: ff_constant_effect
+    { level __s16 }
+    { envelope ff_envelope } ;
+
+STRUCT: ff_ramp_effect
+    { start_level __s16 }
+    { end_level __s16 }
+    { envelope ff_envelope } ;
+
+STRUCT: ff_condition_effect
+    { right_saturation __u16 }
+    { left_saturation __u16 }
+    { right_coeff __s16 }
+    { left_coeff __s16 }
+    { deadband __u16 }
+    { center __s16 } ;
+
+STRUCT: ff_periodic_effect
+    { waveform __u16 }
+    { period __u16 }
+    { magnitude __s16 }
+    { offset __s16 }
+    { phase __u16 }
+    { envelope ff_envelope }
+    { custom_len __u32 }
+    { custom_data __s16* } ;
+
+STRUCT: ff_rumble_effect
+    { strong_magnitude __u16 }
+    { weak_magnitude __u16 } ;
+
+UNION-STRUCT: ff_dummy
+    { constant ff_constant_effect }
+    { ramp ff_ramp_effect }
+    { periodic ff_periodic_effect }
+    { condition ff_condition_effect[2] } ! One for each axis
+    { rumble ff_rumble_effect } ;
+
+! direction in degrees, 0, 90, 180, 270: 0x0000 down, 0x4000 left, 0x8000 up, 0xc000 right
+STRUCT: ff_effect
+    { type __u16 }
+    { id __s16 }
+    { direction __u16 }
+    { trigger ff_trigger }
+    { replay ff_replay }
+    { union ff_dummy } ;
+
+: n>explode-values ( x -- seq )
+    [ dup 0 > ]
+    [ dup log2 2^ [ bitxor ] keep ] produce nip reverse ; inline
+
+: n>explode-positions ( x -- seq )
+    n>explode-values [ log2 ] map ; inline
+
+: seq>explode-values ( seq -- seq' )
+    [ [ n>explode-values ] dip 8 * v+n ] map-index concat ;
+
+: seq>explode-positions ( seq -- seq' )
+    [ [ n>explode-positions ] dip 8 * v+n ] map-index concat ;
+
+: values>implode ( seq -- x ) 0 [ bitor ] reduce ;
+: positions>implode ( seq -- x ) 0 [ 2^ bitor ] reduce ;
+
+CONSTANT: IOC_NONE 0
+CONSTANT: IOC_WRITE 1
+CONSTANT: IOC_READ 2
+
+! IOC is encoded as:
+CONSTANT: IOC_NRBITS 8
+CONSTANT: IOC_TYPEBITS 8
+CONSTANT: IOC_SIZEBITS 14
+CONSTANT: IOC_DIRBITS 2
+
+CONSTANT: IOC_NRSHIFT 0
+CONSTANT: IOC_TYPESHIFT 8  ! NRSHIFT + NRBITS
+CONSTANT: IOC_SIZESHIFT 16 ! TYPESHIFT + TYEPBITS
+CONSTANT: IOC_DIRSHIFT 30  ! SIZESHIFT + SIZEBITS
+
+: IOC ( dir type-ch nr c-size -- x )
+    {
+        [ IOC_DIRSHIFT shift ]
+        [ IOC_TYPESHIFT shift ]
+        [ IOC_NRSHIFT shift ]
+        [ IOC_SIZESHIFT shift ]
+    } spread + + + ; inline
+
+: IOR-size ( type-ch nr size -- x )
+    [ IOC_READ ] 3dip IOC ; inline
+
+: IOR ( type-ch nr c-type -- x c-type )
+    [ IOC_READ ] 3dip [ heap-size IOC ] keep ; inline
+
+: IOW ( type-ch nr struct -- x struct )
+    [ IOC_WRITE ] 3dip [ byte-length IOC ] keep ; inline
+: IOW-size ( type-ch nr size -- x )
+    [ IOC_WRITE ] 3dip IOC ; inline
+
+: call-ioctl ( handle id bytes -- ) ioctl io-error ; inline
+: call-ioctl-out ( handle id bytes -- out )
+    [ ioctl io-error ] keep ; inline
+
+: <0ref> ( type -- ref ) 0 swap <ref> ; inline
+: byte-array-ioctl ( handle id len -- out )
+    <byte-array> call-ioctl-out ; inline
+: c-array-ioctl ( handle id ctype -- out )
+    heap-size <byte-array> call-ioctl-out ; inline
+: c-string-ioctl ( handle id ctype -- out )
+    c-array-ioctl "\0" split1 drop utf8 decode ;
+: ctype-ioctl-out ( handle id ctype -- out )
+    [ <0ref> call-ioctl-out ] keep deref ; inline
+: ctype-ioctl-inout ( handle id bytes type -- out )
+    [ call-ioctl-out ] dip deref ; inline
+: struct-ioctl ( handle id struct-class -- out )
+    <struct> call-ioctl-out ; inline
+
+! EV IOC G/S - evdev ioctl get/set
+! EVIOCGVERSION EVIOCGID EVIOCGREP EVIOCSREP
+: evdev-get-version ( handle -- version ) CHAR: E 0x01 int IOR ctype-ioctl-out ;
+: evdev-get-id ( handle -- version ) CHAR: E 0x02 input_id IOR struct-ioctl ;
+: evdev-get-repeat ( handle -- version ) CHAR: E 0x03 { int 2 } IOR c-array-ioctl ;
+: evdev-set-repeat ( handle struct -- version )
+    [ CHAR: E 0x03 ] dip IOW call-ioctl-out ;
+! EVIOCGKEYCODE EVIOCGKEYCODE_V2 EVIOCSKEYCODE EVIOCSKEYCODE_V2
+: evdev-get-keycode ( handle -- int[2] ) CHAR: E 0x04 { int 2 } IOR c-array-ioctl ;
+: evdev-get-keycode-v2 ( handle -- input_keymap_entry ) CHAR: E 0x04 input_keymap_entry IOR struct-ioctl ;
+: evdev-set-keycode ( handle int[2] -- out ) [ CHAR: E 0x04 ] dip IOW call-ioctl-out ;
+: evdev-set-keycode-v2 ( handle input_keymap_entry -- out ) [ CHAR: E 0x04 ] dip IOW call-ioctl-out ;
+! EVIOCGNAME EVIOCGPHYS EVIOCGUNIQ EVIOCGPROP
+: evdev-get-name ( handle -- name ) CHAR: E 0x06 { char 256 } IOR c-string-ioctl ;
+: evdev-get-physical ( handle -- physical ) CHAR: E 0x07 { char 256 } IOR c-string-ioctl ;
+: evdev-get-unique ( handle -- unique )
+    '[ _ CHAR: E 0x08 { char 512 } IOR c-string-ioctl ] [ drop "" ] recover ;
+: evdev-get-prop ( handle -- prop ) CHAR: E 0x09 { char 256 } IOR c-string-ioctl ;
+! EVIOCGMTSLOTS, size is encoded by IOR
+STRUCT: input_mt_request_layout
+    { code __u32 }
+    { values __s32* } ; ! values[num_slots]
+: evdev-get-mt-slots ( handle size input_mt_request_layout -- prop )
+    '[ _ CHAR: E 0x0a _ IOR-size _ call-ioctl-out ] [ drop f ] recover ;
+! EVIOCGKEY EVIOCGLED EVIOCGSND EVIOCGSW EVIOCGABS EVIOCSABS
+: evdev-get-key ( handle -- bytes ) CHAR: E 0x18 256 IOR-size 256 byte-array-ioctl ;
+: evdev-get-led ( handle -- bytes ) CHAR: E 0x19 256 IOR-size 256 byte-array-ioctl ;
+: evdev-get-sound ( handle -- bytes ) CHAR: E 0x1a 256 IOR-size 256 byte-array-ioctl ;
+: evdev-get-switch ( handle -- bytes ) CHAR: E 0x1b 256 IOR-size 256 byte-array-ioctl ;
+: evdev-get-abs ( handle n -- int[6] ) [ CHAR: E ] dip 0x40 + input_absinfo IOR struct-ioctl ;
+: evdev-set-abs ( handle input_absinfo -- int[6] ) [ CHAR: E ] dip 0xc0 + input_absinfo IOW struct-ioctl ;
+! EVIOCSFF EVIOCRMFF EVIOCGEFFECTS
+: evdev-set-force-feedback ( handle ff_effect -- out )
+    [ CHAR: E 0x80 ] dip IOW call-ioctl-out ;
+: evdev-unset-force-feedback ( handle int -- int )
+    [ CHAR: E 0x81 ] dip IOW int ctype-ioctl-inout ;
+: evdev-get-simulataneous-effects ( handle -- int )
+    CHAR: E 0x84 int IOR ctype-ioctl-out ;
+! EVIOCGRAB EVIOCREVOKE
+: evdev-grab-device ( handle -- int )
+    CHAR: E 0x90 69 int <ref> IOW int ctype-ioctl-inout ;
+: evdev-ungrab-device ( handle -- )
+    CHAR: E 0x90 4 IOW-size f call-ioctl ;
+: evdev-revoke-device ( handle -- )
+    CHAR: E 0x91 4 IOW-size f call-ioctl ;
+! EVIOCGMASK EVIOCSMASK
+: evdev-get-event-mask ( handle -- int )
+    CHAR: E 0x92 input_mask IOR struct-ioctl ;
+: evdev-set-event-mask ( handle event_mask -- int )
+    [ CHAR: E 0x93 ] dip IOW call-ioctl-out ;
+! EVIOCSCLOCKID
+: evdev-set-clock-id ( handle n -- int )
+    [ CHAR: E 0xa0 ] dip int <ref> IOW int ctype-ioctl-inout ;
+
+: evdev-get-bytes ( handle ev len -- bits )
+    [
+        [ IOC_READ CHAR: E ]
+        [ 0x20 + ]
+        [ IOC ] tri*
+    ] keep byte-array-ioctl ;
+
+ENUM: INPUT_PROP
+    { INPUT_PROP_POINTER                 0x00 }   ! needs a pointer
+    { INPUT_PROP_DIRECT                  0x01 }   ! direct input devices
+    { INPUT_PROP_BUTTONPAD               0x02 }   ! has button(s) under pad
+    { INPUT_PROP_SEMI_MT                 0x03 }   ! touch rectangle only
+    { INPUT_PROP_TOPBUTTONPAD            0x04 }   ! softbuttons at top of pad
+    { INPUT_PROP_POINTING_STICK          0x05 }   ! is a pointing stick
+    { INPUT_PROP_ACCELEROMETER           0x06 }   ! has accelerometer
+    { INPUT_PROP_MAX                     0x1f }
+    { INPUT_PROP_CNT                     0x20 } ; ! (INPUT_PROP_MAX + 1)
+
+! Type, 2nd parameter from /dev/input/event8
+ENUM: INPUT_EVENT
+    { EV_SYN            0x00 }   ! events
+    { EV_KEY            0x01 }   ! keys/buttons
+    { EV_REL            0x02 }   ! relative
+    { EV_ABS            0x03 }   ! absolute
+    { EV_MSC            0x04 }   ! miscellaneous
+    { EV_SW             0x05 }   ! switches
+    { EV_LED            0x11 }   ! LEDs
+    { EV_SND            0x12 }   ! sound
+    { EV_REP            0x14 }   ! autorepeat
+    { EV_FF             0x15 }   ! force feedback
+    { EV_PWR            0x16 }   ! power management
+    { EV_FF_STATUS      0x17 }   ! force feedback status
+    { EV_MAX            0x1f }   ! maximum
+    { EV_CNT            0x20 } ; ! EV_MAX + 1
+
+ENUM: INPUT_SYN
+    { SYN_REPORT          0 }
+    { SYN_CONFIG          1 }
+    { SYN_MT_REPORT       2 }
+    { SYN_DROPPED         3 }
+    { SYN_MAX          0x0f }
+    { SYN_CNT          0x10 } ; ! (SYN_MAX+1)
+
+! code, 3rd param
+ENUM: INPUT_KEY
+    { KEY_RESERVED                         0 }
+    { KEY_ESC                              1 }
+    { KEY_1                                2 }
+    { KEY_2                                3 }
+    { KEY_3                                4 }
+    { KEY_4                                5 }
+    { KEY_5                                6 }
+    { KEY_6                                7 }
+    { KEY_7                                8 }
+    { KEY_8                                9 }
+    { KEY_9                               10 }
+    { KEY_0                               11 }
+    { KEY_MINUS                           12 }
+    { KEY_EQUAL                           13 }
+    { KEY_BACKSPACE                       14 }
+    { KEY_TAB                             15 }
+    { KEY_Q                               16 }
+    { KEY_W                               17 }
+    { KEY_E                               18 }
+    { KEY_R                               19 }
+    { KEY_T                               20 }
+    { KEY_Y                               21 }
+    { KEY_U                               22 }
+    { KEY_I                               23 }
+    { KEY_O                               24 }
+    { KEY_P                               25 }
+    { KEY_LEFTBRACE                       26 }
+    { KEY_RIGHTBRACE                      27 }
+    { KEY_ENTER                           28 }
+    { KEY_LEFTCTRL                        29 }
+    { KEY_A                               30 }
+    { KEY_S                               31 }
+    { KEY_D                               32 }
+    { KEY_F                               33 }
+    { KEY_G                               34 }
+    { KEY_H                               35 }
+    { KEY_J                               36 }
+    { KEY_K                               37 }
+    { KEY_L                               38 }
+    { KEY_SEMICOLON                       39 }
+    { KEY_APOSTROPHE                      40 }
+    { KEY_GRAVE                           41 }
+    { KEY_LEFTSHIFT                       42 }
+    { KEY_BACKSLASH                       43 }
+    { KEY_Z                               44 }
+    { KEY_X                               45 }
+    { KEY_C                               46 }
+    { KEY_V                               47 }
+    { KEY_B                               48 }
+    { KEY_N                               49 }
+    { KEY_M                               50 }
+    { KEY_COMMA                           51 }
+    { KEY_DOT                             52 }
+    { KEY_SLASH                           53 }
+    { KEY_RIGHTSHIFT                      54 }
+    { KEY_KPASTERISK                      55 }
+    { KEY_LEFTALT                         56 }
+    { KEY_SPACE                           57 }
+    { KEY_CAPSLOCK                        58 }
+    { KEY_F1                              59 }
+    { KEY_F2                              60 }
+    { KEY_F3                              61 }
+    { KEY_F4                              62 }
+    { KEY_F5                              63 }
+    { KEY_F6                              64 }
+    { KEY_F7                              65 }
+    { KEY_F8                              66 }
+    { KEY_F9                              67 }
+    { KEY_F10                             68 }
+    { KEY_NUMLOCK                         69 }
+    { KEY_SCROLLLOCK                      70 }
+    { KEY_KP7                             71 }
+    { KEY_KP8                             72 }
+    { KEY_KP9                             73 }
+    { KEY_KPMINUS                         74 }
+    { KEY_KP4                             75 }
+    { KEY_KP5                             76 }
+    { KEY_KP6                             77 }
+    { KEY_KPPLUS                          78 }
+    { KEY_KP1                             79 }
+    { KEY_KP2                             80 }
+    { KEY_KP3                             81 }
+    { KEY_KP0                             82 }
+    { KEY_KPDOT                           83 }
+    { KEY_ZENKAKUHANKAKU                  85 }
+    { KEY_102ND                           86 }
+    { KEY_F11                             87 }
+    { KEY_F12                             88 }
+    { KEY_RO                              89 }
+    { KEY_KATAKANA                        90 }
+    { KEY_HIRAGANA                        91 }
+    { KEY_HENKAN                          92 }
+    { KEY_KATAKANAHIRAGANA                93 }
+    { KEY_MUHENKAN                        94 }
+    { KEY_KPJPCOMMA                       95 }
+    { KEY_KPENTER                         96 }
+    { KEY_RIGHTCTRL                       97 }
+    { KEY_KPSLASH                         98 }
+    { KEY_SYSRQ                           99 }
+    { KEY_RIGHTALT                       100 }
+    { KEY_LINEFEED                       101 }
+    { KEY_HOME                           102 }
+    { KEY_UP                             103 }
+    { KEY_PAGEUP                         104 }
+    { KEY_LEFT                           105 }
+    { KEY_RIGHT                          106 }
+    { KEY_END                            107 }
+    { KEY_DOWN                           108 }
+    { KEY_PAGEDOWN                       109 }
+    { KEY_INSERT                         110 }
+    { KEY_DELETE                         111 }
+    { KEY_MACRO                          112 }
+    { KEY_MUTE                           113 }
+    { KEY_VOLUMEDOWN                     114 }
+    { KEY_VOLUMEUP                       115 }
+    { KEY_POWER                          116 }    ! SC System Power Down
+    { KEY_KPEQUAL                        117 }
+    { KEY_KPPLUSMINUS                    118 }
+    { KEY_PAUSE                          119 }
+    { KEY_SCALE                          120 }    ! AL Compiz Scale (Expose)
+    { KEY_KPCOMMA                        121 }
+    { KEY_HANGEUL                        122 }
+    { KEY_HANJA                          123 }
+    { KEY_YEN                            124 }
+    { KEY_LEFTMETA                       125 }
+    { KEY_RIGHTMETA                      126 }
+    { KEY_COMPOSE                        127 }
+    { KEY_STOP                           128 }    ! AC Stop
+    { KEY_AGAIN                          129 }
+    { KEY_PROPS                          130 }    ! AC Properties
+    { KEY_UNDO                           131 }    ! AC Undo
+    { KEY_FRONT                          132 }
+    { KEY_COPY                           133 }    ! AC Copy
+    { KEY_OPEN                           134 }    ! AC Open
+    { KEY_PASTE                          135 }    ! AC Paste
+    { KEY_FIND                           136 }    ! AC Search
+    { KEY_CUT                            137 }    ! AC Cut
+    { KEY_HELP                           138 }    ! AL Integrated Help Center
+    { KEY_MENU                           139 }    ! Menu (show menu)
+    { KEY_CALC                           140 }    ! AL Calculator
+    { KEY_SETUP                          141 }
+    { KEY_SLEEP                          142 }    ! SC System Sleep
+    { KEY_WAKEUP                         143 }    ! System Wake Up
+    { KEY_FILE                           144 }    ! AL Local Machine Browser
+    { KEY_SENDFILE                       145 }
+    { KEY_DELETEFILE                     146 }
+    { KEY_XFER                           147 }
+    { KEY_PROG1                          148 }
+    { KEY_PROG2                          149 }
+    { KEY_WWW                            150 }    ! AL Internet Browser
+    { KEY_MSDOS                          151 }
+    { KEY_COFFEE                         152 }    ! AL Terminal Lock/Screensaver
+    { KEY_ROTATE_DISPLAY                 153 }    ! Display orientation for e.g. tablets
+    { KEY_CYCLEWINDOWS                   154 }
+    { KEY_MAIL                           155 }
+    { KEY_BOOKMARKS                      156 }    ! AC Bookmarks
+    { KEY_COMPUTER                       157 }
+    { KEY_BACK                           158 }    ! AC Back
+    { KEY_FORWARD                        159 }    ! AC Forward
+    { KEY_CLOSECD                        160 }
+    { KEY_EJECTCD                        161 }
+    { KEY_EJECTCLOSECD                   162 }
+    { KEY_NEXTSONG                       163 }
+    { KEY_PLAYPAUSE                      164 }
+    { KEY_PREVIOUSSONG                   165 }
+    { KEY_STOPCD                         166 }
+    { KEY_RECORD                         167 }
+    { KEY_REWIND                         168 }
+    { KEY_PHONE                          169 }    ! Media Select Telephone
+    { KEY_ISO                            170 }
+    { KEY_CONFIG                         171 }    ! AL Consumer Control Configuration
+    { KEY_HOMEPAGE                       172 }    ! AC Home
+    { KEY_REFRESH                        173 }    ! AC Refresh
+    { KEY_EXIT                           174 }    ! AC Exit
+    { KEY_MOVE                           175 }
+    { KEY_EDIT                           176 }
+    { KEY_SCROLLUP                       177 }
+    { KEY_SCROLLDOWN                     178 }
+    { KEY_KPLEFTPAREN                    179 }
+    { KEY_KPRIGHTPAREN                   180 }
+    { KEY_NEW                            181 }    ! AC New
+    { KEY_REDO                           182 }    ! AC Redo/Repeat
+    { KEY_F13                            183 }
+    { KEY_F14                            184 }
+    { KEY_F15                            185 }
+    { KEY_F16                            186 }
+    { KEY_F17                            187 }
+    { KEY_F18                            188 }
+    { KEY_F19                            189 }
+    { KEY_F20                            190 }
+    { KEY_F21                            191 }
+    { KEY_F22                            192 }
+    { KEY_F23                            193 }
+    { KEY_F24                            194 }
+    { KEY_PLAYCD                         200 }
+    { KEY_PAUSECD                        201 }
+    { KEY_PROG3                          202 }
+    { KEY_PROG4                          203 }
+    { KEY_DASHBOARD                      204 }    ! AL Dashboard
+    { KEY_SUSPEND                        205 }
+    { KEY_CLOSE                          206 }    ! AC Close
+    { KEY_PLAY                           207 }
+    { KEY_FASTFORWARD                    208 }
+    { KEY_BASSBOOST                      209 }
+    { KEY_PRINT                          210 }    ! AC Print
+    { KEY_HP                             211 }
+    { KEY_CAMERA                         212 }
+    { KEY_SOUND                          213 }
+    { KEY_QUESTION                       214 }
+    { KEY_EMAIL                          215 }
+    { KEY_CHAT                           216 }
+    { KEY_SEARCH                         217 }
+    { KEY_CONNECT                        218 }
+    { KEY_FINANCE                        219 }    ! AL Checkbook/Finance
+    { KEY_SPORT                          220 }
+    { KEY_SHOP                           221 }
+    { KEY_ALTERASE                       222 }
+    { KEY_CANCEL                         223 }    ! AC Cancel
+    { KEY_BRIGHTNESSDOWN                 224 }
+    { KEY_BRIGHTNESSUP                   225 }
+    { KEY_MEDIA                          226 }
+    { KEY_SWITCHVIDEOMODE                227 }    ! Cycle between available video
+                                                  ! outputs (Monitor/LCD/TV-out/etc)
+    { KEY_KBDILLUMTOGGLE                 228 }
+    { KEY_KBDILLUMDOWN                   229 }
+    { KEY_KBDILLUMUP                     230 }
+    { KEY_SEND                           231 }    ! AC Send
+    { KEY_REPLY                          232 }    ! AC Reply
+    { KEY_FORWARDMAIL                    233 }    ! AC Forward Msg
+    { KEY_SAVE                           234 }    ! AC Save
+    { KEY_DOCUMENTS                      235 }
+    { KEY_BATTERY                        236 }
+    { KEY_BLUETOOTH                      237 }
+    { KEY_WLAN                           238 }
+    { KEY_UWB                            239 }
+    { KEY_UNKNOWN                        240 }
+    { KEY_VIDEO_NEXT                     241 }    ! drive next video source
+    { KEY_VIDEO_PREV                     242 }    ! drive previous video source
+    { KEY_BRIGHTNESS_CYCLE               243 }    ! brightness up, after max is min
+    { KEY_BRIGHTNESS_AUTO                244 }    ! Set Auto Brightness: manual
+                                                  ! brightness control is off,
+                                                  ! rely on ambient
+    { KEY_DISPLAY_OFF                    245 }   ! display device to off state
+    { KEY_WWAN                           246 }   ! Wireless WAN (LTE, UMTS, GSM, etc.)
+    { KEY_RFKILL                         247 }   ! Key that controls all radios
+    { KEY_MICMUTE                        248 }   ! Mute / unmute the microphone
+! Code 255 is reserved for special needs of AT keyboard driver
+    { BTN_0                        0x100 }
+    { BTN_1                        0x101 }
+    { BTN_2                        0x102 }
+    { BTN_3                        0x103 }
+    { BTN_4                        0x104 }
+    { BTN_5                        0x105 }
+    { BTN_6                        0x106 }
+    { BTN_7                        0x107 }
+    { BTN_8                        0x108 }
+    { BTN_9                        0x109 }
+    { BTN_MOUSE                    0x110 }
+    { BTN_LEFT                     0x110 }
+    { BTN_RIGHT                    0x111 }
+    { BTN_MIDDLE                   0x112 }
+    { BTN_SIDE                     0x113 }
+    { BTN_EXTRA                    0x114 }
+    { BTN_FORWARD                  0x115 }
+    { BTN_BACK                     0x116 }
+    { BTN_TASK                     0x117 }
+    { BTN_TRIGGER                  0x120 }
+    { BTN_JOYSTICK                 0x120 } ! Button 1
+    { BTN_THUMB                    0x121 }
+    { BTN_THUMB2                   0x122 }
+    { BTN_TOP                      0x123 }
+    { BTN_TOP2                     0x124 }
+    { BTN_PINKIE                   0x125 }
+    { BTN_BASE                     0x126 }
+    { BTN_BASE2                    0x127 }
+    { BTN_BASE3                    0x128 }
+    { BTN_BASE4                    0x129 }
+    { BTN_BASE5                    0x12a }
+    { BTN_BASE6                    0x12b }
+    { BTN_BASE7                    0x12c } ! not defined by linux
+    { BTN_BASE8                    0x12d } ! not defined by linux
+    { BTN_BASE9                    0x12e } ! not defined by linux
+    { BTN_DEAD                     0x12f }
+    { BTN_A                        0x130 }
+    { BTN_B                        0x131 }
+    { BTN_C                        0x132 }
+    { BTN_X                        0x133 }
+    { BTN_Y                        0x134 }
+    { BTN_Z                        0x135 }
+    { BTN_TL                       0x136 }
+    { BTN_TR                       0x137 }
+    { BTN_TL2                      0x138 }
+    { BTN_TR2                      0x139 }
+    { BTN_SELECT                   0x13a }
+    { BTN_START                    0x13b }
+    { BTN_MODE                     0x13c }
+    { BTN_THUMBL                   0x13d }
+    { BTN_THUMBR                   0x13e }
+    { BTN_TOOL_PEN                 0x140 }
+    { BTN_TOOL_RUBBER              0x141 }
+    { BTN_TOOL_BRUSH               0x142 }
+    { BTN_TOOL_PENCIL              0x143 }
+    { BTN_TOOL_AIRBRUS             0x144 }
+    { BTN_TOOL_FINGER              0x145 }
+    { BTN_TOOL_MOUSE               0x146 }
+    { BTN_TOOL_LENS                0x147 }
+    { BTN_TOOL_QUINTTA             0x148 }    ! Five fingers on trackpad
+    { BTN_STYLUS3                  0x149 }
+    { BTN_TOUCH                    0x14a }
+    { BTN_STYLUS                   0x14b }
+    { BTN_STYLUS2                  0x14c }
+    { BTN_TOOL_DOUBLETAP           0x14d }
+    { BTN_TOOL_TRIPLETAP           0x14e }
+    { BTN_TOOL_QUADTAP             0x14f }    ! Four fingers on trackpad
+    { BTN_WHEEL                    0x150 }
+    { BTN_GEAR_DOWN                0x150 }
+    { BTN_GEAR_UP                  0x151 }
+    { KEY_OK                       0x160 }
+    { KEY_SELECT                   0x161 }
+    { KEY_GOTO                     0x162 }
+    { KEY_CLEAR                    0x163 }
+    { KEY_POWER2                   0x164 }
+    { KEY_OPTION                   0x165 }
+    { KEY_INFO                     0x166 }    ! AL OEM Features/Tips/Tutorial
+    { KEY_TIME                     0x167 }
+    { KEY_VENDOR                   0x168 }
+    { KEY_ARCHIVE                  0x169 }
+    { KEY_PROGRAM                  0x16a }    ! Media Select Program Guide
+    { KEY_CHANNEL                  0x16b }
+    { KEY_FAVORITES                0x16c }
+    { KEY_EPG                      0x16d }
+    { KEY_PVR                      0x16e }    ! Media Select Home
+    { KEY_MHP                      0x16f }
+    { KEY_LANGUAGE                 0x170 }
+    { KEY_TITLE                    0x171 }
+    { KEY_SUBTITLE                 0x172 }
+    { KEY_ANGLE                    0x173 }
+    { KEY_ZOOM                     0x174 }
+    { KEY_MODE                     0x175 }
+    { KEY_KEYBOARD                 0x176 }
+    { KEY_SCREEN                   0x177 }
+    { KEY_PC                       0x178 }    ! Media Select Computer
+    { KEY_TV                       0x179 }    ! Media Select TV
+    { KEY_TV2                      0x17a }    ! Media Select Cable
+    { KEY_VCR                      0x17b }    ! Media Select VCR
+    { KEY_VCR2                     0x17c }    ! VCR Plus
+    { KEY_SAT                      0x17d }    ! Media Select Satellite
+    { KEY_SAT2                     0x17e }
+    { KEY_CD                       0x17f }    ! Media Select CD
+    { KEY_TAPE                     0x180 }    ! Media Select Tape
+    { KEY_RADIO                    0x181 }
+    { KEY_TUNER                    0x182 }    ! Media Select Tuner
+    { KEY_PLAYER                   0x183 }
+    { KEY_TEXT                     0x184 }
+    { KEY_DVD                      0x185 }    ! Media Select DVD
+    { KEY_AUX                      0x186 }
+    { KEY_MP3                      0x187 }
+    { KEY_AUDIO                    0x188 }    ! AL Audio Browser
+    { KEY_VIDEO                    0x189 }    ! AL Movie Browser
+    { KEY_DIRECTORY                0x18a }
+    { KEY_LIST                     0x18b }
+    { KEY_MEMO                     0x18c }    ! Media Select Messages
+    { KEY_CALENDAR                 0x18d }
+    { KEY_RED                      0x18e }
+    { KEY_GREEN                    0x18f }
+    { KEY_YELLOW                   0x190 }
+    { KEY_BLUE                     0x191 }
+    { KEY_CHANNELUP                0x192 }    ! Channel Increment
+    { KEY_CHANNELDOWN              0x193 }    ! Channel Decrement
+    { KEY_FIRST                    0x194 }
+    { KEY_LAST                     0x195 }    ! Recall Last
+    { KEY_AB                       0x196 }
+    { KEY_NEXT                     0x197 }
+    { KEY_RESTART                  0x198 }
+    { KEY_SLOW                     0x199 }
+    { KEY_SHUFFLE                  0x19a }
+    { KEY_BREAK                    0x19b }
+    { KEY_PREVIOUS                 0x19c }
+    { KEY_DIGITS                   0x19d }
+    { KEY_TEEN                     0x19e }
+    { KEY_TWEN                     0x19f }
+    { KEY_VIDEOPHONE               0x1a0 }    ! Media Select Video Phone
+    { KEY_GAMES                    0x1a1 }    ! Media Select Games
+    { KEY_ZOOMIN                   0x1a2 }    ! AC Zoom In
+    { KEY_ZOOMOUT                  0x1a3 }    ! AC Zoom Out
+    { KEY_ZOOMRESET                0x1a4 }    ! AC Zoom
+    { KEY_WORDPROCESSOR            0x1a5 }    ! AL Word Processor
+    { KEY_EDITOR                   0x1a6 }    ! AL Text Editor
+    { KEY_SPREADSHEET              0x1a7 }    ! AL Spreadsheet
+    { KEY_GRAPHICSEDITOR           0x1a8 }    ! AL Graphics Editor
+    { KEY_PRESENTATION             0x1a9 }    ! AL Presentation App
+    { KEY_DATABASE                 0x1aa }    ! AL Database App
+    { KEY_NEWS                     0x1ab }    ! AL Newsreader
+    { KEY_VOICEMAIL                0x1ac }    ! AL Voicemail
+    { KEY_ADDRESSBOOK              0x1ad }    ! AL Contacts/Address Book
+    { KEY_MESSENGER                0x1ae }    ! AL Instant Messaging
+    { KEY_DISPLAYTOGGLE            0x1af }    ! Turn display (LCD) on and off
+    { KEY_SPELLCHECK               0x1b0 }    ! AL Spell Check
+    { KEY_LOGOFF                   0x1b1 }    ! AL Logoff
+    { KEY_DOLLAR                   0x1b2 }
+    { KEY_EURO                     0x1b3 }
+    { KEY_FRAMEBACK                0x1b4 }    ! Consumer - transport controls
+    { KEY_FRAMEFORWARD             0x1b5 }
+    { KEY_CONTEXT_MENU             0x1b6 }    ! GenDesc - system context menu
+    { KEY_MEDIA_REPEAT             0x1b7 }    ! Consumer - transport control
+    { KEY_10CHANNELSUP             0x1b8 }    ! 10 channels up (10+)
+    { KEY_10CHANNELSDOWN           0x1b9 }    ! 10 channels down (10-)
+    { KEY_IMAGES                   0x1ba }    ! AL Image Browser
+    { KEY_DEL_EOL                  0x1c0 }
+    { KEY_DEL_EOS                  0x1c1 }
+    { KEY_INS_LINE                 0x1c2 }
+    { KEY_DEL_LINE                 0x1c3 }
+    { KEY_FN                       0x1d0 }
+    { KEY_FN_ESC                   0x1d1 }
+    { KEY_FN_F1                    0x1d2 }
+    { KEY_FN_F2                    0x1d3 }
+    { KEY_FN_F3                    0x1d4 }
+    { KEY_FN_F4                    0x1d5 }
+    { KEY_FN_F5                    0x1d6 }
+    { KEY_FN_F6                    0x1d7 }
+    { KEY_FN_F7                    0x1d8 }
+    { KEY_FN_F8                    0x1d9 }
+    { KEY_FN_F9                    0x1da }
+    { KEY_FN_F10                   0x1db }
+    { KEY_FN_F11                   0x1dc }
+    { KEY_FN_F12                   0x1dd }
+    { KEY_FN_1                     0x1de }
+    { KEY_FN_2                     0x1df }
+    { KEY_FN_D                     0x1e0 }
+    { KEY_FN_E                     0x1e1 }
+    { KEY_FN_F                     0x1e2 }
+    { KEY_FN_S                     0x1e3 }
+    { KEY_FN_B                     0x1e4 }
+    { KEY_BRL_DOT1                 0x1f1 }
+    { KEY_BRL_DOT2                 0x1f2 }
+    { KEY_BRL_DOT3                 0x1f3 }
+    { KEY_BRL_DOT4                 0x1f4 }
+    { KEY_BRL_DOT5                 0x1f5 }
+    { KEY_BRL_DOT6                 0x1f6 }
+    { KEY_BRL_DOT7                 0x1f7 }
+    { KEY_BRL_DOT8                 0x1f8 }
+    { KEY_BRL_DOT9                 0x1f9 }
+    { KEY_BRL_DOT10                0x1fa }
+    { KEY_NUMERIC_0                0x200 }    ! used by phones, remote controls,
+    { KEY_NUMERIC_1                0x201 }    ! and other keypads
+    { KEY_NUMERIC_2                0x202 }
+    { KEY_NUMERIC_3                0x203 }
+    { KEY_NUMERIC_4                0x204 }
+    { KEY_NUMERIC_5                0x205 }
+    { KEY_NUMERIC_6                0x206 }
+    { KEY_NUMERIC_7                0x207 }
+    { KEY_NUMERIC_8                0x208 }
+    { KEY_NUMERIC_9                0x209 }
+    { KEY_NUMERIC_STAR             0x20a }
+    { KEY_NUMERIC_POUND            0x20b }
+    { KEY_NUMERIC_A                0x20c }    ! Phone key A - HUT Telephony 0xb9
+    { KEY_NUMERIC_B                0x20d }
+    { KEY_NUMERIC_C                0x20e }
+    { KEY_NUMERIC_D                0x20f }
+    { KEY_CAMERA_FOCUS             0x210 }
+    { KEY_WPS_BUTTON               0x211 }    ! WiFi Protected Setup key
+    { KEY_TOUCHPAD_TOGGLE          0x212 }    ! Request switch touchpad on or off
+    { KEY_TOUCHPAD_ON              0x213 }
+    { KEY_TOUCHPAD_OFF             0x214 }
+    { KEY_CAMERA_ZOOMIN            0x215 }
+    { KEY_CAMERA_ZOOMOUT           0x216 }
+    { KEY_CAMERA_UP                0x217 }
+    { KEY_CAMERA_DOWN              0x218 }
+    { KEY_CAMERA_LEFT              0x219 }
+    { KEY_CAMERA_RIGHT             0x21a }
+    { KEY_ATTENDANT_ON             0x21b }
+    { KEY_ATTENDANT_OFF            0x21c }
+    { KEY_ATTENDANT_TOGGLE         0x21d }    ! Attendant call on or off
+    { KEY_LIGHTS_TOGGLE            0x21e }    ! Reading light on or off
+    { BTN_DPAD_UP                  0x220 }
+    { BTN_DPAD_DOWN                0x221 }
+    { BTN_DPAD_LEFT                0x222 }
+    { BTN_DPAD_RIGHT               0x223 }
+    { KEY_ALS_TOGGLE               0x230 }    ! Ambient light sensor
+    { KEY_ROTATE_LOCK_TOGGLE       0x231 }    ! Display rotation lock
+    { KEY_BUTTONCONFIG             0x240 }    ! AL Button Configuration
+    { KEY_TASKMANAGER              0x241 }    ! AL Task/Project Manager
+    { KEY_JOURNAL                  0x242 }    ! AL Log/Journal/Timecard
+    { KEY_CONTROLPANEL             0x243 }    ! AL Control Panel
+    { KEY_APPSELECT                0x244 }    ! AL Select Task/Application
+    { KEY_SCREENSAVER              0x245 }    ! AL Screen Saver
+    { KEY_VOICECOMMAND             0x246 }    ! Listening Voice Command
+    { KEY_ASSISTANT                0x247 }    ! AL Context-aware desktop assistant
+    { KEY_BRIGHTNESS_MIN           0x250 }    ! Set Brightness to Minimum
+    { KEY_BRIGHTNESS_MAX           0x251 }    ! Set Brightness to Maximum
+    { KEY_KBDINPUTASSIST_PREV      0x260 }
+    { KEY_KBDINPUTASSIST_NEXT      0x261 }
+    { KEY_KBDINPUTASSIST_PREVGROUP 0x262 }
+    { KEY_KBDINPUTASSIST_NEXTGROUP 0x263 }
+    { KEY_KBDINPUTASSIST_ACCEPT    0x264 }
+    { KEY_KBDINPUTASSIST_CANCEL    0x265 }
+! Diagonal movement keys
+    { KEY_RIGHT_UP                 0x266 }
+    { KEY_RIGHT_DOWN               0x267 }
+    { KEY_LEFT_UP                  0x268 }
+    { KEY_LEFT_DOWN                0x269 }
+    { KEY_ROOT_MENU                0x26a }    ! Show Device's Root Menu
+! Show Top Menu of the Media (e.g. DVD)
+    { KEY_MEDIA_TOP_MENU           0x26b }
+    { KEY_NUMERIC_11               0x26c }
+    { KEY_NUMERIC_12               0x26d }
+! Toggle Audio Description: refers to an audio service that helps blind and
+! visually impaired consumers understand the action in a program. Note: in
+! some countries this is referred to as "Video Description".
+    { KEY_AUDIO_DESC               0x26e }
+    { KEY_3D_MODE                  0x26f }
+    { KEY_NEXT_FAVORITE            0x270 }
+    { KEY_STOP_RECORD              0x271 }
+    { KEY_PAUSE_RECORD             0x272 }
+    { KEY_VOD                      0x273 }    ! Video on Demand
+    { KEY_UNMUTE                   0x274 }
+    { KEY_FASTREVERSE              0x275 }
+    { KEY_SLOWREVERSE              0x276 }
+! Control a data application associated with the currently viewed channel,
+! e.g. teletext or data broadcast application (MHEG, MHP, HbbTV, etc.)
+    { KEY_DATA                     0x277 }
+    { KEY_ONSCREEN_KEYBOARD        0x278 }
+    { BTN_TRIGGER_HAPPY            0x2c0 }
+    { BTN_TRIGGER_HAPPY1           0x2c0 }
+    { BTN_TRIGGER_HAPPY2           0x2c1 }
+    { BTN_TRIGGER_HAPPY3           0x2c2 }
+    { BTN_TRIGGER_HAPPY4           0x2c3 }
+    { BTN_TRIGGER_HAPPY5           0x2c4 }
+    { BTN_TRIGGER_HAPPY6           0x2c5 }
+    { BTN_TRIGGER_HAPPY7           0x2c6 }
+    { BTN_TRIGGER_HAPPY8           0x2c7 }
+    { BTN_TRIGGER_HAPPY9           0x2c8 }
+    { BTN_TRIGGER_HAPPY10          0x2c9 }
+    { BTN_TRIGGER_HAPPY11          0x2ca }
+    { BTN_TRIGGER_HAPPY12          0x2cb }
+    { BTN_TRIGGER_HAPPY13          0x2cc }
+    { BTN_TRIGGER_HAPPY14          0x2cd }
+    { BTN_TRIGGER_HAPPY15          0x2ce }
+    { BTN_TRIGGER_HAPPY16          0x2cf }
+    { BTN_TRIGGER_HAPPY17          0x2d0 }
+    { BTN_TRIGGER_HAPPY18          0x2d1 }
+    { BTN_TRIGGER_HAPPY19          0x2d2 }
+    { BTN_TRIGGER_HAPPY20          0x2d3 }
+    { BTN_TRIGGER_HAPPY21          0x2d4 }
+    { BTN_TRIGGER_HAPPY22          0x2d5 }
+    { BTN_TRIGGER_HAPPY23          0x2d6 }
+    { BTN_TRIGGER_HAPPY24          0x2d7 }
+    { BTN_TRIGGER_HAPPY25          0x2d8 }
+    { BTN_TRIGGER_HAPPY26          0x2d9 }
+    { BTN_TRIGGER_HAPPY27          0x2da }
+    { BTN_TRIGGER_HAPPY28          0x2db }
+    { BTN_TRIGGER_HAPPY29          0x2dc }
+    { BTN_TRIGGER_HAPPY30          0x2dd }
+    { BTN_TRIGGER_HAPPY31          0x2de }
+    { BTN_TRIGGER_HAPPY32          0x2df }
+    { BTN_TRIGGER_HAPPY33          0x2e0 }
+    { BTN_TRIGGER_HAPPY34          0x2e1 }
+    { BTN_TRIGGER_HAPPY35          0x2e2 }
+    { BTN_TRIGGER_HAPPY36          0x2e3 }
+    { BTN_TRIGGER_HAPPY37          0x2e4 }
+    { BTN_TRIGGER_HAPPY38          0x2e5 }
+    { BTN_TRIGGER_HAPPY39          0x2e6 }
+    { BTN_TRIGGER_HAPPY40          0x2e7 }
+! We avoid low common keys in module aliases so they don't get huge.
+    { KEY_MAX                      0x2ff }
+    { KEY_CNT                      0x300 } ;    ! (KEY_MAX+1)
+
+CONSTANT: BTN_GAMEPAD              0x130
+CONSTANT: BTN_DIGI                 0x140
+CONSTANT: KEY_MIN_INTERESTING      KEY_MUTE
+CONSTANT: KEY_HANGUEL              KEY_HANGEUL
+CONSTANT: KEY_SCREENLOCK           KEY_COFFEE
+CONSTANT: KEY_DIRECTION            KEY_ROTATE_DISPLAY
+CONSTANT: KEY_BRIGHTNESS_ZERO      KEY_BRIGHTNESS_AUTO
+CONSTANT: KEY_WIMAX                KEY_WWAN
+CONSTANT: KEY_BRIGHTNESS_TOGGLE    KEY_DISPLAYTOGGLE
+CONSTANT: BTN_MISC                 0x100
+CONSTANT: BTN_SOUTH                BTN_A
+CONSTANT: BTN_EAST                 BTN_B
+CONSTANT: BTN_NORTH                BTN_X
+CONSTANT: BTN_WEST                 BTN_Y
+
+! Relative axes
+! 3rd param
+ENUM: INPUT_REL
+    { REL_X                        0x00 }
+    { REL_Y                        0x01 }
+    { REL_Z                        0x02 }
+    { REL_RX                       0x03 }
+    { REL_RY                       0x04 }
+    { REL_RZ                       0x05 }
+    { REL_HWHEEL                   0x06 }
+    { REL_DIAL                     0x07 }
+    { REL_WHEEL                    0x08 }
+    { REL_MISC                     0x09 }
+    { REL_RESERVED                 0x0a }
+    { REL_WHEEL_HI_RES             0x0b }
+    { REL_HWHEEL_HI_RES            0x0c }
+    { REL_MAX                      0x0f }
+    { REL_CNT                      0x10 } ;     ! (REL_MAX+1)
+
+! Absolute axes
+ENUM: INPUT_ABS
+    { ABS_X                        0x00 }
+    { ABS_Y                        0x01 }
+    { ABS_Z                        0x02 }
+    { ABS_RX                       0x03 }
+    { ABS_RY                       0x04 }
+    { ABS_RZ                       0x05 }
+    { ABS_THROTTLE                 0x06 }
+    { ABS_RUDDER                   0x07 }
+    { ABS_WHEEL                    0x08 }
+    { ABS_GAS                      0x09 }
+    { ABS_BRAKE                    0x0a }
+    { ABS_HAT0X                    0x10 }
+    { ABS_HAT0Y                    0x11 }
+    { ABS_HAT1X                    0x12 }
+    { ABS_HAT1Y                    0x13 }
+    { ABS_HAT2X                    0x14 }
+    { ABS_HAT2Y                    0x15 }
+    { ABS_HAT3X                    0x16 }
+    { ABS_HAT3Y                    0x17 }
+    { ABS_PRESSURE                 0x18 }
+    { ABS_DISTANCE                 0x19 }
+    { ABS_TILT_X                   0x1a }
+    { ABS_TILT_Y                   0x1b }
+    { ABS_TOOL_WIDTH               0x1c }
+    { ABS_VOLUME                   0x20 }
+    { ABS_MISC                     0x28 }
+    { ABS_MT_SLOT                  0x2f }    ! MT slot being modified
+    { ABS_MT_TOUCH_MAJOR           0x30 }    ! Major axis of touching ellipse
+    { ABS_MT_TOUCH_MINOR           0x31 }    ! Minor axis (omit if circular)
+    { ABS_MT_WIDTH_MAJOR           0x32 }    ! Major axis of approaching ellipse
+    { ABS_MT_WIDTH_MINOR           0x33 }    ! Minor axis (omit if circular)
+    { ABS_MT_ORIENTATION           0x34 }    ! Ellipse orientation
+    { ABS_MT_POSITION_X            0x35 }    ! Center X touch position
+    { ABS_MT_POSITION_Y            0x36 }    ! Center Y touch position
+    { ABS_MT_TOOL_TYPE             0x37 }    ! Type of touching device
+    { ABS_MT_BLOB_ID               0x38 }    ! Group a set of packets as a blob
+    { ABS_MT_TRACKING_ID           0x39 }    ! Unique ID of initiated contact
+    { ABS_MT_PRESSURE              0x3a }    ! Pressure on contact area
+    { ABS_MT_DISTANCE              0x3b }    ! Contact hover distance
+    { ABS_MT_TOOL_X                0x3c }    ! Center X tool position
+    { ABS_MT_TOOL_Y                0x3d }    ! Center Y tool position
+    { ABS_MAX                      0x3f }
+    { ABS_CNT                      0x40 } ;    ! (ABS_MAX+1)
+
+! Switch events
+ENUM: INPUT_SW
+    { SW_LID                       0x00 }    ! set = lid shut
+    { SW_TABLET_MODE               0x01 }    ! set = tablet mode
+    { SW_HEADPHONE_INSERT          0x02 }    ! set = inserted
+    { SW_RFKILL_ALL                0x03 }    ! rfkill master switch, type "any"
+                                             ! set = radio enabled
+    { SW_MICROPHONE_INSERT         0x04 }    ! set = inserted
+    { SW_DOCK                      0x05 }    ! set = plugged into dock
+    { SW_LINEOUT_INSERT            0x06 }    ! set = inserted
+    { SW_JACK_PHYSICAL_INSERT      0x07 }    ! set = mechanical switch set
+    { SW_VIDEOOUT_INSERT           0x08 }    ! set = inserted
+    { SW_CAMERA_LENS_COVER         0x09 }    ! set = lens covered
+    { SW_KEYPAD_SLIDE              0x0a }    ! set = keypad slide out
+    { SW_FRONT_PROXIMITY           0x0b }    ! set = front proximity sensor active
+    { SW_ROTATE_LOCK               0x0c }    ! set = rotate locked/disabled
+    { SW_LINEIN_INSERT             0x0d }    ! set = inserted
+    { SW_MUTE_DEVICE               0x0e }    ! set = device disabled
+    { SW_PEN_INSERTED              0x0f }    ! set = pen inserted
+    { SW_MAX                       0x0f }
+    { SW_CNT                       0x10 } ;  ! (SW_MAX+1)
+
+CONSTANT: SW_RADIO                     SW_RFKILL_ALL  ! deprecated
+
+! Misc events
+ENUM: INPUT_MSC
+    { MSC_SERIAL                   0x00 }
+    { MSC_PULSELED                 0x01 }
+    { MSC_GESTURE                  0x02 }
+    { MSC_RAW                      0x03 }
+    { MSC_SCAN                     0x04 }
+    { MSC_TIMESTAMP                0x05 }
+    { MSC_MAX                      0x07 }
+    { MSC_CNT                      0x08 } ;  ! (MSC_MAX+1)
+
+ENUM: SCANCODES
+    { SCANCODE_BTN_LEFT 589825 }
+    { SCANCODE_BTN_RIGHT 589826 }
+    { SCANCODE_BTN_MIDDLE 589827 }
+    { SCANCODE_BTN_SIDE 589828 }
+    { SCANCODE_BTN_EXTRA 589829 } ;
+
+! LEDs
+ENUM: INPUT_LED
+    { LED_NUML                     0x00 }
+    { LED_CAPSL                    0x01 }
+    { LED_SCROLLL                  0x02 }
+    { LED_COMPOSE                  0x03 }
+    { LED_KANA                     0x04 }
+    { LED_SLEEP                    0x05 }
+    { LED_SUSPEND                  0x06 }
+    { LED_MUTE                     0x07 }
+    { LED_MISC                     0x08 }
+    { LED_MAIL                     0x09 }
+    { LED_CHARGING                 0x0a }
+    { LED_MAX                      0x0f }
+    { LED_CNT                      0x10 } ;  ! (LED_MAX+1)
+
+! Autorepeat values
+ENUM: INPUT_REP
+    { REP_DELAY                    0x00 }
+    { REP_PERIOD                   0x01 }
+    { REP_MAX                      0x01 }
+    { REP_CNT                      0x02 } ;  ! (REP_MAX+1)
+
+! Sounds
+ENUM: INPUT_SND
+    { SND_CLICK                    0x00 }
+    { SND_BELL                     0x01 }
+    { SND_TONE                     0x02 }
+    { SND_MAX                      0x07 }
+    { SND_CNT                      0x08 } ;  ! (SND_MAX+1)
+
+! Force feedback effect types
+ENUM: INPUT_FF
+    { FF_RUMBLE 0x50 }
+    { FF_PERIODIC 0x51 }
+    { FF_CONSTANT 0x52 }
+    { FF_SPRING 0x53 }
+    { FF_FRICTION 0x54 }
+    { FF_DAMPER 0x55 }
+    { FF_INERTIA  0x56 }
+    { FF_RAMP   0x57 }
+
+! FF_EFFECT_MIN FF_RUMBLE
+! FF_EFFECT_MAX FF_RAMP
+
+! Force feedback periodic effect types
+
+    { FF_SQUARE 0x58 }
+    { FF_TRIANGLE 0x59 }
+    { FF_SINE   0x5a                                                                                                                      }
+    { FF_SAW_UP 0x5b }
+    { FF_SAW_DOWN 0x5c }
+    { FF_CUSTOM 0x5d }
+
+! FF_WAVEFORM_MIN FF_SQUARE
+! FF_WAVEFORM_MAX FF_CUSTOM
+! Set ff device properties
+    { FF_GAIN   0x60 }
+    { FF_AUTOCENTER 0x61 }
+
+! ff->playback(effect_id = FF_GAIN) is the first effect_id to
+! cause a collision with another ff method, in this case ff->set_gain().
+! Therefore the greatest safe value for effect_id is FF_GAIN - 1,
+! and thus the total number of effects should never exceed FF_GAIN.
+
+! FF_MAX_EFFECTS  FF_GAIN
+    { FF_MAX    0x7f }
+    { FF_CNT    0x80 } ;
+
+ENUM: FF_STATUS
+    { FF_STATUS_STOPPED 0x00 }
+    { FF_STATUS_PLAYING 0x01 }
+    { FF_STATUS_MAX   0x01 } ;
+
diff --git a/extra/linux/input-events/ffi/platforms.txt b/extra/linux/input-events/ffi/platforms.txt
new file mode 100644 (file)
index 0000000..9c52cb3
--- /dev/null
@@ -0,0 +1 @@
+linux
\ No newline at end of file
diff --git a/extra/linux/input-events/input-events.factor b/extra/linux/input-events/input-events.factor
new file mode 100644 (file)
index 0000000..4a2096f
--- /dev/null
@@ -0,0 +1,175 @@
+! Copyright (C) 2021 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors alien alien.c-types alien.data alien.enums
+arrays ascii assocs combinators combinators.smart grouping
+hashtables io io.backend io.directories io.encodings.binary
+io.files io.files.links io.pathnames kernel
+linux.input-events.ffi math namespaces pack prettyprint
+sequences sequences.extras splitting unix.time ;
+FROM: io => read ;
+IN: linux.input-events
+
+: input-events-assoc ( path -- assoc )
+    dup '[
+        _ qualified-directory-files
+        [ read-link normalize-path ] map-zip
+    ] with-directory ;
+
+: input-events-by-id-assoc ( -- assoc )
+    "/dev/input/by-id/" input-events-assoc ;
+
+: input-events-by-path-assoc ( -- assoc )
+    "/dev/input/by-path/" input-events-assoc ;
+
+: devices-by-type-assoc ( -- assoc )
+    input-events-by-id-assoc [
+        first "-" split1-last nip
+        [ digit? ] trim-tail
+    ] collect-by ;
+
+: event-code-value ( type code value -- a b c )
+    [ <INPUT_EVENT> ] 2dip
+    pick {
+        { EV_SYN [ [ <INPUT_SYN> ] dip ] }
+        { EV_KEY [ [ <INPUT_KEY> ] dip ] }
+        { EV_REL [ [ <INPUT_REL> ] dip ] }
+        { EV_ABS [ [ <INPUT_ABS> ] dip ] }
+        { EV_MSC [ [ <INPUT_MSC> ] dip ] }
+        { EV_SW  [ [ <INPUT_SW> ] dip ] }
+        { EV_LED [ [ <INPUT_LED> ] dip ] }
+        { EV_SND [ [ <INPUT_SND> ] dip ] }
+        { EV_REP [ [ <INPUT_REP> ] dip ] }
+        { EV_FF [ [ <INPUT_FF> ] dip ] }
+        ! { EV_PWR [ [ <INPUT_PWR> ] dip ] }
+        ! { EV_FF_STATUS [ [ <INPUT_FF_STATUS> ] dip ] }
+        [ drop ]
+    } case ;
+
+: evdev-explode-bitfield ( handle ev count -- seq )
+    enum>number 8 /mod [ drop 1 + ] unless-zero evdev-get-bytes seq>explode-positions ;
+
+: evdev-get-syn ( handle -- seq )
+    0 EV_CNT evdev-explode-bitfield ;
+
+: EV>seq ( handle EV -- seq )
+    dup <INPUT_EVENT> {
+        { EV_SYN [ drop evdev-get-syn [ <INPUT_EVENT> ] map-zip ] }
+        { EV_KEY [ KEY_CNT evdev-explode-bitfield [ <INPUT_KEY> ] map-zip ] }
+        { EV_REL [ REL_CNT evdev-explode-bitfield [ <INPUT_REL> ] map-zip ] }
+        { EV_ABS [
+            [ ABS_CNT evdev-explode-bitfield ]
+            [ drop over [ evdev-get-abs ] with map ] 2bi
+            [ [ <INPUT_ABS> ] map-zip ] dip zip
+        ] }
+        { EV_MSC [ MSC_CNT evdev-explode-bitfield [ <INPUT_MSC> ] map-zip ] }
+        { EV_SW  [ SW_CNT evdev-explode-bitfield [ <INPUT_SW> ] map-zip ] }
+        { EV_LED [ LED_CNT evdev-explode-bitfield [ <INPUT_LED> ] map-zip ] }
+        { EV_SND [ SND_CNT evdev-explode-bitfield [ <INPUT_SND> ] map-zip ] }
+        { EV_REP [
+            drop evdev-get-repeat "II" unpack
+            [ <INPUT_REP> swap 2array ] map-index
+        ] }
+        { EV_FF [ FF_CNT evdev-explode-bitfield [ <INPUT_FF> ] map-zip ] }
+        ! { EV_PWR [ PWR_CNT evdev-explode-bitfield ] }
+        { EV_FF_STATUS [ FF_STATUS_MAX evdev-explode-bitfield ] }
+        ! [ nip drop "broken" ]
+    } case ;
+
+: evdev-get-all-bits ( handle -- all-bits )
+    dup evdev-get-syn
+    [
+        [ nip <INPUT_EVENT> ]
+        [ EV>seq ] 2bi 2array
+    ] with map >hashtable ;
+
+: evdev-get-all-mt-slots ( handle -- seq )
+    INPUT_ABS enum>values [
+        [ 65 int <c-array> ] dip
+        0 pick set-nth
+        [ byte-length ] keep evdev-get-mt-slots
+        [ 0 = ] trim-tail
+    ] with map sift
+    [ unclip <INPUT_ABS> swap 2array ] map ;
+
+: with-event-device ( ..x path quot: ( ..x path fd -- ..y ) -- ..y )
+    [ binary over ] dip '[
+        _ input-stream get handle>> fd>> @
+    ] with-file-reader ; inline
+
+: named ( value key -- pair )
+    swap 2array ; inline
+
+: get-event-device-info ( path -- hashtable )
+    [
+        '[
+            _ "path" named
+            _ {
+                [ evdev-get-id "id" named ]
+                [ evdev-get-name "name" named ]
+                [ evdev-get-physical "physical" named ]
+                [ evdev-get-unique "unique" named ]
+                [ evdev-get-prop "props" named ]
+                [ evdev-get-all-mt-slots "mt-slots" named ]
+                [ evdev-get-key seq>explode-positions [ <INPUT_KEY> ] map-zip "keys" named ]
+                [ evdev-get-led seq>explode-positions [ <INPUT_LED> ] map-zip "leds" named ]
+                [ evdev-get-sound seq>explode-positions [ <INPUT_SND> ] map-zip "sounds" named ]
+                [ evdev-get-switch seq>explode-positions [ <INPUT_SW> ] map-zip "switches" named ]
+                [ evdev-get-simulataneous-effects "effects" named ]
+                [ evdev-get-event-mask "event-mask" named ]
+                [ evdev-get-all-bits "capabilities" named ]
+            } cleave
+        ] output>array >hashtable
+    ] with-event-device ;
+
+: all-controller-stats ( -- seq )
+    input-events-by-id-assoc values
+    [ file-name "event" head? ] filter
+    [ get-event-device-info ] map ;
+
+: events-by-file-name ( -- hashtable )
+    all-controller-stats [ "path" of file-name ] collect-by ;
+
+: get-input-events-type ( str -- seq )
+    [ input-events-by-id-assoc ] dip
+    '[ first _ tail? ] filter ;
+
+: get-input-events-joysticks ( -- seq ) "event-joystick" get-input-events-type ;
+: get-input-events-keyboards ( -- seq ) "event-kbd" get-input-events-type ;
+: get-input-events-mice ( -- seq ) "event-mouse" get-input-events-type ;
+
+: read-input-events ( -- seq )
+    240 read-partial 24 group [
+        "QQSSi" unpack-le
+        2 cut
+        [ first2 <timeval> ]
+        [ first3 event-code-value ] bi* 4array
+    ] map ;
+
+SLOT: state
+SLOT: quit?
+
+: read-controller-loop ( controller -- )
+    [ path>> ] [ state>> ] [ ] tri
+    '[
+        2drop
+        [
+            _ read-input-events [
+                ! "." write
+                first4
+                [ drop ] 3dip spin {
+                    { EV_SYN [ dup SYN_REPORT = [ 2drop ] [ 2array . ] if ] }
+                    { EV_KEY [ over 1 = [ pick set-at ] [ nip over delete-at ] if ] }
+                    { EV_ABS [ pick set-at ] }
+                    { EV_REL [ swap 2array . ] }
+                    { EV_MSC [ swap 2array . ] }
+                    [
+                        "unhandled: " write 3array .
+                        ! 3drop
+                    ]
+                } case
+            ] each
+            . ! state
+            ! drop ! state
+            _ quit?>> not
+        ] loop
+    ] with-event-device ;
diff --git a/extra/linux/input-events/platforms.txt b/extra/linux/input-events/platforms.txt
new file mode 100644 (file)
index 0000000..5087d31
--- /dev/null
@@ -0,0 +1,2 @@
+linux
+