2016-04-25 11:13:05 -04:00
extern crate uinput ;
2017-09-01 00:24:35 -04:00
extern crate uinput_sys as ffi ;
2017-09-08 01:16:34 -04:00
extern crate libc ;
extern crate getopts ;
#[ macro_use ]
extern crate nix ;
use uinput ::Device ;
2017-09-01 00:24:35 -04:00
use ffi ::* ;
2017-09-08 01:16:34 -04:00
use libc ::{ c_int , input_event } ;
2016-04-25 11:13:05 -04:00
use std ::thread ;
use std ::time ::Duration ;
2017-09-08 01:16:34 -04:00
use std ::collections ::HashMap ;
use std ::process ::{ exit , Command } ;
use std ::fs ::File ;
use std ::io ::{ Read } ;
use std ::{ env , mem } ;
use std ::os ::unix ::io ::AsRawFd ;
use getopts ::Options ;
const VERSION : & 'static str = env! ( " CARGO_PKG_VERSION " ) ;
const EV_KEY_U16 : u16 = EV_KEY as u16 ;
#[ derive(Debug) ]
struct Config {
device_file : String ,
log_file : String
}
impl Config {
fn new ( device_file : String , log_file : String ) -> Self {
Config { device_file : device_file , log_file : log_file }
}
}
2016-04-25 11:13:05 -04:00
fn main ( ) {
2017-09-08 01:16:34 -04:00
2017-09-14 01:08:17 -04:00
let key_map_config = parse_cfg ( " keymap.toml " ) . expect ( " provided config cannot be found/parsed " ) ;
//println!("key_map_config: {:?}", key_map_config);
2017-09-08 01:16:34 -04:00
let key_map = KeyMap ::key_map ( ) ;
//println!("key_map: {:?}", key_map);
let device = uinput ::default ( ) . expect ( " 1 " )
. name ( " test " ) . expect ( " 2 " )
. event ( key_map . values ( ) ) . expect ( " 3 " )
//.event(uinput::event::Keyboard::All).unwrap()
. create ( ) . expect ( " 4 " ) ;
2017-09-14 22:57:20 -04:00
let mut key_map = KeyMaps ::new ( & key_map , key_map_config ) ;
2017-09-14 01:08:17 -04:00
//println!("keymaps: {:?}", keymaps);
//let mut key_map = KeyMap::new();
//key_map.map(KEY_A, KEY_B);
2017-09-08 01:16:34 -04:00
thread ::sleep ( Duration ::from_secs ( 1 ) ) ;
//device.click(EV_KEY, KEY_H).unwrap();
//device.synchronize().unwrap();
let config = parse_args ( ) ;
println! ( " Config: {:?} " , config ) ;
let mut input_device = InputDevice ::open ( & config . device_file ) ;
input_device . grab ( ) ;
loop {
let event = input_device . read_event ( ) ;
if event . type_ = = EV_KEY_U16 {
key_map . send_event ( event , & device ) ;
/*
println! ( " type: {} code: {} " , event . type_ , event . code ) ;
if event . code = = KEY_A as u16 {
event . code = KEY_B as u16 ;
}
* /
} else {
device . write_event ( event ) . expect ( " could not write event? " ) ;
}
}
2016-04-25 11:13:05 -04:00
}
2017-09-08 01:16:34 -04:00
fn parse_args ( ) -> Config {
fn print_usage ( program : & str , opts : Options ) {
let brief = format! ( " Usage: {} [options] " , program ) ;
println! ( " {} " , opts . usage ( & brief ) ) ;
}
let args : Vec < _ > = env ::args ( ) . collect ( ) ;
let mut opts = Options ::new ( ) ;
opts . optflag ( " h " , " help " , " prints this help message " ) ;
opts . optflag ( " v " , " version " , " prints the version " ) ;
opts . optopt ( " d " , " device " , " specify the device file " , " DEVICE " ) ;
opts . optopt ( " f " , " file " , " specify the file to log to " , " FILE " ) ;
let matches = opts . parse ( & args [ 1 .. ] ) . unwrap_or_else ( | e | panic! ( " {} " , e ) ) ;
if matches . opt_present ( " h " ) {
print_usage ( & args [ 0 ] , opts ) ;
exit ( 0 ) ;
}
if matches . opt_present ( " v " ) {
println! ( " {} " , VERSION ) ;
exit ( 0 ) ;
}
let device_file = matches . opt_str ( " d " ) . unwrap_or_else ( | | get_default_device ( ) ) ;
let log_file = matches . opt_str ( " f " ) . unwrap_or ( " keys.log " . to_owned ( ) ) ;
Config ::new ( device_file , log_file )
}
fn get_default_device ( ) -> String {
let mut filenames = get_keyboard_device_filenames ( ) ;
println! ( " Detected devices: {:?} " , filenames ) ;
if filenames . len ( ) = = 1 {
filenames . swap_remove ( 0 )
} else {
panic! ( " The following keyboard devices were detected: {:?} . Please select one using \
the ` - d ` flag " , filenames);
}
}
// Detects and returns the name of the keyboard device file. This function uses
// the fact that all device information is shown in /proc/bus/input/devices and
// the keyboard device file should always have an EV of 120013
fn get_keyboard_device_filenames ( ) -> Vec < String > {
let mut command_str = " grep -E 'Handlers|EV' /proc/bus/input/devices " . to_string ( ) ;
command_str . push_str ( " | grep -B1 120013 " ) ;
command_str . push_str ( " | grep -Eo event[0-9]+ " ) ;
let res = Command ::new ( " sh " ) . arg ( " -c " ) . arg ( command_str ) . output ( ) . unwrap_or_else ( | e | {
panic! ( " {} " , e ) ;
} ) ;
let res_str = std ::str ::from_utf8 ( & res . stdout ) . unwrap ( ) ;
let mut filenames = Vec ::new ( ) ;
for file in res_str . trim ( ) . split ( '\n' ) {
let mut filename = " /dev/input/ " . to_string ( ) ;
filename . push_str ( file ) ;
filenames . push ( filename ) ;
}
filenames
}
// inputdevice stuff
ioctl! ( write eviocgrab with b 'E' , 0x90 ; c_int ) ;
// TODO: use size_of_input_event instead of hard-coding 24.
const SIZE_OF_INPUT_EVENT : usize = 24 ; //mem::size_of::<input_event>();
struct InputDevice {
device_file : File ,
buf : [ u8 ; SIZE_OF_INPUT_EVENT ] ,
}
impl InputDevice {
pub fn open ( device_file : & str ) -> Self {
let device_file = File ::open ( device_file ) . unwrap_or_else ( | e | panic! ( " {} " , e ) ) ;
InputDevice {
device_file : device_file ,
buf : [ 0 u8 ; SIZE_OF_INPUT_EVENT ] ,
}
}
pub fn read_event ( & mut self ) -> input_event {
let num_bytes = self . device_file . read ( & mut self . buf ) . unwrap_or_else ( | e | panic! ( " {} " , e ) ) ;
if num_bytes ! = SIZE_OF_INPUT_EVENT {
panic! ( " Error while reading from device file " ) ;
}
let event : input_event = unsafe { mem ::transmute ( self . buf ) } ;
event
}
pub fn grab ( & mut self ) {
unsafe {
eviocgrab ( self . device_file . as_raw_fd ( ) , 1 as * const c_int ) . expect ( " no grab? " ) ;
}
}
pub fn release ( & mut self ) {
unsafe {
eviocgrab ( self . device_file . as_raw_fd ( ) , 0 as * const c_int ) . expect ( " no release? " ) ;
}
}
}
impl Drop for InputDevice {
fn drop ( & mut self ) {
self . release ( ) ;
}
}
// keymapper stuff
2017-09-14 22:57:20 -04:00
// 1 is down, 0 is up
const DOWN : i32 = 1 ;
const UP : i32 = 0 ;
2017-09-08 01:16:34 -04:00
trait KeyMapper {
2017-09-14 22:57:20 -04:00
fn send_event ( & mut self , event : input_event , device : & Device ) ;
}
struct LayoutSwitchKey {
key : u16 ,
down : bool ,
}
impl LayoutSwitchKey {
fn set_down ( & mut self , event : input_event ) {
self . down = event . value = = DOWN ;
}
2017-09-08 01:16:34 -04:00
}
2017-09-14 01:08:17 -04:00
struct KeyMaps {
2017-09-14 22:57:20 -04:00
keymaps : Vec < KeyMap > ,
keymap_index_keys : HashMap < u16 , usize > ,
switch_layout_keys : Vec < LayoutSwitchKey > ,
revert_default_key : u16 ,
revert_keymap_index : usize ,
// above do not change, below does
chosen_keymap_index : usize ,
current_keymap_index : usize ,
switch_layout_keys_pressed : bool ,
}
fn parse_key ( key_map : & HashMap < & 'static str , * const c_int > , key : & str ) -> u16 {
match key_map . get ( key . trim ( ) ) {
Some ( key_code ) = > * key_code as u16 ,
None = > panic! ( " unknown key: {} " , key . trim ( ) )
}
2017-09-14 01:08:17 -04:00
}
fn parse_keymap ( key_map : & HashMap < & 'static str , * const c_int > , keymap : & str ) -> Vec < u16 > {
2017-09-14 22:57:20 -04:00
keymap . split ( " , " ) . map ( | k | parse_key ( key_map , k ) ) . collect ( )
2017-09-14 01:08:17 -04:00
}
impl KeyMaps {
pub fn new ( key_map : & HashMap < & 'static str , * const c_int > , config : KeymapConfig ) -> KeyMaps {
if config . keymaps . len ( ) < 2 {
panic! ( " must have at least 2 keymaps (original and mapped) but only have {} , " , config . keymaps . len ( ) ) ;
}
2017-09-14 22:57:20 -04:00
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 ( ) ) ;
}
2017-09-14 01:08:17 -04:00
let base_keymap = parse_keymap ( key_map , & config . keymaps [ 0 ] ) ;
println! ( " base_keymap : {:?} " , base_keymap ) ;
let mut keymaps = vec! ( KeyMap ::new ( ) ) ;
2017-09-14 22:57:20 -04:00
let mut keymap_index_keys : HashMap < u16 , usize > = HashMap ::new ( ) ;
2017-09-14 01:08:17 -04:00
for ( x , v ) in config . keymaps . iter ( ) . enumerate ( ) {
2017-09-14 22:57:20 -04:00
keymap_index_keys . insert ( * key_map . get ( & * x . to_string ( ) ) . unwrap ( ) as u16 , x ) ;
2017-09-14 01:08:17 -04:00
if x = = 0 {
continue ;
}
let v = parse_keymap ( key_map , v ) ;
println! ( " config.keymaps[ {} ]: {:?} " , x , v ) ;
if v . len ( ) ! = base_keymap . len ( ) {
panic! ( " all keymaps must be the same length, keymap index 0 length: {} , index {} length: {} , " , base_keymap . len ( ) , x , v . len ( ) ) ;
}
let mut keymap = KeyMap ::new ( ) ;
for ( i , key_code ) in v . iter ( ) . enumerate ( ) {
keymap . map ( base_keymap [ i ] , * key_code ) ;
}
println! ( " keymap[ {} ]: {:?} " , x , & keymap . keymap [ .. ] ) ;
keymaps . push ( keymap ) ;
}
//println!("keymaps: {:?}", keymaps);
2017-09-14 22:57:20 -04:00
//println!("keymap_index_keys: {:?}", keymap_index_keys);
2017-09-14 01:08:17 -04:00
KeyMaps {
2017-09-14 22:57:20 -04:00
keymaps : keymaps ,
keymap_index_keys : keymap_index_keys ,
switch_layout_keys : config . switch_layout_keys . iter ( ) . map ( | k | LayoutSwitchKey { key : parse_key ( key_map , k ) , down : false } ) . collect ( ) ,
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 ,
switch_layout_keys_pressed : false ,
2017-09-14 01:08:17 -04:00
}
}
}
impl KeyMapper for KeyMaps {
2017-09-14 22:57:20 -04:00
fn send_event ( & mut self , event : input_event , device : & Device ) {
//println!("type: {} code: {} value: {}", event.type_, event.code, event.value);
if event . value ! = 2 {
let mut switch_layout_keys_pressed = true ;
for mut layout_switch_key in self . switch_layout_keys . iter_mut ( ) {
if event . code = = layout_switch_key . key {
layout_switch_key . set_down ( event ) ;
}
switch_layout_keys_pressed & = layout_switch_key . down ;
}
self . switch_layout_keys_pressed = switch_layout_keys_pressed ;
//println!("switch_layout_keys_pressed: {}", self.switch_layout_keys_pressed);
if self . 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
return ; // we don't want to also send this keypress, so bail
}
}
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...
1 = > self . current_keymap_index = self . revert_keymap_index ,
0 = > self . current_keymap_index = self . chosen_keymap_index ,
_ = > ( ) // do nothing for 2
}
}
}
self . keymaps [ self . current_keymap_index ] . send_event ( event , device ) ;
2017-09-14 01:08:17 -04:00
}
}
2017-09-08 01:16:34 -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 {
keymap : [ u16 ; KEY_MAX ] ,
}
impl KeyMap {
pub fn key_map ( ) -> HashMap < & 'static str , * const c_int > {
[
2017-09-14 01:08:17 -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 ) ,
2017-09-08 01:16:34 -04:00
( " 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 ) ,
2017-09-14 01:08:17 -04:00
( " LEFTBRACE " , KEY_LEFTBRACE ) ,
( " RIGHTBRACE " , KEY_RIGHTBRACE ) ,
( " ENTER " , KEY_ENTER ) ,
( " LEFTCTRL " , KEY_LEFTCTRL ) ,
2017-09-08 01:16:34 -04:00
( " 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 ) ,
2017-09-14 01:08:17 -04:00
( " SEMICOLON " , KEY_SEMICOLON ) ,
( " APOSTROPHE " , KEY_APOSTROPHE ) ,
( " GRAVE " , KEY_GRAVE ) ,
( " LEFTSHIFT " , KEY_LEFTSHIFT ) ,
( " BACKSLASH " , KEY_BACKSLASH ) ,
2017-09-08 01:16:34 -04:00
( " Z " , KEY_Z ) ,
( " X " , KEY_X ) ,
( " C " , KEY_C ) ,
( " V " , KEY_V ) ,
( " B " , KEY_B ) ,
( " N " , KEY_N ) ,
( " M " , KEY_M ) ,
2017-09-14 01:08:17 -04:00
( " COMMA " , KEY_COMMA ) ,
( " DOT " , KEY_DOT ) ,
( " SLASH " , KEY_SLASH ) ,
( " RIGHTSHIFT " , KEY_RIGHTSHIFT ) ,
( " KPASTERISK " , KEY_KPASTERISK ) ,
( " LEFTALT " , KEY_LEFTALT ) ,
( " SPACE " , KEY_SPACE ) ,
( " CAPSLOCK " , KEY_CAPSLOCK ) ,
2017-09-08 01:16:34 -04:00
( " 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 ) ,
2017-09-14 01:08:17 -04:00
( " 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 ) ,
2017-09-08 01:16:34 -04:00
( " F11 " , KEY_F11 ) ,
( " F12 " , KEY_F12 ) ,
2017-09-14 01:08:17 -04:00
( " 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 ) ,
2017-09-08 01:16:34 -04:00
( " 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 ) ,
2017-09-14 01:08:17 -04:00
( " 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 ) , // todo: is this right?
( " 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-09-08 01:16:34 -04:00
] . iter ( ) . cloned ( ) . map ( | ( m , v ) | ( m , v as * const c_int ) ) . collect ( )
}
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 ;
}
2017-09-14 01:08:17 -04:00
//println!("keymap: {:?}", &keymap[..]);
2017-09-08 01:16:34 -04:00
KeyMap {
keymap : keymap
}
}
2017-09-14 01:08:17 -04:00
pub fn map ( & mut self , from : u16 , to : u16 ) {
self . keymap [ from as usize ] = to ;
2017-09-08 01:16:34 -04:00
}
}
impl KeyMapper for KeyMap {
2017-09-14 22:57:20 -04:00
fn send_event ( & mut self , mut event : input_event , device : & Device ) {
2017-09-08 01:16:34 -04:00
event . code = self . keymap [ event . code as usize ] ;
device . write_event ( event ) . expect ( " could not write event? " ) ;
}
2017-09-14 01:08:17 -04:00
}
#[ macro_use ]
extern crate serde_derive ;
extern crate toml ;
use std ::path ::Path ;
#[ derive(Deserialize, Debug) ]
struct KeymapConfig {
switch_layout_keys : Vec < String > ,
revert_default_key : String ,
revert_keymap_index : usize ,
default_keymap_index : usize ,
caps_lock_modify : String ,
keymaps : Vec < String >
}
use std ::io ::{ Error , ErrorKind } ;
fn parse_cfg < P : AsRef < Path > > ( path : P ) -> Result < KeymapConfig , Error > {
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 ) ,
Err ( _ ) = > Err ( Error ::new ( ErrorKind ::Other , " oh no! " ) )
}
}