2017-09-21 22:34:24 -04:00
use device ::Device ;
use ffi ::* ;
use libc ::{ c_int , input_event } ;
use std ::fs ::File ;
use std ::io ::Read ;
use std ::collections ::HashMap ;
2017-11-15 01:08:38 -05:00
use { Error , Result } ;
2017-09-21 22:34:24 -04:00
// 1 is down, 0 is up
const DOWN : i32 = 1 ;
const UP : i32 = 0 ;
const INVERT_KEY_FLAG : char = '^' ;
const CAPS_MODIFY_KEY_FLAG : char = '*' ;
const HALF_KEY_SEPARATOR : char = ':' ;
const LEFTSHIFT_INDEX : usize = KEY_LEFTSHIFT as usize ;
const RIGHTSHIFT_INDEX : usize = KEY_RIGHTSHIFT as usize ;
const CAPSLOCK_INDEX : usize = KEY_CAPSLOCK as usize ;
const KEY_LEFTSHIFT_U16 : u16 = KEY_LEFTSHIFT as u16 ;
const KEY_RIGHTSHIFT_U16 : u16 = KEY_RIGHTSHIFT as u16 ;
const KEY_CAPSLOCK_U16 : u16 = KEY_CAPSLOCK as u16 ;
trait KeyMapper {
2017-11-15 01:08:38 -05:00
fn send_event ( & self , key_state : & [ bool ] , event : & mut input_event , device : & Device ) -> Result < ( ) > ;
2017-09-21 22:34:24 -04:00
}
pub struct KeyMaps {
keymaps : Vec < Box < KeyMapper > > ,
keymap_index_keys : HashMap < u16 , usize > ,
switch_layout_keys : Vec < usize > ,
key_state : [ bool ; KEY_MAX ] ,
revert_default_key : u16 ,
revert_keymap_index : usize ,
// above do not change, below does
chosen_keymap_index : usize ,
current_keymap_index : usize ,
}
2017-11-15 22:59:17 -05:00
fn parse_key ( key_map : & HashMap < & 'static str , c_int > , key : & str ) -> u16 {
2017-09-21 22:34:24 -04:00
match key_map . get ( key . trim_matches ( | c : char | c . is_whitespace ( ) | | c = = INVERT_KEY_FLAG | | c = = CAPS_MODIFY_KEY_FLAG ) ) {
Some ( key_code ) = > * key_code as u16 ,
None = > panic! ( " unknown key: {} " , key . trim ( ) )
}
}
2017-11-15 22:59:17 -05:00
fn parse_keymap_numeric ( key_map : & HashMap < & 'static str , c_int > , keymap : & str ) -> Vec < u16 > {
2017-09-21 22:34:24 -04:00
keymap . split ( " , " ) . map ( | k | parse_key ( key_map , k ) ) . collect ( )
}
2017-11-15 22:59:17 -05:00
fn parse_key_half_inverted ( key_map : & HashMap < & 'static str , c_int > , key : & str ) -> HalfInvertedKey {
2017-09-21 22:34:24 -04:00
HalfInvertedKey {
code : parse_key ( key_map , key ) ,
invert_shift : key . contains ( INVERT_KEY_FLAG ) ,
capslock_nomodify : key . contains ( CAPS_MODIFY_KEY_FLAG ) ,
}
}
// maybe shortcut to this if not contains * or :
2017-11-15 22:59:17 -05:00
fn parse_keymap_u16 ( key_map : & HashMap < & 'static str , c_int > , keymap : & str ) -> Vec < u16 > {
2017-09-23 01:29:23 -04:00
keymap . split ( " , " ) . map ( | k | parse_key ( key_map , k ) ) . collect ( )
}
// todo: how do I return an iterator here instead of .collect to Vec?
2017-11-15 22:59:17 -05:00
fn parse_keymap ( key_map : & HashMap < & 'static str , c_int > , keymap : & str ) -> Vec < Key > {
2017-09-23 01:29:23 -04:00
keymap . split ( " , " ) . map ( | k | {
let ret : Key = if k . contains ( HALF_KEY_SEPARATOR ) {
let keys : Vec < & str > = k . split ( HALF_KEY_SEPARATOR ) . collect ( ) ;
if keys . len ( ) ! = 2 {
panic! ( " split key can only have 2 keys, 1 :, has {} keys " , keys . len ( ) ) ;
}
let mut shift_half = parse_key_half_inverted ( key_map , keys [ 1 ] ) ;
shift_half . invert_shift = ! shift_half . invert_shift ;
Key ::FullKey ( parse_key_half_inverted ( key_map , keys [ 0 ] ) , shift_half )
} else if k . contains ( INVERT_KEY_FLAG ) | | k . contains ( CAPS_MODIFY_KEY_FLAG ) {
Key ::HalfKey ( parse_key_half_inverted ( key_map , k ) )
} else {
Key ::Direct ( parse_key ( key_map , k ) )
} ;
ret
} ) . collect ( )
2017-09-21 22:34:24 -04:00
}
impl KeyMaps {
2017-11-15 22:59:17 -05:00
pub fn from_cfg < P : AsRef < Path > > ( key_map : & HashMap < & 'static str , c_int > , path : P ) -> KeyMaps {
2017-09-21 22:34:24 -04:00
let key_map_config = parse_cfg ( path ) . expect ( " provided config cannot be found/parsed " ) ;
KeyMaps ::new ( key_map , key_map_config )
}
2017-11-15 22:59:17 -05:00
pub fn new ( key_map : & HashMap < & 'static str , c_int > , config : KeymapConfig ) -> KeyMaps {
2017-09-21 22:34:24 -04:00
if config . keymaps . len ( ) < 2 {
panic! ( " must have at least 2 keymaps (original and mapped) but only have {} , " , config . keymaps . len ( ) ) ;
}
if config . default_keymap_index > = config . keymaps . len ( ) | | config . revert_keymap_index > = config . keymaps . len ( ) {
panic! ( " default_keymap_index ( {} ) and revert_keymap_index ( {} ) must be less than keymaps length ( {} ), " , config . default_keymap_index , config . revert_keymap_index , config . keymaps . len ( ) ) ;
}
let base_keymap = parse_keymap_numeric ( key_map , & config . keymaps [ 0 ] ) ;
2017-09-22 00:30:56 -04:00
//println!("base_keymap : {:?}", base_keymap);
2017-09-23 00:46:42 -04:00
let mut keymaps : Vec < Box < KeyMapper > > = vec! ( Box ::new ( Key ::Noop ) ) ; // todo: can we share the box?
2017-09-21 22:34:24 -04:00
let mut keymap_index_keys : HashMap < u16 , usize > = HashMap ::new ( ) ;
for ( x , v ) in config . keymaps . iter ( ) . enumerate ( ) {
keymap_index_keys . insert ( * key_map . get ( & * x . to_string ( ) ) . unwrap ( ) as u16 , x ) ;
if x = = 0 {
continue ;
}
2017-09-23 01:29:23 -04:00
if v . contains ( HALF_KEY_SEPARATOR ) | | v . contains ( INVERT_KEY_FLAG ) | | v . contains ( CAPS_MODIFY_KEY_FLAG ) {
// we need KeyMap, the complicated more memory taking one
let v = parse_keymap ( key_map , v ) ;
let mut keymap = KeyMap ::new ( ) ;
let mut i : usize = 0 ;
for key_code in v {
// todo: if these are the same, do Noop instead
keymap . map ( base_keymap [ i ] , key_code ) ;
i = i + 1 ;
if i > base_keymap . len ( ) {
panic! ( " all keymaps must be the same length, keymap index 0 length: {} , index {} length: {} , " , base_keymap . len ( ) , x , i ) ;
2017-09-21 22:34:24 -04:00
}
}
2017-09-23 01:29:23 -04:00
keymaps . push ( Box ::new ( keymap ) ) ;
} else {
// this is a simple keymap
let v = parse_keymap_u16 ( key_map , v ) ;
let mut keymap = CodeKeyMap ::new ( ) ;
let mut i : usize = 0 ;
for key_code in v {
keymap . map ( base_keymap [ i ] , key_code ) ;
i = i + 1 ;
if i > base_keymap . len ( ) {
panic! ( " all keymaps must be the same length, keymap index 0 length: {} , index {} length: {} , " , base_keymap . len ( ) , x , i ) ;
}
2017-09-21 22:34:24 -04:00
}
2017-09-23 01:29:23 -04:00
keymaps . push ( Box ::new ( keymap ) ) ;
2017-09-21 22:34:24 -04:00
}
}
//println!("keymaps: {:?}", keymaps);
//println!("keymap_index_keys: {:?}", keymap_index_keys);
KeyMaps {
keymaps : keymaps ,
keymap_index_keys : keymap_index_keys ,
switch_layout_keys : config . switch_layout_keys . iter ( ) . map ( | k | parse_key ( key_map , k ) as usize ) . collect ( ) ,
key_state : [ false ; KEY_MAX ] ,
// todo: detect key state? at least CAPSLOCK...
revert_default_key : parse_key ( key_map , & config . revert_default_key ) ,
revert_keymap_index : config . revert_keymap_index ,
chosen_keymap_index : config . default_keymap_index ,
current_keymap_index : config . default_keymap_index ,
}
}
}
//impl KeyMapper for KeyMaps {
impl KeyMaps {
2017-11-15 01:08:38 -05:00
pub fn send_event ( & mut self , mut event : & mut input_event , device : & Device ) -> Result < ( ) > {
2017-09-21 22:34:24 -04:00
//println!("type: {} code: {} value: {}", event.type_, event.code, event.value);
if event . value ! = 2 {
// todo: index check here...
if event . code = = KEY_CAPSLOCK_U16 {
if event . value = = DOWN {
self . key_state [ CAPSLOCK_INDEX ] = ! self . key_state [ CAPSLOCK_INDEX ] ;
}
} else {
self . key_state [ event . code as usize ] = event . value = = DOWN ;
}
let mut switch_layout_keys_pressed = true ;
for layout_switch_key in self . switch_layout_keys . iter_mut ( ) {
if ! self . key_state [ * layout_switch_key ] {
switch_layout_keys_pressed = false ;
break ;
}
}
//println!("switch_layout_keys_pressed: {}", self.switch_layout_keys_pressed);
if switch_layout_keys_pressed {
let new_index = self . keymap_index_keys . get ( & event . code ) ;
if new_index . is_some ( ) {
self . chosen_keymap_index = * new_index . unwrap ( ) ;
self . current_keymap_index = self . chosen_keymap_index ; // todo: what if revert_default_key is held? for now ignore
2017-11-15 01:08:38 -05:00
return Ok ( ( ) ) ; // we don't want to also send this keypress, so bail
2017-09-21 22:34:24 -04:00
}
}
if event . code = = self . revert_default_key {
match event . value {
// todo: ctrl+c will get c stuck because code c value 1 will be sent, but then we'll let go of ctrl, and code j value 0 is sent, so c is never released... fix that...
DOWN = > self . current_keymap_index = self . revert_keymap_index ,
UP = > self . current_keymap_index = self . chosen_keymap_index ,
_ = > ( ) // do nothing for 2
}
}
}
2017-11-15 01:08:38 -05:00
self . keymaps [ self . current_keymap_index ] . send_event ( & self . key_state , & mut event , device )
2017-09-21 22:34:24 -04:00
}
}
// 249 is one more than KEY_MICMUTE which is max key in uinput-sys event.rs
const KEY_MAX : usize = 249 ;
struct KeyMap {
2017-09-23 00:47:20 -04:00
//keymap: Vec<Key>,
keymap : [ Key ; KEY_MAX ] ,
2017-09-21 22:34:24 -04:00
}
impl KeyMap {
pub fn new ( ) -> Self {
//let mut keymap = [0u16; KEY_MAX];
//let mut keymap : [Box<KeyMapper>; KEY_MAX] = [Box::new(NOOP); KEY_MAX];
//let mut keymap : [Box<KeyMapper>; KEY_MAX] = [Box::new(0u16); KEY_MAX];
2017-09-23 00:47:20 -04:00
let keymap : [ Key ; KEY_MAX ] = [ Key ::Noop ; KEY_MAX ] ;
/*
2017-09-23 00:46:42 -04:00
let mut keymap : Vec < Key > = Vec ::with_capacity ( KEY_MAX ) ;
2017-09-21 22:34:24 -04:00
#[ allow(unused_variables) ]
for x in 0 .. KEY_MAX {
2017-09-23 00:46:42 -04:00
keymap . push ( Key ::Noop ) ;
2017-09-21 22:34:24 -04:00
}
2017-09-23 00:47:20 -04:00
* /
2017-09-21 22:34:24 -04:00
// which is rustier
/*
for x in 0 .. KEY_MAX {
keymap [ x as usize ] = x as u16 ;
}
for ( x , v ) in keymap . iter_mut ( ) . enumerate ( ) {
* v = x as u16 ;
}
* /
//println!("keymap: {:?}", &keymap[..]);
KeyMap {
keymap : keymap
}
}
/*
pub fn map ( & mut self , from : u16 , to : u16 ) {
self . keymap [ from as usize ] = to ;
}
* /
2017-09-23 00:46:42 -04:00
pub fn map ( & mut self , from : u16 , to : Key ) {
2017-09-21 22:34:24 -04:00
self . keymap [ from as usize ] = to ;
}
}
impl KeyMapper for KeyMap {
2017-11-15 01:08:38 -05:00
fn send_event ( & self , key_state : & [ bool ] , event : & mut input_event , device : & Device ) -> Result < ( ) > {
self . keymap [ event . code as usize ] . send_event ( key_state , event , device )
2017-09-21 22:34:24 -04:00
}
}
2017-09-23 01:29:23 -04:00
struct CodeKeyMap {
//keymap: Vec<Key>,
keymap : [ u16 ; KEY_MAX ] ,
}
impl CodeKeyMap {
pub fn new ( ) -> Self {
let mut keymap = [ 0 u16 ; KEY_MAX ] ;
// which is rustier
/*
for x in 0 .. KEY_MAX {
keymap [ x as usize ] = x as u16 ;
}
* /
for ( x , v ) in keymap . iter_mut ( ) . enumerate ( ) {
* v = x as u16 ;
}
//println!("keymap: {:?}", &keymap[..]);
CodeKeyMap {
keymap : keymap
}
}
pub fn map ( & mut self , from : u16 , to : u16 ) {
self . keymap [ from as usize ] = to ;
}
}
impl KeyMapper for CodeKeyMap {
2017-11-15 01:08:38 -05:00
fn send_event ( & self , key_state : & [ bool ] , event : & mut input_event , device : & Device ) -> Result < ( ) > {
self . keymap [ event . code as usize ] . send_event ( key_state , event , device )
2017-09-23 01:29:23 -04:00
}
}
2017-11-15 01:08:38 -05:00
#[ allow(unused_variables, unused_mut) ]
2017-09-21 22:34:24 -04:00
impl KeyMapper for u16 {
2017-11-15 01:08:38 -05:00
fn send_event ( & self , key_state : & [ bool ] , mut event : & mut input_event , device : & Device ) -> Result < ( ) > {
2017-09-21 22:34:24 -04:00
event . code = * self ;
2017-11-15 01:08:38 -05:00
device . write_event ( event )
2017-09-21 22:34:24 -04:00
}
}
// todo:capslock_nomodify is like a whole-key thing, not a half-key thing, split code/invert_shift to own struct, send into send_key from *InvertedKey, maybe anyway, consider it, maybe 1 char for whole key and another for half?
2017-09-23 00:47:20 -04:00
#[ derive(Clone, Copy) ]
2017-09-21 22:34:24 -04:00
struct HalfInvertedKey {
code : u16 ,
// code this is describing
invert_shift : bool ,
// true to invert shift for this code
capslock_nomodify : bool ,
// true means capslock does not normally modify this, but you would like it to
}
impl HalfInvertedKey {
2017-11-15 01:08:38 -05:00
fn send_key ( & self , key_state : & [ bool ] , event : & mut input_event , device : & Device , left_shift : bool , right_shift : bool , caps_lock : bool ) -> Result < ( ) > {
2017-09-22 23:57:26 -04:00
let code = self . code ;
2017-09-21 22:34:24 -04:00
let value = event . value ;
let mut invert_shift = self . invert_shift ;
if value = = DOWN {
if caps_lock & & self . capslock_nomodify {
invert_shift = ! invert_shift ;
}
if invert_shift {
if left_shift {
event . code = KEY_LEFTSHIFT_U16 ;
event . value = UP ;
} else if right_shift {
event . code = KEY_RIGHTSHIFT_U16 ;
event . value = UP ;
} else {
event . code = KEY_LEFTSHIFT_U16 ;
event . value = DOWN ;
}
//event.code.send_event(key_state, event, device);
2017-11-15 01:08:38 -05:00
device . write_event ( event ) ? ;
2017-09-21 22:34:24 -04:00
event . code = code ; // not needed since u16 does it
event . value = value ;
}
}
2017-11-15 01:08:38 -05:00
code . send_event ( key_state , event , device ) ? ;
2017-09-21 22:34:24 -04:00
if value = = UP {
if caps_lock & & self . capslock_nomodify {
invert_shift = ! invert_shift ;
}
if invert_shift {
if left_shift {
event . code = KEY_LEFTSHIFT_U16 ;
event . value = DOWN ;
} else if right_shift {
event . code = KEY_RIGHTSHIFT_U16 ;
event . value = DOWN ;
} else {
event . code = KEY_LEFTSHIFT_U16 ;
event . value = UP ;
}
//event.code.send_event(key_state, event, device);
2017-11-15 01:08:38 -05:00
device . write_event ( event ) ? ;
2017-09-21 22:34:24 -04:00
// neither of these are needed now...
event . code = code ; // not needed since u16 does it
event . value = value ;
}
}
2017-11-15 01:08:38 -05:00
Ok ( ( ) )
2017-09-21 22:34:24 -04:00
}
}
impl KeyMapper for HalfInvertedKey {
2017-11-15 01:08:38 -05:00
fn send_event ( & self , key_state : & [ bool ] , event : & mut input_event , device : & Device ) -> Result < ( ) > {
2017-09-21 22:34:24 -04:00
let left_shift = key_state [ LEFTSHIFT_INDEX ] ;
let right_shift = key_state [ RIGHTSHIFT_INDEX ] ;
let caps_lock = key_state [ CAPSLOCK_INDEX ] ;
2017-11-15 01:08:38 -05:00
self . send_key ( key_state , event , device , left_shift , right_shift , caps_lock )
2017-09-21 22:34:24 -04:00
}
}
2017-09-23 00:47:20 -04:00
#[ derive(Clone, Copy) ]
2017-09-23 00:46:42 -04:00
enum Key {
Noop ,
Direct ( u16 ) ,
HalfKey ( HalfInvertedKey ) ,
FullKey ( HalfInvertedKey , HalfInvertedKey ) ,
2017-09-21 22:34:24 -04:00
}
2017-09-23 00:46:42 -04:00
impl KeyMapper for Key {
2017-11-15 01:08:38 -05:00
fn send_event ( & self , key_state : & [ bool ] , event : & mut input_event , device : & Device ) -> Result < ( ) > {
2017-09-23 00:46:42 -04:00
match * self {
Key ::Noop = > {
2017-11-15 01:08:38 -05:00
device . write_event ( event )
2017-09-23 00:46:42 -04:00
} ,
Key ::Direct ( code ) = > {
2017-11-15 01:08:38 -05:00
code . send_event ( key_state , event , device )
2017-09-23 00:46:42 -04:00
} ,
Key ::HalfKey ( ref key_half ) = > {
2017-11-15 01:08:38 -05:00
key_half . send_event ( key_state , event , device )
2017-09-23 00:46:42 -04:00
} ,
Key ::FullKey ( ref noshift_half , ref shift_half ) = > {
let left_shift = key_state [ LEFTSHIFT_INDEX ] ;
let right_shift = key_state [ RIGHTSHIFT_INDEX ] ;
let caps_lock = key_state [ CAPSLOCK_INDEX ] ;
if caps_lock ! = ( left_shift | | right_shift ) {
2017-11-15 01:08:38 -05:00
shift_half . send_key ( key_state , event , device , left_shift , right_shift , caps_lock )
2017-09-23 00:46:42 -04:00
} else {
2017-11-15 01:08:38 -05:00
noshift_half . send_key ( key_state , event , device , left_shift , right_shift , caps_lock )
2017-09-23 00:46:42 -04:00
}
} ,
2017-09-21 22:34:24 -04:00
}
}
}
extern crate toml ;
use std ::path ::Path ;
#[ derive(Deserialize, Debug) ]
pub struct KeymapConfig {
switch_layout_keys : Vec < String > ,
revert_default_key : String ,
revert_keymap_index : usize ,
default_keymap_index : usize ,
keymaps : Vec < String >
}
2017-11-15 01:08:38 -05:00
fn parse_cfg < P : AsRef < Path > > ( path : P ) -> Result < KeymapConfig > {
2017-09-21 22:34:24 -04:00
let mut f = File ::open ( path ) ? ;
let mut input = String ::new ( ) ;
f . read_to_string ( & mut input ) ? ;
//toml::from_str(&input)?
match toml ::from_str ( & input ) {
Ok ( toml ) = > Ok ( toml ) ,
2017-11-15 01:08:38 -05:00
Err ( _ ) = > Err ( Error ::NotFound ) // todo: something better
2017-09-21 22:34:24 -04:00
}
}
impl KeyMaps {
2017-11-15 22:59:17 -05:00
pub fn key_map ( ) -> HashMap < & 'static str , c_int > {
2017-09-21 22:34:24 -04:00
[
// generated like:
// grep -o 'KEY_[^ :;]*' ~/.cargo/registry/src/github.com-1ecc6299db9ec823/uinput-sys-0.1.3/src/events.rs | sed 's/^KEY_//' | awk '{print "(\""$1"\", KEY_"$1"),"}'
( " RESERVED " , KEY_RESERVED ) ,
( " ESC " , 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_10 ) ,
( " MINUS " , KEY_MINUS ) ,
( " EQUAL " , KEY_EQUAL ) ,
( " BACKSPACE " , KEY_BACKSPACE ) ,
( " TAB " , KEY_TAB ) ,
( " Q " , KEY_Q ) ,
( " W " , KEY_W ) ,
( " E " , KEY_E ) ,
( " R " , KEY_R ) ,
( " T " , KEY_T ) ,
( " Y " , KEY_Y ) ,
( " U " , KEY_U ) ,
( " I " , KEY_I ) ,
( " O " , KEY_O ) ,
( " P " , KEY_P ) ,
( " LEFTBRACE " , KEY_LEFTBRACE ) ,
( " RIGHTBRACE " , KEY_RIGHTBRACE ) ,
( " ENTER " , KEY_ENTER ) ,
( " LEFTCTRL " , KEY_LEFTCTRL ) ,
( " A " , KEY_A ) ,
( " S " , KEY_S ) ,
( " D " , KEY_D ) ,
( " F " , KEY_F ) ,
( " G " , KEY_G ) ,
( " H " , KEY_H ) ,
( " J " , KEY_J ) ,
( " K " , KEY_K ) ,
( " L " , KEY_L ) ,
( " SEMICOLON " , KEY_SEMICOLON ) ,
( " APOSTROPHE " , KEY_APOSTROPHE ) ,
( " GRAVE " , KEY_GRAVE ) ,
( " LEFTSHIFT " , KEY_LEFTSHIFT ) ,
( " BACKSLASH " , KEY_BACKSLASH ) ,
( " Z " , KEY_Z ) ,
( " X " , KEY_X ) ,
( " C " , KEY_C ) ,
( " V " , KEY_V ) ,
( " B " , KEY_B ) ,
( " N " , KEY_N ) ,
( " M " , KEY_M ) ,
( " COMMA " , KEY_COMMA ) ,
( " DOT " , KEY_DOT ) ,
( " SLASH " , KEY_SLASH ) ,
( " RIGHTSHIFT " , KEY_RIGHTSHIFT ) ,
( " KPASTERISK " , KEY_KPASTERISK ) ,
( " LEFTALT " , KEY_LEFTALT ) ,
( " SPACE " , KEY_SPACE ) ,
( " CAPSLOCK " , KEY_CAPSLOCK ) ,
( " F1 " , KEY_F1 ) ,
( " F2 " , KEY_F2 ) ,
( " F3 " , KEY_F3 ) ,
( " F4 " , KEY_F4 ) ,
( " F5 " , KEY_F5 ) ,
( " F6 " , KEY_F6 ) ,
( " F7 " , KEY_F7 ) ,
( " F8 " , KEY_F8 ) ,
( " F9 " , KEY_F9 ) ,
( " F10 " , KEY_F10 ) ,
( " NUMLOCK " , KEY_NUMLOCK ) ,
( " SCROLLLOCK " , KEY_SCROLLLOCK ) ,
( " KP7 " , KEY_KP7 ) ,
( " KP8 " , KEY_KP8 ) ,
( " KP9 " , KEY_KP9 ) ,
( " KPMINUS " , KEY_KPMINUS ) ,
( " KP4 " , KEY_KP4 ) ,
( " KP5 " , KEY_KP5 ) ,
( " KP6 " , KEY_KP6 ) ,
( " KPPLUS " , KEY_KPPLUS ) ,
( " KP1 " , KEY_KP1 ) ,
( " KP2 " , KEY_KP2 ) ,
( " KP3 " , KEY_KP3 ) ,
( " KP0 " , KEY_KP0 ) ,
( " KPDOT " , KEY_KPDOT ) ,
( " ZENKAKUHANKAKU " , KEY_ZENKAKUHANKAKU ) ,
( " 102ND " , KEY_102ND ) ,
( " F11 " , KEY_F11 ) ,
( " F12 " , KEY_F12 ) ,
( " RO " , KEY_RO ) ,
( " KATAKANA " , KEY_KATAKANA ) ,
( " HIRAGANA " , KEY_HIRAGANA ) ,
( " HENKAN " , KEY_HENKAN ) ,
( " KATAKANAHIRAGANA " , KEY_KATAKANAHIRAGANA ) ,
( " MUHENKAN " , KEY_MUHENKAN ) ,
( " KPJPCOMMA " , KEY_KPJPCOMMA ) ,
( " KPENTER " , KEY_KPENTER ) ,
( " RIGHTCTRL " , KEY_RIGHTCTRL ) ,
( " KPSLASH " , KEY_KPSLASH ) ,
( " SYSRQ " , KEY_SYSRQ ) ,
( " RIGHTALT " , KEY_RIGHTALT ) ,
( " LINEFEED " , KEY_LINEFEED ) ,
( " HOME " , KEY_HOME ) ,
( " UP " , KEY_UP ) ,
( " PAGEUP " , KEY_PAGEUP ) ,
( " LEFT " , KEY_LEFT ) ,
( " RIGHT " , KEY_RIGHT ) ,
( " END " , KEY_END ) ,
( " DOWN " , KEY_DOWN ) ,
( " PAGEDOWN " , KEY_PAGEDOWN ) ,
( " INSERT " , KEY_INSERT ) ,
( " DELETE " , KEY_DELETE ) ,
( " MACRO " , KEY_MACRO ) ,
( " MUTE " , KEY_MUTE ) ,
( " VOLUMEDOWN " , KEY_VOLUMEDOWN ) ,
( " VOLUMEUP " , KEY_VOLUMEUP ) ,
( " POWER " , KEY_POWER ) ,
( " KPEQUAL " , KEY_KPEQUAL ) ,
( " KPPLUSMINUS " , KEY_KPPLUSMINUS ) ,
( " PAUSE " , KEY_PAUSE ) ,
( " SCALE " , KEY_SCALE ) ,
( " KPCOMMA " , KEY_KPCOMMA ) ,
( " HANGEUL " , KEY_HANGEUL ) ,
( " HANGUEL " , KEY_HANGUEL ) ,
( " HANGEUL " , KEY_HANGEUL ) ,
( " HANJA " , KEY_HANJA ) ,
( " YEN " , KEY_YEN ) ,
( " LEFTMETA " , KEY_LEFTMETA ) ,
( " RIGHTMETA " , KEY_RIGHTMETA ) ,
( " COMPOSE " , KEY_COMPOSE ) ,
( " STOP " , KEY_STOP ) ,
( " AGAIN " , KEY_AGAIN ) ,
( " PROPS " , KEY_PROPS ) ,
( " UNDO " , KEY_UNDO ) ,
( " FRONT " , KEY_FRONT ) ,
( " COPY " , KEY_COPY ) ,
( " OPEN " , KEY_OPEN ) ,
( " PASTE " , KEY_PASTE ) ,
( " FIND " , KEY_FIND ) ,
( " CUT " , KEY_CUT ) ,
( " HELP " , KEY_HELP ) ,
( " MENU " , KEY_MENU ) ,
( " CALC " , KEY_CALC ) ,
( " SETUP " , KEY_SETUP ) ,
( " SLEEP " , KEY_SLEEP ) ,
( " WAKEUP " , KEY_WAKEUP ) ,
( " FILE " , KEY_FILE ) ,
( " SENDFILE " , KEY_SENDFILE ) ,
( " DELETEFILE " , KEY_DELETEFILE ) ,
( " XFER " , KEY_XFER ) ,
( " PROG1 " , KEY_PROG1 ) ,
( " PROG2 " , KEY_PROG2 ) ,
( " WWW " , KEY_WWW ) ,
( " MSDOS " , KEY_MSDOS ) ,
( " COFFEE " , KEY_COFFEE ) ,
( " SCREENLOCK " , KEY_SCREENLOCK ) ,
( " COFFEE " , KEY_COFFEE ) ,
( " ROTATE_DISPLAY " , KEY_ROTATE_DISPLAY ) ,
( " DIRECTION " , KEY_DIRECTION ) ,
( " ROTATE_DISPLAY " , KEY_ROTATE_DISPLAY ) ,
( " CYCLEWINDOWS " , KEY_CYCLEWINDOWS ) ,
( " MAIL " , KEY_MAIL ) ,
( " BOOKMARKS " , KEY_BOOKMARKS ) ,
( " COMPUTER " , KEY_COMPUTER ) ,
( " BACK " , KEY_BACK ) ,
( " FORWARD " , KEY_FORWARD ) ,
( " CLOSECD " , KEY_CLOSECD ) ,
( " EJECTCD " , KEY_EJECTCD ) ,
( " EJECTCLOSECD " , KEY_EJECTCLOSECD ) ,
( " NEXTSONG " , KEY_NEXTSONG ) ,
( " PLAYPAUSE " , KEY_PLAYPAUSE ) ,
( " PREVIOUSSONG " , KEY_PREVIOUSSONG ) ,
( " STOPCD " , KEY_STOPCD ) ,
( " RECORD " , KEY_RECORD ) ,
( " REWIND " , KEY_REWIND ) ,
( " PHONE " , KEY_PHONE ) ,
( " ISO " , KEY_ISO ) ,
( " CONFIG " , KEY_CONFIG ) ,
( " HOMEPAGE " , KEY_HOMEPAGE ) ,
( " REFRESH " , KEY_REFRESH ) ,
( " EXIT " , KEY_EXIT ) ,
( " MOVE " , KEY_MOVE ) ,
( " EDIT " , KEY_EDIT ) ,
( " SCROLLUP " , KEY_SCROLLUP ) ,
( " SCROLLDOWN " , KEY_SCROLLDOWN ) ,
( " KPLEFTPAREN " , KEY_KPLEFTPAREN ) ,
( " KPRIGHTPAREN " , KEY_KPRIGHTPAREN ) ,
( " NEW " , KEY_NEW ) ,
( " REDO " , KEY_REDO ) ,
( " F13 " , KEY_F13 ) ,
( " F14 " , KEY_F14 ) ,
( " F15 " , KEY_F15 ) ,
( " F16 " , KEY_F16 ) ,
( " F17 " , KEY_F17 ) ,
( " F18 " , KEY_F18 ) ,
( " F19 " , KEY_F19 ) ,
( " F20 " , KEY_F20 ) ,
( " F21 " , KEY_F21 ) ,
( " F22 " , KEY_F22 ) ,
( " F23 " , KEY_F23 ) ,
( " F24 " , KEY_F24 ) ,
( " PLAYCD " , KEY_PLAYCD ) ,
( " PAUSECD " , KEY_PAUSECD ) ,
( " PROG3 " , KEY_PROG3 ) ,
( " PROG4 " , KEY_PROG4 ) ,
( " DASHBOARD " , KEY_DASHBOARD ) ,
( " SUSPEND " , KEY_SUSPEND ) ,
( " CLOSE " , KEY_CLOSE ) ,
( " PLAY " , KEY_PLAY ) ,
( " FASTFORWARD " , KEY_FASTFORWARD ) ,
( " BASSBOOST " , KEY_BASSBOOST ) ,
( " PRINT " , KEY_PRINT ) ,
( " HP " , KEY_HP ) ,
( " CAMERA " , KEY_CAMERA ) ,
( " SOUND " , KEY_SOUND ) ,
( " QUESTION " , KEY_QUESTION ) ,
( " EMAIL " , KEY_EMAIL ) ,
( " CHAT " , KEY_CHAT ) ,
( " SEARCH " , KEY_SEARCH ) ,
( " CONNECT " , KEY_CONNECT ) ,
( " FINANCE " , KEY_FINANCE ) ,
( " SPORT " , KEY_SPORT ) ,
( " SHOP " , KEY_SHOP ) ,
( " ALTERASE " , KEY_ALTERASE ) ,
( " CANCEL " , KEY_CANCEL ) ,
( " BRIGHTNESSDOWN " , KEY_BRIGHTNESSDOWN ) ,
( " BRIGHTNESSUP " , KEY_BRIGHTNESSUP ) ,
( " MEDIA " , KEY_MEDIA ) ,
( " SWITCHVIDEOMODE " , KEY_SWITCHVIDEOMODE ) ,
( " KBDILLUMTOGGLE " , KEY_KBDILLUMTOGGLE ) ,
( " KBDILLUMDOWN " , KEY_KBDILLUMDOWN ) ,
( " KBDILLUMUP " , KEY_KBDILLUMUP ) ,
( " SEND " , KEY_SEND ) ,
( " REPLY " , KEY_REPLY ) ,
( " FORWARDMAIL " , KEY_FORWARDMAIL ) ,
( " SAVE " , KEY_SAVE ) ,
( " DOCUMENTS " , KEY_DOCUMENTS ) ,
( " BATTERY " , KEY_BATTERY ) ,
( " BLUETOOTH " , KEY_BLUETOOTH ) ,
( " WLAN " , KEY_WLAN ) ,
( " UWB " , KEY_UWB ) ,
( " UNKNOWN " , KEY_UNKNOWN ) ,
( " VIDEO_NEXT " , KEY_VIDEO_NEXT ) ,
( " VIDEO_PREV " , KEY_VIDEO_PREV ) ,
( " BRIGHTNESS_CYCLE " , KEY_BRIGHTNESS_CYCLE ) ,
( " BRIGHTNESS_AUTO " , KEY_BRIGHTNESS_AUTO ) ,
( " BRIGHTNESS_ZERO " , KEY_BRIGHTNESS_ZERO ) ,
( " BRIGHTNESS_AUTO " , KEY_BRIGHTNESS_AUTO ) ,
( " DISPLAY_OFF " , KEY_DISPLAY_OFF ) ,
( " WWAN " , KEY_WWAN ) ,
( " WIMAX " , KEY_WIMAX ) ,
( " WWAN " , KEY_WWAN ) ,
( " RFKILL " , KEY_RFKILL ) ,
( " MICMUTE " , KEY_MICMUTE ) ,
// below manual shortcuts
( " PSCR " , KEY_SYSRQ ) ,
( " SLCK " , KEY_SCROLLLOCK ) ,
( " BRK " , KEY_PAUSE ) ,
( " GRV " , KEY_GRAVE ) ,
( " 0 " , KEY_10 ) , // dumb or named wrong?
( " MINS " , KEY_MINUS ) ,
( " EQL " , KEY_EQUAL ) ,
( " BSPC " , KEY_BACKSPACE ) ,
( " LBRC " , KEY_LEFTBRACE ) ,
( " RBRC " , KEY_RIGHTBRACE ) ,
( " BSLS " , KEY_BACKSLASH ) ,
( " SCLN " , KEY_SEMICOLON ) ,
( " QUOT " , KEY_APOSTROPHE ) ,
( " ENT " , KEY_ENTER ) ,
( " COMM " , KEY_COMMA ) ,
( " DOT " , KEY_DOT ) ,
( " SLSH " , KEY_SLASH ) ,
( " CAPS " , KEY_CAPSLOCK ) ,
( " LSFT " , KEY_LEFTSHIFT ) ,
( " RSFT " , KEY_RIGHTSHIFT ) ,
( " SPC " , KEY_SPACE ) ,
( " APP " , KEY_COMPOSE ) ,
( " LCTL " , KEY_LEFTCTRL ) ,
( " RCTL " , KEY_RIGHTCTRL ) ,
( " LALT " , KEY_LEFTALT ) ,
( " RALT " , KEY_RIGHTALT ) ,
( " LGUI " , KEY_LEFTMETA ) ,
( " RGUI " , KEY_RIGHTMETA ) ,
( " INS " , KEY_INSERT ) ,
( " PGUP " , KEY_PAGEUP ) ,
( " PGDN " , KEY_PAGEDOWN ) ,
( " DEL " , KEY_DELETE ) ,
( " RGHT " , KEY_RIGHT ) ,
( " NLCK " , KEY_NUMLOCK ) ,
( " PSLS " , KEY_KPSLASH ) ,
( " PAST " , KEY_KPASTERISK ) ,
( " PMNS " , KEY_KPMINUS ) ,
( " P7 " , KEY_KP7 ) ,
( " P8 " , KEY_KP8 ) ,
( " P9 " , KEY_KP9 ) ,
( " P4 " , KEY_KP4 ) ,
( " P5 " , KEY_KP5 ) ,
( " P6 " , KEY_KP6 ) ,
( " PPLS " , KEY_KPPLUS ) ,
( " P1 " , KEY_KP1 ) ,
( " P2 " , KEY_KP2 ) ,
( " P3 " , KEY_KP3 ) ,
( " P0 " , KEY_KP0 ) ,
( " PDOT " , KEY_KPDOT ) ,
( " PENT " , KEY_KPENTER ) ,
2017-11-15 22:59:17 -05:00
] . iter ( ) . cloned ( ) . map ( | ( m , v ) | ( m , v ) ) . collect ( )
2017-09-21 22:34:24 -04:00
}
}