Format all code
This commit is contained in:
parent
270cdca14f
commit
82421be440
75
src/error.rs
75
src/error.rs
@ -1,7 +1,4 @@
|
|||||||
use std::fmt;
|
use std::{error, ffi, fmt, io};
|
||||||
use std::error;
|
|
||||||
use std::ffi;
|
|
||||||
use std::io;
|
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
use nix;
|
use nix;
|
||||||
@ -9,66 +6,66 @@ use nix;
|
|||||||
/// UInput error.
|
/// UInput error.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
/// System errors.
|
/// System errors.
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
Nix(nix::Error),
|
Nix(nix::Error),
|
||||||
|
|
||||||
/// Errors with internal nulls in names.
|
/// Errors with internal nulls in names.
|
||||||
Nul(ffi::NulError),
|
Nul(ffi::NulError),
|
||||||
|
|
||||||
Io(io::Error),
|
Io(io::Error),
|
||||||
|
|
||||||
#[cfg(feature = "toml_serde")]
|
#[cfg(feature = "toml_serde")]
|
||||||
Toml(toml::de::Error),
|
Toml(toml::de::Error),
|
||||||
|
|
||||||
NotAKeyboard,
|
NotAKeyboard,
|
||||||
|
|
||||||
/// error reading input_event
|
/// error reading input_event
|
||||||
ShortRead,
|
ShortRead,
|
||||||
|
|
||||||
/// epoll already added
|
/// epoll already added
|
||||||
EpollAlreadyAdded,
|
EpollAlreadyAdded,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ffi::NulError> for Error {
|
impl From<ffi::NulError> for Error {
|
||||||
fn from(value: ffi::NulError) -> Self {
|
fn from(value: ffi::NulError) -> Self {
|
||||||
Error::Nul(value)
|
Error::Nul(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
impl From<nix::Error> for Error {
|
impl From<nix::Error> for Error {
|
||||||
fn from(value: nix::Error) -> Self {
|
fn from(value: nix::Error) -> Self {
|
||||||
Error::Nix(value)
|
Error::Nix(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<io::Error> for Error {
|
impl From<io::Error> for Error {
|
||||||
fn from(value: io::Error) -> Self {
|
fn from(value: io::Error) -> Self {
|
||||||
Error::Io(value)
|
Error::Io(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Error {
|
impl fmt::Display for Error {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||||
match self {
|
match self {
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
&Error::Nix(ref err) => err.fmt(f),
|
&Error::Nix(ref err) => err.fmt(f),
|
||||||
|
|
||||||
&Error::Nul(ref err) => err.fmt(f),
|
&Error::Nul(ref err) => err.fmt(f),
|
||||||
|
|
||||||
&Error::Io(ref err) => err.fmt(f),
|
&Error::Io(ref err) => err.fmt(f),
|
||||||
|
|
||||||
#[cfg(feature = "toml_serde")]
|
#[cfg(feature = "toml_serde")]
|
||||||
&Error::Toml(ref err) => err.fmt(f),
|
&Error::Toml(ref err) => err.fmt(f),
|
||||||
|
|
||||||
&Error::NotAKeyboard => f.write_str("This device file is not a keyboard"),
|
&Error::NotAKeyboard => f.write_str("This device file is not a keyboard"),
|
||||||
|
|
||||||
&Error::ShortRead => f.write_str("Error while reading from device file."),
|
&Error::ShortRead => f.write_str("Error while reading from device file."),
|
||||||
|
|
||||||
&Error::EpollAlreadyAdded => f.write_str("epoll already added, delete first"),
|
&Error::EpollAlreadyAdded => f.write_str("epoll already added, delete first"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl error::Error for Error {}
|
impl error::Error for Error {}
|
||||||
|
272
src/keymapper.rs
272
src/keymapper.rs
@ -1,7 +1,4 @@
|
|||||||
|
use std::{collections::HashMap, convert::TryFrom, hash::Hash};
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::hash::Hash;
|
|
||||||
use std::convert::TryFrom;
|
|
||||||
|
|
||||||
#[cfg(feature = "toml_serde")]
|
#[cfg(feature = "toml_serde")]
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
@ -23,17 +20,17 @@ pub enum KeyState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait KeyEvent<T>
|
pub trait KeyEvent<T>
|
||||||
where
|
where
|
||||||
T: Into<usize>,
|
T: Into<usize>,
|
||||||
{
|
{
|
||||||
fn code(&self) -> T;
|
fn code(&self) -> T;
|
||||||
fn value(&self) -> KeyState;
|
fn value(&self) -> KeyState;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Keyboard<T, E, R = ()>
|
pub trait Keyboard<T, E, R = ()>
|
||||||
where
|
where
|
||||||
T: Into<usize> + Copy,
|
T: Into<usize> + Copy,
|
||||||
E: KeyEvent<T>,
|
E: KeyEvent<T>,
|
||||||
{
|
{
|
||||||
fn send(&self, event: &mut E) -> Result<R>;
|
fn send(&self, event: &mut E) -> Result<R>;
|
||||||
fn send_mod_code(&self, code: T, event: &mut E) -> Result<R>;
|
fn send_mod_code(&self, code: T, event: &mut E) -> Result<R>;
|
||||||
@ -44,7 +41,14 @@ pub trait Keyboard<T, E, R = ()>
|
|||||||
fn caps_lock_code(&self) -> T;
|
fn caps_lock_code(&self) -> T;
|
||||||
fn block_key(&self) -> Result<R>;
|
fn block_key(&self) -> Result<R>;
|
||||||
|
|
||||||
fn send_half_inverted_key(&self, half_inverted_key: &HalfInvertedKey<T>, event: &mut E, left_shift: bool, right_shift: bool, caps_lock: bool) -> Result<R> {
|
fn send_half_inverted_key(
|
||||||
|
&self,
|
||||||
|
half_inverted_key: &HalfInvertedKey<T>,
|
||||||
|
event: &mut E,
|
||||||
|
left_shift: bool,
|
||||||
|
right_shift: bool,
|
||||||
|
caps_lock: bool,
|
||||||
|
) -> Result<R> {
|
||||||
let value = event.value();
|
let value = event.value();
|
||||||
let mut invert_shift = half_inverted_key.invert_shift;
|
let mut invert_shift = half_inverted_key.invert_shift;
|
||||||
if value == KeyState::DOWN {
|
if value == KeyState::DOWN {
|
||||||
@ -87,19 +91,19 @@ pub trait Keyboard<T, E, R = ()>
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait KeyMapper<K, T, E, R>
|
pub trait KeyMapper<K, T, E, R>
|
||||||
where
|
where
|
||||||
T: Into<usize> + Copy,
|
T: Into<usize> + Copy,
|
||||||
E: KeyEvent<T>,
|
E: KeyEvent<T>,
|
||||||
K: Keyboard<T, E, R>,
|
K: Keyboard<T, E, R>,
|
||||||
{
|
{
|
||||||
fn send_event(&self, key_state: &[bool], event: &mut E, device: &K) -> Result<R>;
|
fn send_event(&self, key_state: &[bool], event: &mut E, device: &K) -> Result<R>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct KeyMaps<K, T, E, R = ()>
|
pub struct KeyMaps<K, T, E, R = ()>
|
||||||
where
|
where
|
||||||
T: Into<usize> + Copy + Clone + Eq + Hash,
|
T: Into<usize> + Copy + Clone + Eq + Hash,
|
||||||
E: KeyEvent<T>,
|
E: KeyEvent<T>,
|
||||||
K: Keyboard<T, E, R>,
|
K: Keyboard<T, E, R>,
|
||||||
{
|
{
|
||||||
keymaps: Vec<Box<dyn KeyMapper<K, T, E, R>>>,
|
keymaps: Vec<Box<dyn KeyMapper<K, T, E, R>>>,
|
||||||
keymap_index_keys: HashMap<T, usize>,
|
keymap_index_keys: HashMap<T, usize>,
|
||||||
@ -113,17 +117,25 @@ pub struct KeyMaps<K, T, E, R = ()>
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn parse_key<T: Clone + Copy>(key_map: &HashMap<&'static str, T>, key: &str) -> T {
|
fn parse_key<T: Clone + Copy>(key_map: &HashMap<&'static str, T>, key: &str) -> T {
|
||||||
match key_map.get(key.trim_matches(|c: char| c.is_whitespace() || c == INVERT_KEY_FLAG || c == CAPS_MODIFY_KEY_FLAG)) {
|
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,
|
Some(key_code) => *key_code,
|
||||||
None => panic!("unknown key: {}", key.trim())
|
None => panic!("unknown key: {}", key.trim()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_keymap_numeric<T: Clone + Copy>(key_map: &HashMap<&'static str, T>, keymap: &str) -> Vec<T> {
|
fn parse_keymap_numeric<T: Clone + Copy>(
|
||||||
|
key_map: &HashMap<&'static str, T>,
|
||||||
|
keymap: &str,
|
||||||
|
) -> Vec<T> {
|
||||||
keymap.split(",").map(|k| parse_key(key_map, k)).collect()
|
keymap.split(",").map(|k| parse_key(key_map, k)).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_key_half_inverted<T: Clone + Copy>(key_map: &HashMap<&'static str, T>, key: &str) -> HalfInvertedKey<T> {
|
fn parse_key_half_inverted<T: Clone + Copy>(
|
||||||
|
key_map: &HashMap<&'static str, T>,
|
||||||
|
key: &str,
|
||||||
|
) -> HalfInvertedKey<T> {
|
||||||
HalfInvertedKey {
|
HalfInvertedKey {
|
||||||
code: parse_key(key_map, key),
|
code: parse_key(key_map, key),
|
||||||
invert_shift: key.contains(INVERT_KEY_FLAG),
|
invert_shift: key.contains(INVERT_KEY_FLAG),
|
||||||
@ -138,53 +150,70 @@ fn parse_keymap_u16<T: Clone + Copy>(key_map: &HashMap<&'static str, T>, keymap:
|
|||||||
|
|
||||||
// todo: how do I return an iterator here instead of .collect to Vec?
|
// todo: how do I return an iterator here instead of .collect to Vec?
|
||||||
fn parse_keymap<T: Copy>(key_map: &HashMap<&'static str, T>, keymap: &str) -> Vec<Key<T>> {
|
fn parse_keymap<T: Copy>(key_map: &HashMap<&'static str, T>, keymap: &str) -> Vec<Key<T>> {
|
||||||
keymap.split(",").map(|k| {
|
keymap
|
||||||
let ret: Key<T> = if k.contains(HALF_KEY_SEPARATOR) {
|
.split(",")
|
||||||
let keys: Vec<&str> = k.split(HALF_KEY_SEPARATOR).collect();
|
.map(|k| {
|
||||||
if keys.len() != 2 {
|
let ret: Key<T> = if k.contains(HALF_KEY_SEPARATOR) {
|
||||||
panic!("split key can only have 2 keys, 1 :, has {} keys", keys.len());
|
let keys: Vec<&str> = k.split(HALF_KEY_SEPARATOR).collect();
|
||||||
}
|
if keys.len() != 2 {
|
||||||
let mut shift_half = parse_key_half_inverted(key_map, keys[1]);
|
panic!(
|
||||||
shift_half.invert_shift = !shift_half.invert_shift;
|
"split key can only have 2 keys, 1 :, has {} keys",
|
||||||
Key::FullKey(parse_key_half_inverted(key_map, keys[0]), shift_half)
|
keys.len()
|
||||||
} else if k.contains(INVERT_KEY_FLAG) || k.contains(CAPS_MODIFY_KEY_FLAG) {
|
);
|
||||||
Key::HalfKey(parse_key_half_inverted(key_map, k))
|
}
|
||||||
} else {
|
let mut shift_half = parse_key_half_inverted(key_map, keys[1]);
|
||||||
Key::Direct(parse_key(key_map, k))
|
shift_half.invert_shift = !shift_half.invert_shift;
|
||||||
};
|
Key::FullKey(parse_key_half_inverted(key_map, keys[0]), shift_half)
|
||||||
ret
|
} else if k.contains(INVERT_KEY_FLAG) || k.contains(CAPS_MODIFY_KEY_FLAG) {
|
||||||
}).collect()
|
Key::HalfKey(parse_key_half_inverted(key_map, k))
|
||||||
|
} else {
|
||||||
|
Key::Direct(parse_key(key_map, k))
|
||||||
|
};
|
||||||
|
ret
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<K, T, E, R> KeyMaps<K, T, E, R>
|
impl<K, T, E, R> KeyMaps<K, T, E, R>
|
||||||
where
|
where
|
||||||
T: Into<usize> + TryFrom<usize> + Copy + Clone + Eq + Hash + Default + 'static,
|
T: Into<usize> + TryFrom<usize> + Copy + Clone + Eq + Hash + Default + 'static,
|
||||||
E: KeyEvent<T>,
|
E: KeyEvent<T>,
|
||||||
K: Keyboard<T, E, R>,
|
K: Keyboard<T, E, R>,
|
||||||
{
|
{
|
||||||
#[cfg(feature = "toml_serde")]
|
#[cfg(feature = "toml_serde")]
|
||||||
pub fn from_cfg<P: AsRef<Path>>(key_map: &HashMap<&'static str, T>, path: P) -> KeyMaps<K, T, E, R> {
|
pub fn from_cfg<P: AsRef<Path>>(
|
||||||
|
key_map: &HashMap<&'static str, T>,
|
||||||
|
path: P,
|
||||||
|
) -> KeyMaps<K, T, E, R> {
|
||||||
let key_map_config = parse_cfg(path).expect("provided config cannot be found/parsed");
|
let key_map_config = parse_cfg(path).expect("provided config cannot be found/parsed");
|
||||||
KeyMaps::new(key_map, key_map_config)
|
KeyMaps::new(key_map, key_map_config)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(key_map: &HashMap<&'static str, T>, config: KeymapConfig) -> KeyMaps<K, T, E, R> {
|
pub fn new(key_map: &HashMap<&'static str, T>, config: KeymapConfig) -> KeyMaps<K, T, E, R> {
|
||||||
if config.keymaps.len() < 2 {
|
if config.keymaps.len() < 2 {
|
||||||
panic!("must have at least 2 keymaps (original and mapped) but only have {},", config.keymaps.len());
|
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() {
|
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());
|
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]);
|
let base_keymap = parse_keymap_numeric(key_map, &config.keymaps[0]);
|
||||||
//println!("base_keymap : {:?}", base_keymap);
|
//println!("base_keymap : {:?}", base_keymap);
|
||||||
let mut keymaps: Vec<Box<dyn KeyMapper<K, T, E, R>>> = vec!(Box::new(Key::Noop)); // todo: can we share the box?
|
let mut keymaps: Vec<Box<dyn KeyMapper<K, T, E, R>>> = vec![Box::new(Key::Noop)]; // todo: can we share the box?
|
||||||
let mut keymap_index_keys: HashMap<T, usize> = HashMap::new();
|
let mut keymap_index_keys: HashMap<T, usize> = HashMap::new();
|
||||||
for (x, v) in config.keymaps.iter().enumerate() {
|
for (x, v) in config.keymaps.iter().enumerate() {
|
||||||
keymap_index_keys.insert(*key_map.get(&*x.to_string()).unwrap(), x);
|
keymap_index_keys.insert(*key_map.get(&*x.to_string()).unwrap(), x);
|
||||||
if x == 0 {
|
if x == 0 {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if v.contains(HALF_KEY_SEPARATOR) || v.contains(INVERT_KEY_FLAG) || v.contains(CAPS_MODIFY_KEY_FLAG) {
|
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
|
// we need KeyMap, the complicated more memory taking one
|
||||||
let v = parse_keymap(key_map, v);
|
let v = parse_keymap(key_map, v);
|
||||||
let mut keymap = KeyMap::new();
|
let mut keymap = KeyMap::new();
|
||||||
@ -241,7 +270,11 @@ impl<K, T, E, R> KeyMaps<K, T, E, R>
|
|||||||
KeyMaps {
|
KeyMaps {
|
||||||
keymaps: keymaps,
|
keymaps: keymaps,
|
||||||
keymap_index_keys: keymap_index_keys,
|
keymap_index_keys: keymap_index_keys,
|
||||||
switch_layout_keys: config.switch_layout_keys.iter().map(|k| parse_key(key_map, k).into()).collect(),
|
switch_layout_keys: config
|
||||||
|
.switch_layout_keys
|
||||||
|
.iter()
|
||||||
|
.map(|k| parse_key(key_map, k).into())
|
||||||
|
.collect(),
|
||||||
key_state: [false; KEY_MAX],
|
key_state: [false; KEY_MAX],
|
||||||
// todo: detect key state? at least CAPSLOCK...
|
// todo: detect key state? at least CAPSLOCK...
|
||||||
revert_default_keys,
|
revert_default_keys,
|
||||||
@ -250,17 +283,18 @@ impl<K, T, E, R> KeyMaps<K, T, E, R>
|
|||||||
current_keymap_index: config.default_keymap_index,
|
current_keymap_index: config.default_keymap_index,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//}
|
//}
|
||||||
|
|
||||||
//impl KeyMapper for KeyMaps {
|
//impl KeyMapper for KeyMaps {
|
||||||
//impl KeyMaps {
|
//impl KeyMaps {
|
||||||
pub fn send_event(&mut self, mut event: &mut E, device: &K) -> Result<R> {
|
pub fn send_event(&mut self, mut event: &mut E, device: &K) -> Result<R> {
|
||||||
let value = event.value();
|
let value = event.value();
|
||||||
if value != KeyState::OTHER {
|
if value != KeyState::OTHER {
|
||||||
// todo: index check here...
|
// todo: index check here...
|
||||||
if event.code() == device.caps_lock_code() {
|
if event.code() == device.caps_lock_code() {
|
||||||
if value == KeyState::DOWN {
|
if value == KeyState::DOWN {
|
||||||
self.key_state[device.caps_lock_code().into()] = !self.key_state[device.caps_lock_code().into()];
|
self.key_state[device.caps_lock_code().into()] =
|
||||||
|
!self.key_state[device.caps_lock_code().into()];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let idx = event.code().into();
|
let idx = event.code().into();
|
||||||
@ -286,28 +320,35 @@ pub fn send_event(&mut self, mut event: &mut E, device: &K) -> Result<R> {
|
|||||||
return device.block_key(); // we don't want to also send this keypress, so bail
|
return device.block_key(); // we don't want to also send this keypress, so bail
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if self.revert_default_keys.contains(&event.code()) {
|
if self.revert_default_keys.contains(&event.code()) {
|
||||||
match value {
|
match value {
|
||||||
KeyState::DOWN => {
|
KeyState::DOWN => {
|
||||||
// todo: should we release currently held keys and then press them back down here, kinda the opposite of below? not for now...
|
// todo: should we release currently held keys and then press them back down here, kinda the opposite of below? not for now...
|
||||||
self.current_keymap_index = self.revert_keymap_index
|
self.current_keymap_index = self.revert_keymap_index
|
||||||
},
|
}
|
||||||
KeyState::UP => {
|
KeyState::UP => {
|
||||||
self.current_keymap_index = self.chosen_keymap_index;
|
self.current_keymap_index = self.chosen_keymap_index;
|
||||||
#[cfg(not(target_os = "macos"))] {
|
#[cfg(not(target_os = "macos"))]
|
||||||
// need to release all currently held down keys, except this one, otherwise 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
|
{
|
||||||
let orig_code = event.code();
|
// need to release all currently held down keys, except this one, otherwise 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
|
||||||
for (idx, key_down) in self.key_state.iter_mut().enumerate() {
|
let orig_code = event.code();
|
||||||
if *key_down {
|
for (idx, key_down) in self.key_state.iter_mut().enumerate() {
|
||||||
device.send_mod_code_value(T::try_from(idx).unwrap_or_else(|_| panic!("cannot convert from usize to T ????")), true, event)?;
|
if *key_down {
|
||||||
*key_down = false;
|
device.send_mod_code_value(
|
||||||
|
T::try_from(idx).unwrap_or_else(|_| {
|
||||||
|
panic!("cannot convert from usize to T ????")
|
||||||
|
}),
|
||||||
|
true,
|
||||||
|
event,
|
||||||
|
)?;
|
||||||
|
*key_down = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// todo: seems like we should not send this here, and instead just set the original code back, and pass it through the keymaps?
|
||||||
|
return device.send_mod_code_value(orig_code, true, event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// todo: seems like we should not send this here, and instead just set the original code back, and pass it through the keymaps?
|
_ => (), // do nothing for 2
|
||||||
return device.send_mod_code_value(orig_code, true, event)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => () // do nothing for 2
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -325,7 +366,7 @@ struct KeyMap<T: Into<usize> + Copy> {
|
|||||||
impl<T: Into<usize> + Copy> KeyMap<T> {
|
impl<T: Into<usize> + Copy> KeyMap<T> {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
KeyMap {
|
KeyMap {
|
||||||
keymap: [Key::Noop; KEY_MAX]
|
keymap: [Key::Noop; KEY_MAX],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -335,10 +376,10 @@ impl<T: Into<usize> + Copy> KeyMap<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<K, T, E, R> KeyMapper<K, T, E, R> for KeyMap<T>
|
impl<K, T, E, R> KeyMapper<K, T, E, R> for KeyMap<T>
|
||||||
where
|
where
|
||||||
T: Into<usize> + Copy,
|
T: Into<usize> + Copy,
|
||||||
E: KeyEvent<T>,
|
E: KeyEvent<T>,
|
||||||
K: Keyboard<T, E, R>,
|
K: Keyboard<T, E, R>,
|
||||||
{
|
{
|
||||||
fn send_event(&self, key_state: &[bool], event: &mut E, device: &K) -> Result<R> {
|
fn send_event(&self, key_state: &[bool], event: &mut E, device: &K) -> Result<R> {
|
||||||
self.keymap[event.code().into()].send_event(key_state, event, device)
|
self.keymap[event.code().into()].send_event(key_state, event, device)
|
||||||
@ -356,9 +397,7 @@ impl<T: Into<usize> + TryFrom<usize> + Copy + Default> CodeKeyMap<T> {
|
|||||||
*v = T::try_from(x).unwrap_or_else(|_| panic!("cannot convert from usize to T ????"));
|
*v = T::try_from(x).unwrap_or_else(|_| panic!("cannot convert from usize to T ????"));
|
||||||
}
|
}
|
||||||
//println!("keymap: {:?}", &keymap[..]);
|
//println!("keymap: {:?}", &keymap[..]);
|
||||||
CodeKeyMap {
|
CodeKeyMap { keymap }
|
||||||
keymap
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn map(&mut self, from: T, to: T) {
|
pub fn map(&mut self, from: T, to: T) {
|
||||||
@ -367,10 +406,10 @@ impl<T: Into<usize> + TryFrom<usize> + Copy + Default> CodeKeyMap<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<K, T, E, R> KeyMapper<K, T, E, R> for CodeKeyMap<T>
|
impl<K, T, E, R> KeyMapper<K, T, E, R> for CodeKeyMap<T>
|
||||||
where
|
where
|
||||||
T: Into<usize> + TryFrom<usize> + Copy + Default,
|
T: Into<usize> + TryFrom<usize> + Copy + Default,
|
||||||
E: KeyEvent<T>,
|
E: KeyEvent<T>,
|
||||||
K: Keyboard<T, E, R>,
|
K: Keyboard<T, E, R>,
|
||||||
{
|
{
|
||||||
fn send_event(&self, _key_state: &[bool], event: &mut E, device: &K) -> Result<R> {
|
fn send_event(&self, _key_state: &[bool], event: &mut E, device: &K) -> Result<R> {
|
||||||
device.send_mod_code(self.keymap[event.code().into()], event)
|
device.send_mod_code(self.keymap[event.code().into()], event)
|
||||||
@ -390,10 +429,10 @@ pub struct HalfInvertedKey<T: Clone + Copy> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<K, T, E, R> KeyMapper<K, T, E, R> for HalfInvertedKey<T>
|
impl<K, T, E, R> KeyMapper<K, T, E, R> for HalfInvertedKey<T>
|
||||||
where
|
where
|
||||||
T: Into<usize> + Clone + Copy,
|
T: Into<usize> + Clone + Copy,
|
||||||
E: KeyEvent<T>,
|
E: KeyEvent<T>,
|
||||||
K: Keyboard<T, E, R>,
|
K: Keyboard<T, E, R>,
|
||||||
{
|
{
|
||||||
fn send_event(&self, key_state: &[bool], event: &mut E, device: &K) -> Result<R> {
|
fn send_event(&self, key_state: &[bool], event: &mut E, device: &K) -> Result<R> {
|
||||||
let left_shift = key_state[device.left_shift_code().into()];
|
let left_shift = key_state[device.left_shift_code().into()];
|
||||||
@ -405,8 +444,8 @@ impl<K, T, E, R> KeyMapper<K, T, E, R> for HalfInvertedKey<T>
|
|||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
enum Key<T>
|
enum Key<T>
|
||||||
where
|
where
|
||||||
T: Copy + Clone
|
T: Copy + Clone,
|
||||||
{
|
{
|
||||||
Noop,
|
Noop,
|
||||||
Direct(T),
|
Direct(T),
|
||||||
@ -415,32 +454,38 @@ enum Key<T>
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<K, T, E, R> KeyMapper<K, T, E, R> for Key<T>
|
impl<K, T, E, R> KeyMapper<K, T, E, R> for Key<T>
|
||||||
where
|
where
|
||||||
T: Into<usize> + Copy,
|
T: Into<usize> + Copy,
|
||||||
E: KeyEvent<T>,
|
E: KeyEvent<T>,
|
||||||
K: Keyboard<T, E, R>,
|
K: Keyboard<T, E, R>,
|
||||||
{
|
{
|
||||||
fn send_event(&self, key_state: &[bool], event: &mut E, device: &K) -> Result<R> {
|
fn send_event(&self, key_state: &[bool], event: &mut E, device: &K) -> Result<R> {
|
||||||
match *self {
|
match *self {
|
||||||
Key::Noop => {
|
Key::Noop => device.send(event),
|
||||||
device.send(event)
|
Key::Direct(code) => device.send_mod_code(code, event),
|
||||||
},
|
Key::HalfKey(ref key_half) => key_half.send_event(key_state, event, device),
|
||||||
Key::Direct(code) => {
|
|
||||||
device.send_mod_code(code, event)
|
|
||||||
},
|
|
||||||
Key::HalfKey(ref key_half) => {
|
|
||||||
key_half.send_event(key_state, event, device)
|
|
||||||
},
|
|
||||||
Key::FullKey(ref noshift_half, ref shift_half) => {
|
Key::FullKey(ref noshift_half, ref shift_half) => {
|
||||||
let left_shift = key_state[device.left_shift_code().into()];
|
let left_shift = key_state[device.left_shift_code().into()];
|
||||||
let right_shift = key_state[device.right_shift_code().into()];
|
let right_shift = key_state[device.right_shift_code().into()];
|
||||||
let caps_lock = key_state[device.caps_lock_code().into()];
|
let caps_lock = key_state[device.caps_lock_code().into()];
|
||||||
if caps_lock != (left_shift || right_shift) {
|
if caps_lock != (left_shift || right_shift) {
|
||||||
device.send_half_inverted_key(shift_half, event, left_shift, right_shift, caps_lock)
|
device.send_half_inverted_key(
|
||||||
|
shift_half,
|
||||||
|
event,
|
||||||
|
left_shift,
|
||||||
|
right_shift,
|
||||||
|
caps_lock,
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
device.send_half_inverted_key(noshift_half, event, left_shift, right_shift, caps_lock)
|
device.send_half_inverted_key(
|
||||||
|
noshift_half,
|
||||||
|
event,
|
||||||
|
left_shift,
|
||||||
|
right_shift,
|
||||||
|
caps_lock,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -453,7 +498,7 @@ pub struct KeymapConfig {
|
|||||||
revert_default_keys: Option<Vec<String>>,
|
revert_default_keys: Option<Vec<String>>,
|
||||||
revert_keymap_index: usize,
|
revert_keymap_index: usize,
|
||||||
default_keymap_index: usize,
|
default_keymap_index: usize,
|
||||||
keymaps: Vec<String>
|
keymaps: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "toml_serde")]
|
#[cfg(feature = "toml_serde")]
|
||||||
@ -473,7 +518,7 @@ pub struct KeymapConfig {
|
|||||||
revert_default_keys: Option<Vec<&'static str>>,
|
revert_default_keys: Option<Vec<&'static str>>,
|
||||||
revert_keymap_index: usize,
|
revert_keymap_index: usize,
|
||||||
default_keymap_index: usize,
|
default_keymap_index: usize,
|
||||||
keymaps: Vec<&'static str>
|
keymaps: Vec<&'static str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "toml_serde"))]
|
#[cfg(not(feature = "toml_serde"))]
|
||||||
@ -528,4 +573,3 @@ impl Default for KeymapConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,12 +1,7 @@
|
|||||||
use std::path::Path;
|
use crate::{Device, Result};
|
||||||
use std::{mem, slice};
|
|
||||||
use std::ffi::CString;
|
|
||||||
use libc::c_int;
|
use libc::c_int;
|
||||||
use nix::{self, fcntl, unistd, ioctl_write_ptr, ioctl_none};
|
use nix::{self, fcntl, ioctl_none, ioctl_write_ptr, sys::stat, unistd};
|
||||||
use nix::sys::stat;
|
use std::{collections::hash_map::Values, ffi::CString, mem, os::raw::c_char, path::Path, slice};
|
||||||
use crate::{Result, Device};
|
|
||||||
use std::collections::hash_map::Values;
|
|
||||||
use std::os::raw::c_char;
|
|
||||||
|
|
||||||
use crate::linux::device::codes::*;
|
use crate::linux::device::codes::*;
|
||||||
|
|
||||||
@ -21,131 +16,134 @@ pub const ABS_CNT: c_int = ABS_MAX + 1;
|
|||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct input_id {
|
pub struct input_id {
|
||||||
pub bustype: u16,
|
pub bustype: u16,
|
||||||
pub vendor: u16,
|
pub vendor: u16,
|
||||||
pub product: u16,
|
pub product: u16,
|
||||||
pub version: u16,
|
pub version: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct uinput_user_dev {
|
pub struct uinput_user_dev {
|
||||||
pub name: [c_char; UINPUT_MAX_NAME_SIZE as usize],
|
pub name: [c_char; UINPUT_MAX_NAME_SIZE as usize],
|
||||||
pub id: input_id,
|
pub id: input_id,
|
||||||
|
|
||||||
pub ff_effects_max: u32,
|
pub ff_effects_max: u32,
|
||||||
pub absmax: [i32; ABS_CNT as usize],
|
pub absmax: [i32; ABS_CNT as usize],
|
||||||
pub absmin: [i32; ABS_CNT as usize],
|
pub absmin: [i32; ABS_CNT as usize],
|
||||||
pub absfuzz: [i32; ABS_CNT as usize],
|
pub absfuzz: [i32; ABS_CNT as usize],
|
||||||
pub absflat: [i32; ABS_CNT as usize],
|
pub absflat: [i32; ABS_CNT as usize],
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Device builder.
|
/// Device builder.
|
||||||
pub struct Builder {
|
pub struct Builder {
|
||||||
fd: c_int,
|
fd: c_int,
|
||||||
def: uinput_user_dev,
|
def: uinput_user_dev,
|
||||||
abs: Option<c_int>,
|
abs: Option<c_int>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Builder {
|
impl Builder {
|
||||||
/// Create a builder from the specified path.
|
/// Create a builder from the specified path.
|
||||||
pub fn open<P: AsRef<Path>>(path: P) -> Result<Self> {
|
pub fn open<P: AsRef<Path>>(path: P) -> Result<Self> {
|
||||||
Ok(Builder {
|
Ok(Builder {
|
||||||
fd: fcntl::open(path.as_ref(), fcntl::OFlag::O_WRONLY | fcntl::OFlag::O_NONBLOCK, stat::Mode::empty())?,
|
fd: fcntl::open(
|
||||||
def: unsafe { mem::zeroed() },
|
path.as_ref(),
|
||||||
abs: None,
|
fcntl::OFlag::O_WRONLY | fcntl::OFlag::O_NONBLOCK,
|
||||||
})
|
stat::Mode::empty(),
|
||||||
}
|
)?,
|
||||||
|
def: unsafe { mem::zeroed() },
|
||||||
|
abs: None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// Create a builder from `/dev/uinput`.
|
/// Create a builder from `/dev/uinput`.
|
||||||
pub fn default() -> Result<Self> {
|
pub fn default() -> Result<Self> {
|
||||||
Builder::open("/dev/uinput")
|
Builder::open("/dev/uinput")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the name.
|
/// Set the name.
|
||||||
pub fn name<T: AsRef<str>>(mut self, value: T) -> Result<Self> {
|
pub fn name<T: AsRef<str>>(mut self, value: T) -> Result<Self> {
|
||||||
let string = CString::new(value.as_ref())?;
|
let string = CString::new(value.as_ref())?;
|
||||||
let bytes = string.as_bytes_with_nul();
|
let bytes = string.as_bytes_with_nul();
|
||||||
|
|
||||||
if bytes.len() > UINPUT_MAX_NAME_SIZE as usize {
|
if bytes.len() > UINPUT_MAX_NAME_SIZE as usize {
|
||||||
Err(nix::Error::EINVAL)?;
|
Err(nix::Error::EINVAL)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
(&mut self.def.name)[..bytes.len()]
|
(&mut self.def.name)[..bytes.len()].clone_from_slice(unsafe { mem::transmute(bytes) });
|
||||||
.clone_from_slice(unsafe { mem::transmute(bytes) });
|
|
||||||
|
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the bus type.
|
/// Set the bus type.
|
||||||
pub fn bus(mut self, value: u16) -> Self {
|
pub fn bus(mut self, value: u16) -> Self {
|
||||||
self.def.id.bustype = value;
|
self.def.id.bustype = value;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the vendor ID.
|
/// Set the vendor ID.
|
||||||
pub fn vendor(mut self, value: u16) -> Self {
|
pub fn vendor(mut self, value: u16) -> Self {
|
||||||
self.def.id.vendor = value;
|
self.def.id.vendor = value;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the product ID.
|
/// Set the product ID.
|
||||||
pub fn product(mut self, value: u16) -> Self {
|
pub fn product(mut self, value: u16) -> Self {
|
||||||
self.def.id.product = value;
|
self.def.id.product = value;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the version.
|
/// Set the version.
|
||||||
pub fn version(mut self, value: u16) -> Self {
|
pub fn version(mut self, value: u16) -> Self {
|
||||||
self.def.id.version = value;
|
self.def.id.version = value;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn event(mut self, key_codes: Values<&str, u16>) -> Result<Self> {
|
pub fn event(mut self, key_codes: Values<&str, u16>) -> Result<Self> {
|
||||||
self.abs = None;
|
self.abs = None;
|
||||||
unsafe {
|
unsafe {
|
||||||
ui_set_evbit(self.fd, EV_KEY as *const c_int)?;
|
ui_set_evbit(self.fd, EV_KEY as *const c_int)?;
|
||||||
|
|
||||||
for key_code in key_codes {
|
for key_code in key_codes {
|
||||||
ui_set_keybit(self.fd, *key_code as *const c_int)?;
|
ui_set_keybit(self.fd, *key_code as *const c_int)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the maximum value for the previously enabled absolute event.
|
/// Set the maximum value for the previously enabled absolute event.
|
||||||
pub fn max(mut self, value: i32) -> Self {
|
pub fn max(mut self, value: i32) -> Self {
|
||||||
self.def.absmax[self.abs.unwrap() as usize] = value;
|
self.def.absmax[self.abs.unwrap() as usize] = value;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the minimum value for the previously enabled absolute event.
|
/// Set the minimum value for the previously enabled absolute event.
|
||||||
pub fn min(mut self, value: i32) -> Self {
|
pub fn min(mut self, value: i32) -> Self {
|
||||||
self.def.absmin[self.abs.unwrap() as usize] = value;
|
self.def.absmin[self.abs.unwrap() as usize] = value;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the fuzz value for the previously enabled absolute event.
|
/// Set the fuzz value for the previously enabled absolute event.
|
||||||
pub fn fuzz(mut self, value: i32) -> Self {
|
pub fn fuzz(mut self, value: i32) -> Self {
|
||||||
self.def.absfuzz[self.abs.unwrap() as usize] = value;
|
self.def.absfuzz[self.abs.unwrap() as usize] = value;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the flat value for the previously enabled absolute event.
|
/// Set the flat value for the previously enabled absolute event.
|
||||||
pub fn flat(mut self, value: i32) -> Self {
|
pub fn flat(mut self, value: i32) -> Self {
|
||||||
self.def.absflat[self.abs.unwrap() as usize] = value;
|
self.def.absflat[self.abs.unwrap() as usize] = value;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create the defined device.
|
/// Create the defined device.
|
||||||
pub fn create(self) -> Result<Device> {
|
pub fn create(self) -> Result<Device> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let ptr = &self.def as *const _ as *const u8;
|
let ptr = &self.def as *const _ as *const u8;
|
||||||
let size = mem::size_of_val(&self.def);
|
let size = mem::size_of_val(&self.def);
|
||||||
|
|
||||||
unistd::write(self.fd, slice::from_raw_parts(ptr, size))?;
|
unistd::write(self.fd, slice::from_raw_parts(ptr, size))?;
|
||||||
ui_dev_create(self.fd)?;
|
ui_dev_create(self.fd)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Device::new(self.fd))
|
Ok(Device::new(self.fd))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,7 +1,7 @@
|
|||||||
use std::{mem, ptr, slice};
|
|
||||||
use libc::{timeval, gettimeofday, input_event, c_int};
|
|
||||||
use nix::{unistd, ioctl_none};
|
|
||||||
use crate::Result;
|
use crate::Result;
|
||||||
|
use libc::{c_int, gettimeofday, input_event, timeval};
|
||||||
|
use nix::{ioctl_none, unistd};
|
||||||
|
use std::{mem, ptr, slice};
|
||||||
|
|
||||||
use crate::linux::device::codes::*;
|
use crate::linux::device::codes::*;
|
||||||
|
|
||||||
@ -9,80 +9,81 @@ ioctl_none!(ui_dev_destroy, b'U', 2);
|
|||||||
|
|
||||||
/// The virtual device.
|
/// The virtual device.
|
||||||
pub struct Device {
|
pub struct Device {
|
||||||
fd: c_int,
|
fd: c_int,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Device {
|
impl Device {
|
||||||
/// Wrap a file descriptor in a `Device`.
|
/// Wrap a file descriptor in a `Device`.
|
||||||
pub fn new(fd: c_int) -> Self {
|
pub fn new(fd: c_int) -> Self {
|
||||||
Device {
|
Device { fd: fd }
|
||||||
fd: fd
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub fn write(&self, kind: c_int, code: c_int, value: c_int) -> Result<()> {
|
pub fn write(&self, kind: c_int, code: c_int, value: c_int) -> Result<()> {
|
||||||
let mut event = input_event {
|
let mut event = input_event {
|
||||||
time: timeval { tv_sec: 0, tv_usec: 0 },
|
time: timeval {
|
||||||
type_: kind as u16,
|
tv_sec: 0,
|
||||||
code: code as u16,
|
tv_usec: 0,
|
||||||
value: value as i32,
|
},
|
||||||
};
|
type_: kind as u16,
|
||||||
|
code: code as u16,
|
||||||
|
value: value as i32,
|
||||||
|
};
|
||||||
|
|
||||||
self.write_event(&mut event)
|
self.write_event(&mut event)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub fn write_event(&self, event: &mut input_event) -> Result<()> {
|
pub fn write_event(&self, event: &mut input_event) -> Result<()> {
|
||||||
unsafe {
|
unsafe {
|
||||||
gettimeofday(&mut event.time, ptr::null_mut());
|
gettimeofday(&mut event.time, ptr::null_mut());
|
||||||
|
|
||||||
let ptr = event as *const _ as *const u8;
|
let ptr = event as *const _ as *const u8;
|
||||||
let size = mem::size_of_val(event);
|
let size = mem::size_of_val(event);
|
||||||
|
|
||||||
unistd::write(self.fd, slice::from_raw_parts(ptr, size))?;
|
unistd::write(self.fd, slice::from_raw_parts(ptr, size))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Synchronize the device.
|
/// Synchronize the device.
|
||||||
pub fn synchronize(&self) -> Result<()> {
|
pub fn synchronize(&self) -> Result<()> {
|
||||||
self.write(EV_SYN, SYN_REPORT, 0)
|
self.write(EV_SYN, SYN_REPORT, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send an event.
|
/// Send an event.
|
||||||
pub fn send(&self, kind: c_int, code: c_int, value: i32) -> Result<()> {
|
pub fn send(&self, kind: c_int, code: c_int, value: i32) -> Result<()> {
|
||||||
self.write(kind, code, value)
|
self.write(kind, code, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send a press event.
|
/// Send a press event.
|
||||||
pub fn press(&self, kind: c_int, code: c_int) -> Result<()> {
|
pub fn press(&self, kind: c_int, code: c_int) -> Result<()> {
|
||||||
self.write(kind, code, 1)
|
self.write(kind, code, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send a release event.
|
/// Send a release event.
|
||||||
pub fn release(&self, kind: c_int, code: c_int) -> Result<()> {
|
pub fn release(&self, kind: c_int, code: c_int) -> Result<()> {
|
||||||
self.write(kind, code, 0)
|
self.write(kind, code, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send a press and release event.
|
/// Send a press and release event.
|
||||||
pub fn click(&self, kind: c_int, code: c_int) -> Result<()> {
|
pub fn click(&self, kind: c_int, code: c_int) -> Result<()> {
|
||||||
self.press(kind, code)?;
|
self.press(kind, code)?;
|
||||||
self.release(kind, code)
|
self.release(kind, code)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send a relative or absolute positioning event.
|
/// Send a relative or absolute positioning event.
|
||||||
pub fn position(&self, kind: c_int, code: c_int, value: i32) -> Result<()> {
|
pub fn position(&self, kind: c_int, code: c_int, value: i32) -> Result<()> {
|
||||||
self.write(kind, code, value)
|
self.write(kind, code, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for Device {
|
impl Drop for Device {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
// ignore error here so as to not panic in a drop
|
// ignore error here so as to not panic in a drop
|
||||||
ui_dev_destroy(self.fd).ok();
|
ui_dev_destroy(self.fd).ok();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,14 @@
|
|||||||
use std::mem;
|
use libc::{c_int, input_event};
|
||||||
use std::fs::File;
|
use nix::{ioctl_read_buf, ioctl_write_ptr};
|
||||||
use std::io::Read;
|
use std::{fs::File, io::Read, mem, os::unix::io::AsRawFd};
|
||||||
use std::os::unix::io::AsRawFd;
|
|
||||||
use libc::{input_event, c_int};
|
|
||||||
use nix::{ioctl_write_ptr, ioctl_read_buf};
|
|
||||||
|
|
||||||
#[cfg(feature = "epoll_inotify")]
|
#[cfg(feature = "epoll_inotify")]
|
||||||
use std::os::unix::prelude::RawFd;
|
use std::os::unix::prelude::RawFd;
|
||||||
|
|
||||||
use crate::{Error,Result};
|
use crate::{
|
||||||
use crate::linux::{EV_KEY, KEY_MAX, NAME, KEY_W, KEY_A, KEY_S, KEY_D, BTN_LEFT};
|
linux::{BTN_LEFT, EV_KEY, KEY_A, KEY_D, KEY_MAX, KEY_S, KEY_W, NAME},
|
||||||
|
Error, Result,
|
||||||
|
};
|
||||||
|
|
||||||
ioctl_write_ptr!(eviocgrab, b'E', 0x90, c_int);
|
ioctl_write_ptr!(eviocgrab, b'E', 0x90, c_int);
|
||||||
ioctl_read_buf!(eviocgname, b'E', 0x06, u8);
|
ioctl_read_buf!(eviocgname, b'E', 0x06, u8);
|
||||||
@ -73,16 +72,19 @@ impl InputDevice {
|
|||||||
unsafe {
|
unsafe {
|
||||||
eviocgbit_ev_key(raw_fd, &mut key_bits)?;
|
eviocgbit_ev_key(raw_fd, &mut key_bits)?;
|
||||||
};
|
};
|
||||||
let key_unsupported = |key : c_int| (key_bits[key as usize / 8] & (1 << (key % 8))) == 0;
|
let key_unsupported = |key: c_int| (key_bits[key as usize / 8] & (1 << (key % 8))) == 0;
|
||||||
if key_unsupported(KEY_W) || key_unsupported(KEY_A) || key_unsupported(KEY_S) || key_unsupported(KEY_D) || !key_unsupported(BTN_LEFT) {
|
if key_unsupported(KEY_W)
|
||||||
|
|| key_unsupported(KEY_A)
|
||||||
|
|| key_unsupported(KEY_S)
|
||||||
|
|| key_unsupported(KEY_D)
|
||||||
|
|| !key_unsupported(BTN_LEFT)
|
||||||
|
{
|
||||||
return Err(Error::NotAKeyboard);
|
return Err(Error::NotAKeyboard);
|
||||||
}
|
}
|
||||||
|
|
||||||
// is it another running copy of rusty-keys ?
|
// is it another running copy of rusty-keys ?
|
||||||
let mut name = [0u8; NAME.len()];
|
let mut name = [0u8; NAME.len()];
|
||||||
unsafe {
|
unsafe { eviocgname(raw_fd, &mut name)? };
|
||||||
eviocgname(raw_fd, &mut name)?
|
|
||||||
};
|
|
||||||
// exclude anything starting with "Yubico" also
|
// exclude anything starting with "Yubico" also
|
||||||
if NAME.as_bytes() == &name || "Yubico".as_bytes() == &name[0..6] {
|
if NAME.as_bytes() == &name || "Yubico".as_bytes() == &name[0..6] {
|
||||||
return Err(Error::NotAKeyboard);
|
return Err(Error::NotAKeyboard);
|
||||||
@ -110,7 +112,7 @@ impl InputDevice {
|
|||||||
|
|
||||||
#[cfg(feature = "epoll_inotify")]
|
#[cfg(feature = "epoll_inotify")]
|
||||||
pub fn epoll_add(mut self, epoll_fd: RawFd, data: u64) -> Result<Self> {
|
pub fn epoll_add(mut self, epoll_fd: RawFd, data: u64) -> Result<Self> {
|
||||||
use nix::fcntl::{OFlag, fcntl, FcntlArg};
|
use nix::fcntl::{fcntl, FcntlArg, OFlag};
|
||||||
|
|
||||||
if None != self.epoll_fd {
|
if None != self.epoll_fd {
|
||||||
return Err(Error::EpollAlreadyAdded);
|
return Err(Error::EpollAlreadyAdded);
|
||||||
@ -123,7 +125,12 @@ impl InputDevice {
|
|||||||
fcntl(raw_fd, FcntlArg::F_SETFL(flags | OFlag::O_NONBLOCK))?;
|
fcntl(raw_fd, FcntlArg::F_SETFL(flags | OFlag::O_NONBLOCK))?;
|
||||||
|
|
||||||
let epoll_event = epoll::Event::new(epoll::Events::EPOLLIN | epoll::Events::EPOLLET, data);
|
let epoll_event = epoll::Event::new(epoll::Events::EPOLLIN | epoll::Events::EPOLLET, data);
|
||||||
epoll::ctl(epoll_fd, epoll::ControlOptions::EPOLL_CTL_ADD, raw_fd, epoll_event)?;
|
epoll::ctl(
|
||||||
|
epoll_fd,
|
||||||
|
epoll::ControlOptions::EPOLL_CTL_ADD,
|
||||||
|
raw_fd,
|
||||||
|
epoll_event,
|
||||||
|
)?;
|
||||||
self.epoll_fd = Some(epoll_fd);
|
self.epoll_fd = Some(epoll_fd);
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
@ -134,7 +141,12 @@ impl InputDevice {
|
|||||||
// set this to None first, if we end up returning an Err early, we can't do anything else anyway...
|
// set this to None first, if we end up returning an Err early, we can't do anything else anyway...
|
||||||
self.epoll_fd = None;
|
self.epoll_fd = None;
|
||||||
let empty_event = epoll::Event::new(epoll::Events::empty(), 0);
|
let empty_event = epoll::Event::new(epoll::Events::empty(), 0);
|
||||||
epoll::ctl(epoll_fd, epoll::ControlOptions::EPOLL_CTL_DEL, self.device_file.as_raw_fd(), empty_event)?;
|
epoll::ctl(
|
||||||
|
epoll_fd,
|
||||||
|
epoll::ControlOptions::EPOLL_CTL_DEL,
|
||||||
|
self.device_file.as_raw_fd(),
|
||||||
|
empty_event,
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
837
src/linux/mod.rs
837
src/linux/mod.rs
@ -1,15 +1,12 @@
|
|||||||
|
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
use crate::linux::device::codes::*;
|
use crate::linux::device::codes::*;
|
||||||
|
|
||||||
pub mod device;
|
pub mod device;
|
||||||
pub use device::{Device,InputDevice, Builder};
|
pub use device::{Builder, Device, InputDevice};
|
||||||
|
|
||||||
use libc::input_event;
|
use libc::input_event;
|
||||||
use std::process::exit;
|
use std::{collections::HashMap, env, process::exit};
|
||||||
use std::env;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
#[cfg(feature = "epoll_inotify")]
|
#[cfg(feature = "epoll_inotify")]
|
||||||
const INPUT_FOLDER: &str = "/dev/input/";
|
const INPUT_FOLDER: &str = "/dev/input/";
|
||||||
@ -48,7 +45,12 @@ impl Keyboard<u16, input_event> for Device {
|
|||||||
Keyboard::send(self, event)
|
Keyboard::send(self, event)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_mod_code_value(&self, code: u16, up_not_down: bool, event: &mut input_event) -> Result<()> {
|
fn send_mod_code_value(
|
||||||
|
&self,
|
||||||
|
code: u16,
|
||||||
|
up_not_down: bool,
|
||||||
|
event: &mut input_event,
|
||||||
|
) -> Result<()> {
|
||||||
event.code = code;
|
event.code = code;
|
||||||
let value = event.value;
|
let value = event.value;
|
||||||
if up_not_down {
|
if up_not_down {
|
||||||
@ -86,12 +88,15 @@ impl Keyboard<u16, input_event> for Device {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct Config {
|
struct Config {
|
||||||
device_files: Vec<String>,
|
device_files: Vec<String>,
|
||||||
config_file: String
|
config_file: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
fn new(device_files: Vec<String>, config_file: String) -> Self {
|
fn new(device_files: Vec<String>, config_file: String) -> Self {
|
||||||
Config { device_files: device_files, config_file: config_file }
|
Config {
|
||||||
|
device_files: device_files,
|
||||||
|
config_file: config_file,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,91 +135,120 @@ pub fn main_res() -> Result<()> {
|
|||||||
panic!("without epoll_inotify feature, only exactly 1 device is supported");
|
panic!("without epoll_inotify feature, only exactly 1 device is supported");
|
||||||
|
|
||||||
#[cfg(feature = "epoll_inotify")]
|
#[cfg(feature = "epoll_inotify")]
|
||||||
{
|
{
|
||||||
use inotify::{Inotify, WatchMask};
|
use inotify::{Inotify, WatchMask};
|
||||||
|
|
||||||
let epoll_fd = epoll::create(true)?;
|
let epoll_fd = epoll::create(true)?;
|
||||||
const INOTIFY_DATA: u64 = u64::max_value();
|
const INOTIFY_DATA: u64 = u64::max_value();
|
||||||
|
|
||||||
let (device_files, mut inotify) = if config.device_files.len() > 0 {
|
let (device_files, mut inotify) = if config.device_files.len() > 0 {
|
||||||
// we operate on exactly the devices sent in and never watch for new devices
|
// we operate on exactly the devices sent in and never watch for new devices
|
||||||
(config.device_files.iter().map(|device_file| InputDevice::open(&device_file).expect("device_file does not exist!")).collect(), None)
|
(
|
||||||
} else {
|
config
|
||||||
use std::os::unix::io::AsRawFd;
|
.device_files
|
||||||
// we want to wait forever starting new threads for any new keyboard devices
|
.iter()
|
||||||
// there is a slight race condition here, if a keyboard is plugged in between the time we
|
.map(|device_file| {
|
||||||
// enumerate the devices and set up the inotify watch, we'll miss it, doing it the other way
|
InputDevice::open(&device_file).expect("device_file does not exist!")
|
||||||
// can bring duplicates though, todo: think about this...
|
})
|
||||||
let device_files = get_keyboard_devices();
|
.collect(),
|
||||||
let mut inotify = Inotify::init()?;
|
None,
|
||||||
inotify.add_watch(INPUT_FOLDER, WatchMask::CREATE)?;
|
)
|
||||||
let epoll_event = epoll::Event::new(epoll::Events::EPOLLIN | epoll::Events::EPOLLET, INOTIFY_DATA);
|
} else {
|
||||||
epoll::ctl(epoll_fd, epoll::ControlOptions::EPOLL_CTL_ADD, inotify.as_raw_fd(), epoll_event)?;
|
use std::os::unix::io::AsRawFd;
|
||||||
(device_files, Some(inotify))
|
// we want to wait forever starting new threads for any new keyboard devices
|
||||||
};
|
// there is a slight race condition here, if a keyboard is plugged in between the time we
|
||||||
let mut input_devices = Vec::with_capacity(device_files.len());
|
// enumerate the devices and set up the inotify watch, we'll miss it, doing it the other way
|
||||||
for (idx, device_file) in device_files.into_iter().enumerate() {
|
// can bring duplicates though, todo: think about this...
|
||||||
input_devices.push(Some(device_file.grab()?.epoll_add(epoll_fd, idx as u64)?));
|
let device_files = get_keyboard_devices();
|
||||||
}
|
let mut inotify = Inotify::init()?;
|
||||||
|
inotify.add_watch(INPUT_FOLDER, WatchMask::CREATE)?;
|
||||||
|
let epoll_event = epoll::Event::new(
|
||||||
|
epoll::Events::EPOLLIN | epoll::Events::EPOLLET,
|
||||||
|
INOTIFY_DATA,
|
||||||
|
);
|
||||||
|
epoll::ctl(
|
||||||
|
epoll_fd,
|
||||||
|
epoll::ControlOptions::EPOLL_CTL_ADD,
|
||||||
|
inotify.as_raw_fd(),
|
||||||
|
epoll_event,
|
||||||
|
)?;
|
||||||
|
(device_files, Some(inotify))
|
||||||
|
};
|
||||||
|
let mut input_devices = Vec::with_capacity(device_files.len());
|
||||||
|
for (idx, device_file) in device_files.into_iter().enumerate() {
|
||||||
|
input_devices.push(Some(device_file.grab()?.epoll_add(epoll_fd, idx as u64)?));
|
||||||
|
}
|
||||||
|
|
||||||
let mut epoll_buf = [epoll::Event::new(epoll::Events::empty(), 0); 4];
|
let mut epoll_buf = [epoll::Event::new(epoll::Events::empty(), 0); 4];
|
||||||
let mut inotify_buf = [0u8; 256];
|
let mut inotify_buf = [0u8; 256];
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let num_events = epoll::wait(epoll_fd, -1, &mut epoll_buf)?;
|
let num_events = epoll::wait(epoll_fd, -1, &mut epoll_buf)?;
|
||||||
for event in &epoll_buf[0..num_events] {
|
for event in &epoll_buf[0..num_events] {
|
||||||
let idx = event.data as usize;
|
let idx = event.data as usize;
|
||||||
if let Some(Some(input_device)) = &mut input_devices.get_mut(idx) {
|
if let Some(Some(input_device)) = &mut input_devices.get_mut(idx) {
|
||||||
loop {
|
loop {
|
||||||
match input_device.read_event(&mut input_event_buf) {
|
match input_device.read_event(&mut input_event_buf) {
|
||||||
Ok(event) => {
|
Ok(event) => {
|
||||||
//println!("input event: {:?}", event);
|
//println!("input event: {:?}", event);
|
||||||
send_event(&mut key_map, event, &device)?
|
send_event(&mut key_map, event, &device)?
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
if let Error::Io(ref err) = err {
|
if let Error::Io(ref err) = err {
|
||||||
if err.kind() == std::io::ErrorKind::WouldBlock {
|
if err.kind() == std::io::ErrorKind::WouldBlock {
|
||||||
// go back to epoll event loop
|
// go back to epoll event loop
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// otherwise it's some other error, don't read anything from this again
|
|
||||||
println!("input err: {:?}", err);
|
|
||||||
// remove it from input_devices and drop it
|
|
||||||
let _ = std::mem::replace(&mut input_devices[idx], None);
|
|
||||||
if inotify.is_none() {
|
|
||||||
// if we aren't watching with inotify, and the last device is removed (Vec only has None's in it), exit the program
|
|
||||||
if input_devices.iter().all(|id| id.is_none()) {
|
|
||||||
println!("last device went away, exiting...");
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
// otherwise it's some other error, don't read anything from this again
|
||||||
|
println!("input err: {:?}", err);
|
||||||
|
// remove it from input_devices and drop it
|
||||||
|
let _ = std::mem::replace(&mut input_devices[idx], None);
|
||||||
|
if inotify.is_none() {
|
||||||
|
// if we aren't watching with inotify, and the last device is removed (Vec only has None's in it), exit the program
|
||||||
|
if input_devices.iter().all(|id| id.is_none()) {
|
||||||
|
println!("last device went away, exiting...");
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if event.data == INOTIFY_DATA {
|
}
|
||||||
if let Some(inotify) = &mut inotify {
|
} else if event.data == INOTIFY_DATA {
|
||||||
for event in inotify.read_events(&mut inotify_buf)? {
|
if let Some(inotify) = &mut inotify {
|
||||||
if let Some(device_file) = event.name.and_then(|name| name.to_str()) {
|
for event in inotify.read_events(&mut inotify_buf)? {
|
||||||
// check if this is an eligible keyboard device
|
if let Some(device_file) = event.name.and_then(|name| name.to_str())
|
||||||
let mut path = std::path::PathBuf::new();
|
{
|
||||||
path.push(INPUT_FOLDER);
|
// check if this is an eligible keyboard device
|
||||||
path.push(device_file);
|
let mut path = std::path::PathBuf::new();
|
||||||
|
path.push(INPUT_FOLDER);
|
||||||
|
path.push(device_file);
|
||||||
|
|
||||||
if let Ok(input_device) = InputDevice::open(path).and_then(|id| id.valid_keyboard_device()) {
|
if let Ok(input_device) = InputDevice::open(path)
|
||||||
println!("starting mapping for new keyboard: {}", device_file);
|
.and_then(|id| id.valid_keyboard_device())
|
||||||
|
{
|
||||||
|
println!(
|
||||||
|
"starting mapping for new keyboard: {}",
|
||||||
|
device_file
|
||||||
|
);
|
||||||
|
|
||||||
let idx = input_devices.iter().position(|id| id.is_none()).unwrap_or(input_devices.len());
|
let idx = input_devices
|
||||||
|
.iter()
|
||||||
|
.position(|id| id.is_none())
|
||||||
|
.unwrap_or(input_devices.len());
|
||||||
|
|
||||||
let input_device = input_device.grab()?.epoll_add(epoll_fd, idx as u64)?;
|
let input_device =
|
||||||
|
input_device.grab()?.epoll_add(epoll_fd, idx as u64)?;
|
||||||
|
|
||||||
if idx == input_devices.len() {
|
if idx == input_devices.len() {
|
||||||
input_devices.push(Some(input_device));
|
input_devices.push(Some(input_device));
|
||||||
} else {
|
} else {
|
||||||
// simply replacing None here
|
// simply replacing None here
|
||||||
let _ = std::mem::replace(&mut input_devices[idx], Some(input_device));
|
let _ = std::mem::replace(
|
||||||
}
|
&mut input_devices[idx],
|
||||||
|
Some(input_device),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -223,6 +257,7 @@ pub fn main_res() -> Result<()> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,7 +282,12 @@ fn parse_args() -> Config {
|
|||||||
let mut opts = Options::new();
|
let mut opts = Options::new();
|
||||||
opts.optflag("h", "help", "prints this help message");
|
opts.optflag("h", "help", "prints this help message");
|
||||||
opts.optflag("v", "version", "prints the version");
|
opts.optflag("v", "version", "prints the version");
|
||||||
opts.optopt("c", "config", "specify the keymap config file to use (default: /etc/rusty-keys/keymap.toml)", "FILE");
|
opts.optopt(
|
||||||
|
"c",
|
||||||
|
"config",
|
||||||
|
"specify the keymap config file to use (default: /etc/rusty-keys/keymap.toml)",
|
||||||
|
"FILE",
|
||||||
|
);
|
||||||
|
|
||||||
let matches = opts.parse(&args[1..]);
|
let matches = opts.parse(&args[1..]);
|
||||||
if matches.is_err() {
|
if matches.is_err() {
|
||||||
@ -265,7 +305,9 @@ fn parse_args() -> Config {
|
|||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
let config_file = matches.opt_str("c").unwrap_or("/etc/rusty-keys/keymap.toml".to_owned());
|
let config_file = matches
|
||||||
|
.opt_str("c")
|
||||||
|
.unwrap_or("/etc/rusty-keys/keymap.toml".to_owned());
|
||||||
|
|
||||||
Config::new(matches.free, config_file)
|
Config::new(matches.free, config_file)
|
||||||
}
|
}
|
||||||
@ -276,7 +318,9 @@ fn get_keyboard_devices() -> Vec<InputDevice> {
|
|||||||
if let Ok(entries) = std::fs::read_dir(INPUT_FOLDER) {
|
if let Ok(entries) = std::fs::read_dir(INPUT_FOLDER) {
|
||||||
for entry in entries {
|
for entry in entries {
|
||||||
if let Ok(entry) = entry {
|
if let Ok(entry) = entry {
|
||||||
if let Ok(input_device) = InputDevice::open(entry.path()).and_then(|id|id.valid_keyboard_device()) {
|
if let Ok(input_device) =
|
||||||
|
InputDevice::open(entry.path()).and_then(|id| id.valid_keyboard_device())
|
||||||
|
{
|
||||||
res.push(input_device);
|
res.push(input_device);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -286,314 +330,317 @@ fn get_keyboard_devices() -> Vec<InputDevice> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn key_map() -> HashMap<&'static str, u16> {
|
pub fn key_map() -> HashMap<&'static str, u16> {
|
||||||
[
|
[
|
||||||
// generated like:
|
// generated like:
|
||||||
// grep -o 'KEY_[^ :;]*' ~/.cargo/registry/src/github.com-1ecc6299db9ec823/uinput-sys-0.1.3/src/codes | sed 's/^KEY_//' | awk '{print "(\""$1"\", KEY_"$1"),"}'
|
// grep -o 'KEY_[^ :;]*' ~/.cargo/registry/src/github.com-1ecc6299db9ec823/uinput-sys-0.1.3/src/codes | sed 's/^KEY_//' | awk '{print "(\""$1"\", KEY_"$1"),"}'
|
||||||
("RESERVED", KEY_RESERVED),
|
("RESERVED", KEY_RESERVED),
|
||||||
("ESC", KEY_ESC),
|
("ESC", KEY_ESC),
|
||||||
("1", KEY_1),
|
("1", KEY_1),
|
||||||
("2", KEY_2),
|
("2", KEY_2),
|
||||||
("3", KEY_3),
|
("3", KEY_3),
|
||||||
("4", KEY_4),
|
("4", KEY_4),
|
||||||
("5", KEY_5),
|
("5", KEY_5),
|
||||||
("6", KEY_6),
|
("6", KEY_6),
|
||||||
("7", KEY_7),
|
("7", KEY_7),
|
||||||
("8", KEY_8),
|
("8", KEY_8),
|
||||||
("9", KEY_9),
|
("9", KEY_9),
|
||||||
("10", KEY_10),
|
("10", KEY_10),
|
||||||
("MINUS", KEY_MINUS),
|
("MINUS", KEY_MINUS),
|
||||||
("EQUAL", KEY_EQUAL),
|
("EQUAL", KEY_EQUAL),
|
||||||
("BACKSPACE", KEY_BACKSPACE),
|
("BACKSPACE", KEY_BACKSPACE),
|
||||||
("TAB", KEY_TAB),
|
("TAB", KEY_TAB),
|
||||||
("Q", KEY_Q),
|
("Q", KEY_Q),
|
||||||
("W", KEY_W),
|
("W", KEY_W),
|
||||||
("E", KEY_E),
|
("E", KEY_E),
|
||||||
("R", KEY_R),
|
("R", KEY_R),
|
||||||
("T", KEY_T),
|
("T", KEY_T),
|
||||||
("Y", KEY_Y),
|
("Y", KEY_Y),
|
||||||
("U", KEY_U),
|
("U", KEY_U),
|
||||||
("I", KEY_I),
|
("I", KEY_I),
|
||||||
("O", KEY_O),
|
("O", KEY_O),
|
||||||
("P", KEY_P),
|
("P", KEY_P),
|
||||||
("LEFTBRACE", KEY_LEFTBRACE),
|
("LEFTBRACE", KEY_LEFTBRACE),
|
||||||
("RIGHTBRACE", KEY_RIGHTBRACE),
|
("RIGHTBRACE", KEY_RIGHTBRACE),
|
||||||
("ENTER", KEY_ENTER),
|
("ENTER", KEY_ENTER),
|
||||||
("LEFTCTRL", KEY_LEFTCTRL),
|
("LEFTCTRL", KEY_LEFTCTRL),
|
||||||
("A", KEY_A),
|
("A", KEY_A),
|
||||||
("S", KEY_S),
|
("S", KEY_S),
|
||||||
("D", KEY_D),
|
("D", KEY_D),
|
||||||
("F", KEY_F),
|
("F", KEY_F),
|
||||||
("G", KEY_G),
|
("G", KEY_G),
|
||||||
("H", KEY_H),
|
("H", KEY_H),
|
||||||
("J", KEY_J),
|
("J", KEY_J),
|
||||||
("K", KEY_K),
|
("K", KEY_K),
|
||||||
("L", KEY_L),
|
("L", KEY_L),
|
||||||
("SEMICOLON", KEY_SEMICOLON),
|
("SEMICOLON", KEY_SEMICOLON),
|
||||||
("APOSTROPHE", KEY_APOSTROPHE),
|
("APOSTROPHE", KEY_APOSTROPHE),
|
||||||
("GRAVE", KEY_GRAVE),
|
("GRAVE", KEY_GRAVE),
|
||||||
("LEFTSHIFT", KEY_LEFTSHIFT),
|
("LEFTSHIFT", KEY_LEFTSHIFT),
|
||||||
("BACKSLASH", KEY_BACKSLASH),
|
("BACKSLASH", KEY_BACKSLASH),
|
||||||
("Z", KEY_Z),
|
("Z", KEY_Z),
|
||||||
("X", KEY_X),
|
("X", KEY_X),
|
||||||
("C", KEY_C),
|
("C", KEY_C),
|
||||||
("V", KEY_V),
|
("V", KEY_V),
|
||||||
("B", KEY_B),
|
("B", KEY_B),
|
||||||
("N", KEY_N),
|
("N", KEY_N),
|
||||||
("M", KEY_M),
|
("M", KEY_M),
|
||||||
("COMMA", KEY_COMMA),
|
("COMMA", KEY_COMMA),
|
||||||
("DOT", KEY_DOT),
|
("DOT", KEY_DOT),
|
||||||
("SLASH", KEY_SLASH),
|
("SLASH", KEY_SLASH),
|
||||||
("RIGHTSHIFT", KEY_RIGHTSHIFT),
|
("RIGHTSHIFT", KEY_RIGHTSHIFT),
|
||||||
("KPASTERISK", KEY_KPASTERISK),
|
("KPASTERISK", KEY_KPASTERISK),
|
||||||
("LEFTALT", KEY_LEFTALT),
|
("LEFTALT", KEY_LEFTALT),
|
||||||
("SPACE", KEY_SPACE),
|
("SPACE", KEY_SPACE),
|
||||||
("CAPSLOCK", KEY_CAPSLOCK),
|
("CAPSLOCK", KEY_CAPSLOCK),
|
||||||
("F1", KEY_F1),
|
("F1", KEY_F1),
|
||||||
("F2", KEY_F2),
|
("F2", KEY_F2),
|
||||||
("F3", KEY_F3),
|
("F3", KEY_F3),
|
||||||
("F4", KEY_F4),
|
("F4", KEY_F4),
|
||||||
("F5", KEY_F5),
|
("F5", KEY_F5),
|
||||||
("F6", KEY_F6),
|
("F6", KEY_F6),
|
||||||
("F7", KEY_F7),
|
("F7", KEY_F7),
|
||||||
("F8", KEY_F8),
|
("F8", KEY_F8),
|
||||||
("F9", KEY_F9),
|
("F9", KEY_F9),
|
||||||
("F10", KEY_F10),
|
("F10", KEY_F10),
|
||||||
("NUMLOCK", KEY_NUMLOCK),
|
("NUMLOCK", KEY_NUMLOCK),
|
||||||
("SCROLLLOCK", KEY_SCROLLLOCK),
|
("SCROLLLOCK", KEY_SCROLLLOCK),
|
||||||
("KP7", KEY_KP7),
|
("KP7", KEY_KP7),
|
||||||
("KP8", KEY_KP8),
|
("KP8", KEY_KP8),
|
||||||
("KP9", KEY_KP9),
|
("KP9", KEY_KP9),
|
||||||
("KPMINUS", KEY_KPMINUS),
|
("KPMINUS", KEY_KPMINUS),
|
||||||
("KP4", KEY_KP4),
|
("KP4", KEY_KP4),
|
||||||
("KP5", KEY_KP5),
|
("KP5", KEY_KP5),
|
||||||
("KP6", KEY_KP6),
|
("KP6", KEY_KP6),
|
||||||
("KPPLUS", KEY_KPPLUS),
|
("KPPLUS", KEY_KPPLUS),
|
||||||
("KP1", KEY_KP1),
|
("KP1", KEY_KP1),
|
||||||
("KP2", KEY_KP2),
|
("KP2", KEY_KP2),
|
||||||
("KP3", KEY_KP3),
|
("KP3", KEY_KP3),
|
||||||
("KP0", KEY_KP0),
|
("KP0", KEY_KP0),
|
||||||
("KPDOT", KEY_KPDOT),
|
("KPDOT", KEY_KPDOT),
|
||||||
("ZENKAKUHANKAKU", KEY_ZENKAKUHANKAKU),
|
("ZENKAKUHANKAKU", KEY_ZENKAKUHANKAKU),
|
||||||
("102ND", KEY_102ND),
|
("102ND", KEY_102ND),
|
||||||
("F11", KEY_F11),
|
("F11", KEY_F11),
|
||||||
("F12", KEY_F12),
|
("F12", KEY_F12),
|
||||||
("RO", KEY_RO),
|
("RO", KEY_RO),
|
||||||
("KATAKANA", KEY_KATAKANA),
|
("KATAKANA", KEY_KATAKANA),
|
||||||
("HIRAGANA", KEY_HIRAGANA),
|
("HIRAGANA", KEY_HIRAGANA),
|
||||||
("HENKAN", KEY_HENKAN),
|
("HENKAN", KEY_HENKAN),
|
||||||
("KATAKANAHIRAGANA", KEY_KATAKANAHIRAGANA),
|
("KATAKANAHIRAGANA", KEY_KATAKANAHIRAGANA),
|
||||||
("MUHENKAN", KEY_MUHENKAN),
|
("MUHENKAN", KEY_MUHENKAN),
|
||||||
("KPJPCOMMA", KEY_KPJPCOMMA),
|
("KPJPCOMMA", KEY_KPJPCOMMA),
|
||||||
("KPENTER", KEY_KPENTER),
|
("KPENTER", KEY_KPENTER),
|
||||||
("RIGHTCTRL", KEY_RIGHTCTRL),
|
("RIGHTCTRL", KEY_RIGHTCTRL),
|
||||||
("KPSLASH", KEY_KPSLASH),
|
("KPSLASH", KEY_KPSLASH),
|
||||||
("SYSRQ", KEY_SYSRQ),
|
("SYSRQ", KEY_SYSRQ),
|
||||||
("RIGHTALT", KEY_RIGHTALT),
|
("RIGHTALT", KEY_RIGHTALT),
|
||||||
("LINEFEED", KEY_LINEFEED),
|
("LINEFEED", KEY_LINEFEED),
|
||||||
("HOME", KEY_HOME),
|
("HOME", KEY_HOME),
|
||||||
("UP", KEY_UP),
|
("UP", KEY_UP),
|
||||||
("PAGEUP", KEY_PAGEUP),
|
("PAGEUP", KEY_PAGEUP),
|
||||||
("LEFT", KEY_LEFT),
|
("LEFT", KEY_LEFT),
|
||||||
("RIGHT", KEY_RIGHT),
|
("RIGHT", KEY_RIGHT),
|
||||||
("END", KEY_END),
|
("END", KEY_END),
|
||||||
("DOWN", KEY_DOWN),
|
("DOWN", KEY_DOWN),
|
||||||
("PAGEDOWN", KEY_PAGEDOWN),
|
("PAGEDOWN", KEY_PAGEDOWN),
|
||||||
("INSERT", KEY_INSERT),
|
("INSERT", KEY_INSERT),
|
||||||
("DELETE", KEY_DELETE),
|
("DELETE", KEY_DELETE),
|
||||||
("MACRO", KEY_MACRO),
|
("MACRO", KEY_MACRO),
|
||||||
("MUTE", KEY_MUTE),
|
("MUTE", KEY_MUTE),
|
||||||
("VOLUMEDOWN", KEY_VOLUMEDOWN),
|
("VOLUMEDOWN", KEY_VOLUMEDOWN),
|
||||||
("VOLUMEUP", KEY_VOLUMEUP),
|
("VOLUMEUP", KEY_VOLUMEUP),
|
||||||
("POWER", KEY_POWER),
|
("POWER", KEY_POWER),
|
||||||
("KPEQUAL", KEY_KPEQUAL),
|
("KPEQUAL", KEY_KPEQUAL),
|
||||||
("KPPLUSMINUS", KEY_KPPLUSMINUS),
|
("KPPLUSMINUS", KEY_KPPLUSMINUS),
|
||||||
("PAUSE", KEY_PAUSE),
|
("PAUSE", KEY_PAUSE),
|
||||||
("SCALE", KEY_SCALE),
|
("SCALE", KEY_SCALE),
|
||||||
("KPCOMMA", KEY_KPCOMMA),
|
("KPCOMMA", KEY_KPCOMMA),
|
||||||
("HANGEUL", KEY_HANGEUL),
|
("HANGEUL", KEY_HANGEUL),
|
||||||
("HANGUEL", KEY_HANGUEL),
|
("HANGUEL", KEY_HANGUEL),
|
||||||
("HANGEUL", KEY_HANGEUL),
|
("HANGEUL", KEY_HANGEUL),
|
||||||
("HANJA", KEY_HANJA),
|
("HANJA", KEY_HANJA),
|
||||||
("YEN", KEY_YEN),
|
("YEN", KEY_YEN),
|
||||||
("LEFTMETA", KEY_LEFTMETA),
|
("LEFTMETA", KEY_LEFTMETA),
|
||||||
("RIGHTMETA", KEY_RIGHTMETA),
|
("RIGHTMETA", KEY_RIGHTMETA),
|
||||||
("COMPOSE", KEY_COMPOSE),
|
("COMPOSE", KEY_COMPOSE),
|
||||||
("STOP", KEY_STOP),
|
("STOP", KEY_STOP),
|
||||||
("AGAIN", KEY_AGAIN),
|
("AGAIN", KEY_AGAIN),
|
||||||
("PROPS", KEY_PROPS),
|
("PROPS", KEY_PROPS),
|
||||||
("UNDO", KEY_UNDO),
|
("UNDO", KEY_UNDO),
|
||||||
("FRONT", KEY_FRONT),
|
("FRONT", KEY_FRONT),
|
||||||
("COPY", KEY_COPY),
|
("COPY", KEY_COPY),
|
||||||
("OPEN", KEY_OPEN),
|
("OPEN", KEY_OPEN),
|
||||||
("PASTE", KEY_PASTE),
|
("PASTE", KEY_PASTE),
|
||||||
("FIND", KEY_FIND),
|
("FIND", KEY_FIND),
|
||||||
("CUT", KEY_CUT),
|
("CUT", KEY_CUT),
|
||||||
("HELP", KEY_HELP),
|
("HELP", KEY_HELP),
|
||||||
("MENU", KEY_MENU),
|
("MENU", KEY_MENU),
|
||||||
("CALC", KEY_CALC),
|
("CALC", KEY_CALC),
|
||||||
("SETUP", KEY_SETUP),
|
("SETUP", KEY_SETUP),
|
||||||
("SLEEP", KEY_SLEEP),
|
("SLEEP", KEY_SLEEP),
|
||||||
("WAKEUP", KEY_WAKEUP),
|
("WAKEUP", KEY_WAKEUP),
|
||||||
("FILE", KEY_FILE),
|
("FILE", KEY_FILE),
|
||||||
("SENDFILE", KEY_SENDFILE),
|
("SENDFILE", KEY_SENDFILE),
|
||||||
("DELETEFILE", KEY_DELETEFILE),
|
("DELETEFILE", KEY_DELETEFILE),
|
||||||
("XFER", KEY_XFER),
|
("XFER", KEY_XFER),
|
||||||
("PROG1", KEY_PROG1),
|
("PROG1", KEY_PROG1),
|
||||||
("PROG2", KEY_PROG2),
|
("PROG2", KEY_PROG2),
|
||||||
("WWW", KEY_WWW),
|
("WWW", KEY_WWW),
|
||||||
("MSDOS", KEY_MSDOS),
|
("MSDOS", KEY_MSDOS),
|
||||||
("COFFEE", KEY_COFFEE),
|
("COFFEE", KEY_COFFEE),
|
||||||
("SCREENLOCK", KEY_SCREENLOCK),
|
("SCREENLOCK", KEY_SCREENLOCK),
|
||||||
("COFFEE", KEY_COFFEE),
|
("COFFEE", KEY_COFFEE),
|
||||||
("ROTATE_DISPLAY", KEY_ROTATE_DISPLAY),
|
("ROTATE_DISPLAY", KEY_ROTATE_DISPLAY),
|
||||||
("DIRECTION", KEY_DIRECTION),
|
("DIRECTION", KEY_DIRECTION),
|
||||||
("ROTATE_DISPLAY", KEY_ROTATE_DISPLAY),
|
("ROTATE_DISPLAY", KEY_ROTATE_DISPLAY),
|
||||||
("CYCLEWINDOWS", KEY_CYCLEWINDOWS),
|
("CYCLEWINDOWS", KEY_CYCLEWINDOWS),
|
||||||
("MAIL", KEY_MAIL),
|
("MAIL", KEY_MAIL),
|
||||||
("BOOKMARKS", KEY_BOOKMARKS),
|
("BOOKMARKS", KEY_BOOKMARKS),
|
||||||
("COMPUTER", KEY_COMPUTER),
|
("COMPUTER", KEY_COMPUTER),
|
||||||
("BACK", KEY_BACK),
|
("BACK", KEY_BACK),
|
||||||
("FORWARD", KEY_FORWARD),
|
("FORWARD", KEY_FORWARD),
|
||||||
("CLOSECD", KEY_CLOSECD),
|
("CLOSECD", KEY_CLOSECD),
|
||||||
("EJECTCD", KEY_EJECTCD),
|
("EJECTCD", KEY_EJECTCD),
|
||||||
("EJECTCLOSECD", KEY_EJECTCLOSECD),
|
("EJECTCLOSECD", KEY_EJECTCLOSECD),
|
||||||
("NEXTSONG", KEY_NEXTSONG),
|
("NEXTSONG", KEY_NEXTSONG),
|
||||||
("PLAYPAUSE", KEY_PLAYPAUSE),
|
("PLAYPAUSE", KEY_PLAYPAUSE),
|
||||||
("PREVIOUSSONG", KEY_PREVIOUSSONG),
|
("PREVIOUSSONG", KEY_PREVIOUSSONG),
|
||||||
("STOPCD", KEY_STOPCD),
|
("STOPCD", KEY_STOPCD),
|
||||||
("RECORD", KEY_RECORD),
|
("RECORD", KEY_RECORD),
|
||||||
("REWIND", KEY_REWIND),
|
("REWIND", KEY_REWIND),
|
||||||
("PHONE", KEY_PHONE),
|
("PHONE", KEY_PHONE),
|
||||||
("ISO", KEY_ISO),
|
("ISO", KEY_ISO),
|
||||||
("CONFIG", KEY_CONFIG),
|
("CONFIG", KEY_CONFIG),
|
||||||
("HOMEPAGE", KEY_HOMEPAGE),
|
("HOMEPAGE", KEY_HOMEPAGE),
|
||||||
("REFRESH", KEY_REFRESH),
|
("REFRESH", KEY_REFRESH),
|
||||||
("EXIT", KEY_EXIT),
|
("EXIT", KEY_EXIT),
|
||||||
("MOVE", KEY_MOVE),
|
("MOVE", KEY_MOVE),
|
||||||
("EDIT", KEY_EDIT),
|
("EDIT", KEY_EDIT),
|
||||||
("SCROLLUP", KEY_SCROLLUP),
|
("SCROLLUP", KEY_SCROLLUP),
|
||||||
("SCROLLDOWN", KEY_SCROLLDOWN),
|
("SCROLLDOWN", KEY_SCROLLDOWN),
|
||||||
("KPLEFTPAREN", KEY_KPLEFTPAREN),
|
("KPLEFTPAREN", KEY_KPLEFTPAREN),
|
||||||
("KPRIGHTPAREN", KEY_KPRIGHTPAREN),
|
("KPRIGHTPAREN", KEY_KPRIGHTPAREN),
|
||||||
("NEW", KEY_NEW),
|
("NEW", KEY_NEW),
|
||||||
("REDO", KEY_REDO),
|
("REDO", KEY_REDO),
|
||||||
("F13", KEY_F13),
|
("F13", KEY_F13),
|
||||||
("F14", KEY_F14),
|
("F14", KEY_F14),
|
||||||
("F15", KEY_F15),
|
("F15", KEY_F15),
|
||||||
("F16", KEY_F16),
|
("F16", KEY_F16),
|
||||||
("F17", KEY_F17),
|
("F17", KEY_F17),
|
||||||
("F18", KEY_F18),
|
("F18", KEY_F18),
|
||||||
("F19", KEY_F19),
|
("F19", KEY_F19),
|
||||||
("F20", KEY_F20),
|
("F20", KEY_F20),
|
||||||
("F21", KEY_F21),
|
("F21", KEY_F21),
|
||||||
("F22", KEY_F22),
|
("F22", KEY_F22),
|
||||||
("F23", KEY_F23),
|
("F23", KEY_F23),
|
||||||
("F24", KEY_F24),
|
("F24", KEY_F24),
|
||||||
("PLAYCD", KEY_PLAYCD),
|
("PLAYCD", KEY_PLAYCD),
|
||||||
("PAUSECD", KEY_PAUSECD),
|
("PAUSECD", KEY_PAUSECD),
|
||||||
("PROG3", KEY_PROG3),
|
("PROG3", KEY_PROG3),
|
||||||
("PROG4", KEY_PROG4),
|
("PROG4", KEY_PROG4),
|
||||||
("DASHBOARD", KEY_DASHBOARD),
|
("DASHBOARD", KEY_DASHBOARD),
|
||||||
("SUSPEND", KEY_SUSPEND),
|
("SUSPEND", KEY_SUSPEND),
|
||||||
("CLOSE", KEY_CLOSE),
|
("CLOSE", KEY_CLOSE),
|
||||||
("PLAY", KEY_PLAY),
|
("PLAY", KEY_PLAY),
|
||||||
("FASTFORWARD", KEY_FASTFORWARD),
|
("FASTFORWARD", KEY_FASTFORWARD),
|
||||||
("BASSBOOST", KEY_BASSBOOST),
|
("BASSBOOST", KEY_BASSBOOST),
|
||||||
("PRINT", KEY_PRINT),
|
("PRINT", KEY_PRINT),
|
||||||
("HP", KEY_HP),
|
("HP", KEY_HP),
|
||||||
("CAMERA", KEY_CAMERA),
|
("CAMERA", KEY_CAMERA),
|
||||||
("SOUND", KEY_SOUND),
|
("SOUND", KEY_SOUND),
|
||||||
("QUESTION", KEY_QUESTION),
|
("QUESTION", KEY_QUESTION),
|
||||||
("EMAIL", KEY_EMAIL),
|
("EMAIL", KEY_EMAIL),
|
||||||
("CHAT", KEY_CHAT),
|
("CHAT", KEY_CHAT),
|
||||||
("SEARCH", KEY_SEARCH),
|
("SEARCH", KEY_SEARCH),
|
||||||
("CONNECT", KEY_CONNECT),
|
("CONNECT", KEY_CONNECT),
|
||||||
("FINANCE", KEY_FINANCE),
|
("FINANCE", KEY_FINANCE),
|
||||||
("SPORT", KEY_SPORT),
|
("SPORT", KEY_SPORT),
|
||||||
("SHOP", KEY_SHOP),
|
("SHOP", KEY_SHOP),
|
||||||
("ALTERASE", KEY_ALTERASE),
|
("ALTERASE", KEY_ALTERASE),
|
||||||
("CANCEL", KEY_CANCEL),
|
("CANCEL", KEY_CANCEL),
|
||||||
("BRIGHTNESSDOWN", KEY_BRIGHTNESSDOWN),
|
("BRIGHTNESSDOWN", KEY_BRIGHTNESSDOWN),
|
||||||
("BRIGHTNESSUP", KEY_BRIGHTNESSUP),
|
("BRIGHTNESSUP", KEY_BRIGHTNESSUP),
|
||||||
("MEDIA", KEY_MEDIA),
|
("MEDIA", KEY_MEDIA),
|
||||||
("SWITCHVIDEOMODE", KEY_SWITCHVIDEOMODE),
|
("SWITCHVIDEOMODE", KEY_SWITCHVIDEOMODE),
|
||||||
("KBDILLUMTOGGLE", KEY_KBDILLUMTOGGLE),
|
("KBDILLUMTOGGLE", KEY_KBDILLUMTOGGLE),
|
||||||
("KBDILLUMDOWN", KEY_KBDILLUMDOWN),
|
("KBDILLUMDOWN", KEY_KBDILLUMDOWN),
|
||||||
("KBDILLUMUP", KEY_KBDILLUMUP),
|
("KBDILLUMUP", KEY_KBDILLUMUP),
|
||||||
("SEND", KEY_SEND),
|
("SEND", KEY_SEND),
|
||||||
("REPLY", KEY_REPLY),
|
("REPLY", KEY_REPLY),
|
||||||
("FORWARDMAIL", KEY_FORWARDMAIL),
|
("FORWARDMAIL", KEY_FORWARDMAIL),
|
||||||
("SAVE", KEY_SAVE),
|
("SAVE", KEY_SAVE),
|
||||||
("DOCUMENTS", KEY_DOCUMENTS),
|
("DOCUMENTS", KEY_DOCUMENTS),
|
||||||
("BATTERY", KEY_BATTERY),
|
("BATTERY", KEY_BATTERY),
|
||||||
("BLUETOOTH", KEY_BLUETOOTH),
|
("BLUETOOTH", KEY_BLUETOOTH),
|
||||||
("WLAN", KEY_WLAN),
|
("WLAN", KEY_WLAN),
|
||||||
("UWB", KEY_UWB),
|
("UWB", KEY_UWB),
|
||||||
("UNKNOWN", KEY_UNKNOWN),
|
("UNKNOWN", KEY_UNKNOWN),
|
||||||
("VIDEO_NEXT", KEY_VIDEO_NEXT),
|
("VIDEO_NEXT", KEY_VIDEO_NEXT),
|
||||||
("VIDEO_PREV", KEY_VIDEO_PREV),
|
("VIDEO_PREV", KEY_VIDEO_PREV),
|
||||||
("BRIGHTNESS_CYCLE", KEY_BRIGHTNESS_CYCLE),
|
("BRIGHTNESS_CYCLE", KEY_BRIGHTNESS_CYCLE),
|
||||||
("BRIGHTNESS_AUTO", KEY_BRIGHTNESS_AUTO),
|
("BRIGHTNESS_AUTO", KEY_BRIGHTNESS_AUTO),
|
||||||
("BRIGHTNESS_ZERO", KEY_BRIGHTNESS_ZERO),
|
("BRIGHTNESS_ZERO", KEY_BRIGHTNESS_ZERO),
|
||||||
("BRIGHTNESS_AUTO", KEY_BRIGHTNESS_AUTO),
|
("BRIGHTNESS_AUTO", KEY_BRIGHTNESS_AUTO),
|
||||||
("DISPLAY_OFF", KEY_DISPLAY_OFF),
|
("DISPLAY_OFF", KEY_DISPLAY_OFF),
|
||||||
("WWAN", KEY_WWAN),
|
("WWAN", KEY_WWAN),
|
||||||
("WIMAX", KEY_WIMAX),
|
("WIMAX", KEY_WIMAX),
|
||||||
("WWAN", KEY_WWAN),
|
("WWAN", KEY_WWAN),
|
||||||
("RFKILL", KEY_RFKILL),
|
("RFKILL", KEY_RFKILL),
|
||||||
("MICMUTE", KEY_MICMUTE),
|
("MICMUTE", KEY_MICMUTE),
|
||||||
// below manual shortcuts
|
// below manual shortcuts
|
||||||
("PSCR", KEY_SYSRQ),
|
("PSCR", KEY_SYSRQ),
|
||||||
("SLCK", KEY_SCROLLLOCK),
|
("SLCK", KEY_SCROLLLOCK),
|
||||||
("BRK", KEY_PAUSE),
|
("BRK", KEY_PAUSE),
|
||||||
("GRV", KEY_GRAVE),
|
("GRV", KEY_GRAVE),
|
||||||
("0", KEY_10), // dumb or named wrong?
|
("0", KEY_10), // dumb or named wrong?
|
||||||
("MINS", KEY_MINUS),
|
("MINS", KEY_MINUS),
|
||||||
("EQL", KEY_EQUAL),
|
("EQL", KEY_EQUAL),
|
||||||
("BSPC", KEY_BACKSPACE),
|
("BSPC", KEY_BACKSPACE),
|
||||||
("LBRC", KEY_LEFTBRACE),
|
("LBRC", KEY_LEFTBRACE),
|
||||||
("RBRC", KEY_RIGHTBRACE),
|
("RBRC", KEY_RIGHTBRACE),
|
||||||
("BSLS", KEY_BACKSLASH),
|
("BSLS", KEY_BACKSLASH),
|
||||||
("SCLN", KEY_SEMICOLON),
|
("SCLN", KEY_SEMICOLON),
|
||||||
("QUOT", KEY_APOSTROPHE),
|
("QUOT", KEY_APOSTROPHE),
|
||||||
("ENT", KEY_ENTER),
|
("ENT", KEY_ENTER),
|
||||||
("COMM", KEY_COMMA),
|
("COMM", KEY_COMMA),
|
||||||
("DOT", KEY_DOT),
|
("DOT", KEY_DOT),
|
||||||
("SLSH", KEY_SLASH),
|
("SLSH", KEY_SLASH),
|
||||||
("CAPS", KEY_CAPSLOCK),
|
("CAPS", KEY_CAPSLOCK),
|
||||||
("LSFT", KEY_LEFTSHIFT),
|
("LSFT", KEY_LEFTSHIFT),
|
||||||
("RSFT", KEY_RIGHTSHIFT),
|
("RSFT", KEY_RIGHTSHIFT),
|
||||||
("SPC", KEY_SPACE),
|
("SPC", KEY_SPACE),
|
||||||
("APP", KEY_COMPOSE),
|
("APP", KEY_COMPOSE),
|
||||||
("LCTL", KEY_LEFTCTRL),
|
("LCTL", KEY_LEFTCTRL),
|
||||||
("RCTL", KEY_RIGHTCTRL),
|
("RCTL", KEY_RIGHTCTRL),
|
||||||
("LALT", KEY_LEFTALT),
|
("LALT", KEY_LEFTALT),
|
||||||
("RALT", KEY_RIGHTALT),
|
("RALT", KEY_RIGHTALT),
|
||||||
("LGUI", KEY_LEFTMETA),
|
("LGUI", KEY_LEFTMETA),
|
||||||
("RGUI", KEY_RIGHTMETA),
|
("RGUI", KEY_RIGHTMETA),
|
||||||
("INS", KEY_INSERT),
|
("INS", KEY_INSERT),
|
||||||
("PGUP", KEY_PAGEUP),
|
("PGUP", KEY_PAGEUP),
|
||||||
("PGDN", KEY_PAGEDOWN),
|
("PGDN", KEY_PAGEDOWN),
|
||||||
("DEL", KEY_DELETE),
|
("DEL", KEY_DELETE),
|
||||||
("RGHT", KEY_RIGHT),
|
("RGHT", KEY_RIGHT),
|
||||||
("NLCK", KEY_NUMLOCK),
|
("NLCK", KEY_NUMLOCK),
|
||||||
("PSLS", KEY_KPSLASH),
|
("PSLS", KEY_KPSLASH),
|
||||||
("PAST", KEY_KPASTERISK),
|
("PAST", KEY_KPASTERISK),
|
||||||
("PMNS", KEY_KPMINUS),
|
("PMNS", KEY_KPMINUS),
|
||||||
("P7", KEY_KP7),
|
("P7", KEY_KP7),
|
||||||
("P8", KEY_KP8),
|
("P8", KEY_KP8),
|
||||||
("P9", KEY_KP9),
|
("P9", KEY_KP9),
|
||||||
("P4", KEY_KP4),
|
("P4", KEY_KP4),
|
||||||
("P5", KEY_KP5),
|
("P5", KEY_KP5),
|
||||||
("P6", KEY_KP6),
|
("P6", KEY_KP6),
|
||||||
("PPLS", KEY_KPPLUS),
|
("PPLS", KEY_KPPLUS),
|
||||||
("P1", KEY_KP1),
|
("P1", KEY_KP1),
|
||||||
("P2", KEY_KP2),
|
("P2", KEY_KP2),
|
||||||
("P3", KEY_KP3),
|
("P3", KEY_KP3),
|
||||||
("P0", KEY_KP0),
|
("P0", KEY_KP0),
|
||||||
("PDOT", KEY_KPDOT),
|
("PDOT", KEY_KPDOT),
|
||||||
("PENT", KEY_KPENTER),
|
("PENT", KEY_KPENTER),
|
||||||
("TOUCHPAD_TOGGLE", KEY_TOUCHPAD_TOGGLE),
|
("TOUCHPAD_TOGGLE", KEY_TOUCHPAD_TOGGLE),
|
||||||
].iter().cloned().map(|(m, v)| (m, v as u16)).collect()
|
]
|
||||||
}
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.map(|(m, v)| (m, v as u16))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use core_graphics::event::CGKeyCode;
|
use core_graphics::event::CGKeyCode;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
pub const KEY_RESERVED: CGKeyCode = 0x31;
|
pub const KEY_RESERVED: CGKeyCode = 0x31;
|
||||||
pub const KEY_ESC: CGKeyCode = 0x00;
|
pub const KEY_ESC: CGKeyCode = 0x00;
|
||||||
@ -564,5 +563,9 @@ pub fn key_map() -> HashMap<&'static str, CGKeyCode> {
|
|||||||
("P0", KEY_KP0),
|
("P0", KEY_KP0),
|
||||||
("PDOT", KEY_KPDOT),
|
("PDOT", KEY_KPDOT),
|
||||||
("PENT", KEY_KPENTER),
|
("PENT", KEY_KPENTER),
|
||||||
].iter().cloned().map(|(m, v)| (m, v)).collect()
|
]
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.map(|(m, v)| (m, v))
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
|
254
src/macos/mod.rs
254
src/macos/mod.rs
@ -4,8 +4,7 @@
|
|||||||
#![allow(improper_ctypes)]
|
#![allow(improper_ctypes)]
|
||||||
|
|
||||||
use crate::*;
|
use crate::*;
|
||||||
use std::env;
|
use std::{env, process::exit};
|
||||||
use std::process::exit;
|
|
||||||
|
|
||||||
use getopts::Options;
|
use getopts::Options;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
@ -13,9 +12,10 @@ use std::fs::File;
|
|||||||
pub mod codes;
|
pub mod codes;
|
||||||
use codes::*;
|
use codes::*;
|
||||||
|
|
||||||
use core_graphics::event::CGKeyCode;
|
use core_graphics::{
|
||||||
use core_graphics::event::*;
|
event::{CGKeyCode, *},
|
||||||
use core_graphics::event_source::*;
|
event_source::*,
|
||||||
|
};
|
||||||
|
|
||||||
use core_graphics::event::{CGEventTapLocation, CGEventType};
|
use core_graphics::event::{CGEventTapLocation, CGEventType};
|
||||||
|
|
||||||
@ -62,8 +62,12 @@ impl KeyEvent<CGKeyCode> for CGEvent {
|
|||||||
KEY_CAPSLOCK => NX_DEVICECAPSLOCKMASK,
|
KEY_CAPSLOCK => NX_DEVICECAPSLOCKMASK,
|
||||||
_ => panic!("unhandled key: {}", self.code()),
|
_ => panic!("unhandled key: {}", self.code()),
|
||||||
};
|
};
|
||||||
if (flags & mask) != 0 { KeyState::DOWN } else { KeyState::UP }
|
if (flags & mask) != 0 {
|
||||||
},
|
KeyState::DOWN
|
||||||
|
} else {
|
||||||
|
KeyState::UP
|
||||||
|
}
|
||||||
|
}
|
||||||
CGEventType::KeyDown => KeyState::DOWN,
|
CGEventType::KeyDown => KeyState::DOWN,
|
||||||
CGEventType::KeyUp => KeyState::UP,
|
CGEventType::KeyUp => KeyState::UP,
|
||||||
CGEventType::TapDisabledByTimeout => {
|
CGEventType::TapDisabledByTimeout => {
|
||||||
@ -71,11 +75,11 @@ impl KeyEvent<CGKeyCode> for CGEvent {
|
|||||||
todo!("implement register listener");
|
todo!("implement register listener");
|
||||||
//register_listener(channel);
|
//register_listener(channel);
|
||||||
//KeyState::OTHER
|
//KeyState::OTHER
|
||||||
},
|
}
|
||||||
_ => {
|
_ => {
|
||||||
println!("Received unknown EventType: {:?}", event_type);
|
println!("Received unknown EventType: {:?}", event_type);
|
||||||
KeyState::OTHER
|
KeyState::OTHER
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -99,15 +103,21 @@ impl Keyboard<CGKeyCode, CGEvent, Option<CGEvent>> for CGEventSource {
|
|||||||
self.send_mod_code_value(code, event.value() == KeyState::UP, event)
|
self.send_mod_code_value(code, event.value() == KeyState::UP, event)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_mod_code_value(&self, code: CGKeyCode, up_not_down: bool, _event: &mut CGEvent) -> Result<Option<CGEvent>> {
|
fn send_mod_code_value(
|
||||||
|
&self,
|
||||||
|
code: CGKeyCode,
|
||||||
|
up_not_down: bool,
|
||||||
|
_event: &mut CGEvent,
|
||||||
|
) -> Result<Option<CGEvent>> {
|
||||||
//println!("send_mod_code_value orig: {} code: {}, up_not_down: {}", event.code(), code, up_not_down);
|
//println!("send_mod_code_value orig: {} code: {}, up_not_down: {}", event.code(), code, up_not_down);
|
||||||
//return Ok(None);
|
//return Ok(None);
|
||||||
|
|
||||||
let event =
|
let event = CGEvent::new_keyboard_event(self.clone(), code, !up_not_down)
|
||||||
CGEvent::new_keyboard_event(self.clone(), code, !up_not_down)
|
.expect("Failed creating event");
|
||||||
.expect("Failed creating event");
|
|
||||||
match tapLocation {
|
match tapLocation {
|
||||||
CGEventTapLocation::HID => event.set_integer_value_field(EventField::EVENT_SOURCE_USER_DATA, uniqueHIDUserData),
|
CGEventTapLocation::HID => {
|
||||||
|
event.set_integer_value_field(EventField::EVENT_SOURCE_USER_DATA, uniqueHIDUserData)
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
};
|
};
|
||||||
event.post(tapLocation);
|
event.post(tapLocation);
|
||||||
@ -146,12 +156,14 @@ pub fn main_res() -> Result<()> {
|
|||||||
|
|
||||||
let key_maps = MacOSKeyMaps::from_cfg(&key_map, &config.config_file);
|
let key_maps = MacOSKeyMaps::from_cfg(&key_map, &config.config_file);
|
||||||
//println!("key_maps: {}", key_maps);
|
//println!("key_maps: {}", key_maps);
|
||||||
let callback_pointer: CallbackPointer = (key_maps, CGEventSource::new(CGEventSourceStateID::Private).expect("Failed creating event source"));
|
let callback_pointer: CallbackPointer = (
|
||||||
|
key_maps,
|
||||||
|
CGEventSource::new(CGEventSourceStateID::Private).expect("Failed creating event source"),
|
||||||
|
);
|
||||||
|
|
||||||
let mask = CGEventMaskBit(CGEventType::KeyDown)
|
let mask = CGEventMaskBit(CGEventType::KeyDown)
|
||||||
| CGEventMaskBit(CGEventType::KeyUp)
|
| CGEventMaskBit(CGEventType::KeyUp)
|
||||||
| CGEventMaskBit(CGEventType::FlagsChanged)
|
| CGEventMaskBit(CGEventType::FlagsChanged);
|
||||||
;
|
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let options = 0;
|
let options = 0;
|
||||||
@ -191,12 +203,14 @@ pub fn main_res() -> Result<()> {
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct Config {
|
struct Config {
|
||||||
config_file: String
|
config_file: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
fn new(config_file: String) -> Self {
|
fn new(config_file: String) -> Self {
|
||||||
Config { config_file: config_file }
|
Config {
|
||||||
|
config_file: config_file,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -224,7 +238,10 @@ fn parse_args() -> Config {
|
|||||||
|
|
||||||
default_configs.push("keymap.toml".to_string());
|
default_configs.push("keymap.toml".to_string());
|
||||||
|
|
||||||
let c_msg = format!("specify the keymap config file to use (default in order: {:?})", default_configs);
|
let c_msg = format!(
|
||||||
|
"specify the keymap config file to use (default in order: {:?})",
|
||||||
|
default_configs
|
||||||
|
);
|
||||||
|
|
||||||
let mut opts = Options::new();
|
let mut opts = Options::new();
|
||||||
opts.optflag("h", "help", "prints this help message");
|
opts.optflag("h", "help", "prints this help message");
|
||||||
@ -278,117 +295,119 @@ type CGEventTapOptions = u32;
|
|||||||
type CGEventTapPlacement = u32;
|
type CGEventTapPlacement = u32;
|
||||||
|
|
||||||
// Callback Type
|
// Callback Type
|
||||||
type CGEventTapCallBack = extern "C" fn(Pointer, CGEventType, CGEvent, &mut CallbackPointer) -> CGEvent;
|
type CGEventTapCallBack =
|
||||||
|
extern "C" fn(Pointer, CGEventType, CGEvent, &mut CallbackPointer) -> CGEvent;
|
||||||
|
|
||||||
// Constants
|
// Constants
|
||||||
const kCGSessionEventTap: CGEventTapLocation = CGEventTapLocation::HID;
|
const kCGSessionEventTap: CGEventTapLocation = CGEventTapLocation::HID;
|
||||||
const kCGHeadInsertEventTap: CGEventTapPlacement = 0;
|
const kCGHeadInsertEventTap: CGEventTapPlacement = 0;
|
||||||
|
|
||||||
// Link to ApplicationServices/ApplicationServices.h and Carbon/Carbon.h
|
// Link to ApplicationServices/ApplicationServices.h and Carbon/Carbon.h
|
||||||
#[link(name = "ApplicationServices", kind = "framework")]
|
#[link(name = "ApplicationServices", kind = "framework")]
|
||||||
#[link(name = "Carbon", kind = "framework")]
|
#[link(name = "Carbon", kind = "framework")]
|
||||||
extern {
|
extern "C" {
|
||||||
|
|
||||||
/// Pass through to the default loop modes
|
/// Pass through to the default loop modes
|
||||||
pub static kCFRunLoopCommonModes: Pointer;
|
pub static kCFRunLoopCommonModes: Pointer;
|
||||||
|
|
||||||
/// Pass through to the default allocator
|
/// Pass through to the default allocator
|
||||||
pub static kCFAllocatorDefault: Pointer;
|
pub static kCFAllocatorDefault: Pointer;
|
||||||
|
|
||||||
/// Run the current threads loop in default mode
|
/// Run the current threads loop in default mode
|
||||||
pub fn CFRunLoopRun();
|
pub fn CFRunLoopRun();
|
||||||
|
|
||||||
/// Obtain the current threads loop
|
/// Obtain the current threads loop
|
||||||
pub fn CFRunLoopGetCurrent() -> Pointer;
|
pub fn CFRunLoopGetCurrent() -> Pointer;
|
||||||
|
|
||||||
/// Create an event tap
|
/// Create an event tap
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
///
|
///
|
||||||
/// * `place` - The location of the new event tap. Pass one of
|
/// * `place` - The location of the new event tap. Pass one of
|
||||||
/// the constants listed in Event Tap Locations. Only
|
/// the constants listed in Event Tap Locations. Only
|
||||||
/// processes running as the root user may locate an
|
/// processes running as the root user may locate an
|
||||||
/// event tap at the point where HID events enter the
|
/// event tap at the point where HID events enter the
|
||||||
/// window server; for other users, this function
|
/// window server; for other users, this function
|
||||||
/// returns NULL.
|
/// returns NULL.
|
||||||
///
|
///
|
||||||
/// * `options` - The placement of the new event tap in the
|
/// * `options` - The placement of the new event tap in the
|
||||||
/// list of active event taps. Pass one of the
|
/// list of active event taps. Pass one of the
|
||||||
/// constants listed in Event Tap Placement.
|
/// constants listed in Event Tap Placement.
|
||||||
///
|
///
|
||||||
/// * `eventsOfInterest` - A constant that specifies whether
|
/// * `eventsOfInterest` - A constant that specifies whether
|
||||||
/// the new event tap is a passive listener or an
|
/// the new event tap is a passive listener or an
|
||||||
/// active filter.
|
/// active filter.
|
||||||
///
|
///
|
||||||
/// * `callback` - A bit mask that specifies the set of events
|
/// * `callback` - A bit mask that specifies the set of events
|
||||||
/// to be observed. For a list of possible events,
|
/// to be observed. For a list of possible events,
|
||||||
/// see Event Types. For information on how to
|
/// see Event Types. For information on how to
|
||||||
/// specify the mask, see CGEventMask. If the event
|
/// specify the mask, see CGEventMask. If the event
|
||||||
/// tap is not permitted to monitor one or more of
|
/// tap is not permitted to monitor one or more of
|
||||||
/// the events specified in the eventsOfInterest
|
/// the events specified in the eventsOfInterest
|
||||||
/// parameter, then the appropriate bits in the mask
|
/// parameter, then the appropriate bits in the mask
|
||||||
/// are cleared. If that action results in an empty
|
/// are cleared. If that action results in an empty
|
||||||
/// mask, this function returns NULL. callback
|
/// mask, this function returns NULL. callback
|
||||||
///
|
///
|
||||||
/// * `refcon` - An event tap callback function that you
|
/// * `refcon` - An event tap callback function that you
|
||||||
/// provide. Your callback function is invoked from
|
/// provide. Your callback function is invoked from
|
||||||
/// the run loop to which the event tap is added as a
|
/// the run loop to which the event tap is added as a
|
||||||
/// source. The thread safety of the callback is
|
/// source. The thread safety of the callback is
|
||||||
/// defined by the run loop’s environment. To learn
|
/// defined by the run loop’s environment. To learn
|
||||||
/// more about event tap callbacks, see
|
/// more about event tap callbacks, see
|
||||||
/// CGEventTapCallBack. refcon
|
/// CGEventTapCallBack. refcon
|
||||||
///
|
///
|
||||||
/// * `channel` - A pointer to user-defined data. This pointer
|
/// * `channel` - A pointer to user-defined data. This pointer
|
||||||
/// is passed into the callback function specified in
|
/// is passed into the callback function specified in
|
||||||
/// the callback parameter. Here we use it as a mpsc
|
/// the callback parameter. Here we use it as a mpsc
|
||||||
/// channel.
|
/// channel.
|
||||||
pub fn CGEventTapCreate(
|
pub fn CGEventTapCreate(
|
||||||
tap: CGEventTapLocation,
|
tap: CGEventTapLocation,
|
||||||
place: CGEventTapPlacement,
|
place: CGEventTapPlacement,
|
||||||
options: CGEventTapOptions,
|
options: CGEventTapOptions,
|
||||||
eventsOfInterest: CGEventMask,
|
eventsOfInterest: CGEventMask,
|
||||||
callback: CGEventTapCallBack,
|
callback: CGEventTapCallBack,
|
||||||
channel: &CallbackPointer,
|
channel: &CallbackPointer,
|
||||||
) -> CFMachPortRef;
|
) -> CFMachPortRef;
|
||||||
|
|
||||||
/// Creates a CFRunLoopSource object for a CFMachPort
|
/// Creates a CFRunLoopSource object for a CFMachPort
|
||||||
/// object.
|
/// object.
|
||||||
///
|
///
|
||||||
/// The run loop source is not automatically added to
|
/// The run loop source is not automatically added to
|
||||||
/// a run loop. To add the source to a run loop, use
|
/// a run loop. To add the source to a run loop, use
|
||||||
/// CFRunLoopAddSource
|
/// CFRunLoopAddSource
|
||||||
pub fn CFMachPortCreateRunLoopSource(
|
pub fn CFMachPortCreateRunLoopSource(
|
||||||
allocator: Pointer,
|
allocator: Pointer,
|
||||||
port: CFMachPortRef,
|
port: CFMachPortRef,
|
||||||
order: libc::c_int,
|
order: libc::c_int,
|
||||||
) -> Pointer;
|
) -> Pointer;
|
||||||
|
|
||||||
/// Adds a CFRunLoopSource object to a run loop mode.
|
/// Adds a CFRunLoopSource object to a run loop mode.
|
||||||
pub fn CFRunLoopAddSource(
|
pub fn CFRunLoopAddSource(run_loop: Pointer, run_loop_source: Pointer, mode: Pointer);
|
||||||
run_loop: Pointer,
|
|
||||||
run_loop_source: Pointer,
|
|
||||||
mode: Pointer,
|
|
||||||
);
|
|
||||||
|
|
||||||
pub fn CGEventTapEnable(port: CFMachPortRef, enable: bool);
|
pub fn CGEventTapEnable(port: CFMachPortRef, enable: bool);
|
||||||
}
|
}
|
||||||
|
|
||||||
const NX_DEVICELCTLKEYMASK: u64 = 0x00000001;
|
const NX_DEVICELCTLKEYMASK: u64 = 0x00000001;
|
||||||
const NX_DEVICERCTLKEYMASK: u64 = 0x00002000;
|
const NX_DEVICERCTLKEYMASK: u64 = 0x00002000;
|
||||||
const NX_DEVICELSHIFTKEYMASK: u64 = 0x00000002;
|
const NX_DEVICELSHIFTKEYMASK: u64 = 0x00000002;
|
||||||
const NX_DEVICERSHIFTKEYMASK: u64 = 0x00000004;
|
const NX_DEVICERSHIFTKEYMASK: u64 = 0x00000004;
|
||||||
const NX_DEVICELCMDKEYMASK: u64 = 0x00000008;
|
const NX_DEVICELCMDKEYMASK: u64 = 0x00000008;
|
||||||
const NX_DEVICERCMDKEYMASK: u64 = 0x00000010;
|
const NX_DEVICERCMDKEYMASK: u64 = 0x00000010;
|
||||||
const NX_DEVICELALTKEYMASK: u64 = 0x00000020;
|
const NX_DEVICELALTKEYMASK: u64 = 0x00000020;
|
||||||
const NX_DEVICERALTKEYMASK: u64 = 0x00000040;
|
const NX_DEVICERALTKEYMASK: u64 = 0x00000040;
|
||||||
|
|
||||||
const NX_DEVICECAPSLOCKMASK: u64 = 1 << 16;
|
const NX_DEVICECAPSLOCKMASK: u64 = 1 << 16;
|
||||||
|
|
||||||
/// This callback will be registered to be invoked from the run loop
|
/// This callback will be registered to be invoked from the run loop
|
||||||
/// to which the event tap is added as a source.
|
/// to which the event tap is added as a source.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
#[allow(unused_variables, improper_ctypes_definitions)]
|
#[allow(unused_variables, improper_ctypes_definitions)]
|
||||||
pub extern fn callback(proxy: Pointer, event_type: CGEventType, mut event: CGEvent, callback_pointer: &mut CallbackPointer) -> CGEvent {
|
pub extern "C" fn callback(
|
||||||
|
proxy: Pointer,
|
||||||
|
event_type: CGEventType,
|
||||||
|
mut event: CGEvent,
|
||||||
|
callback_pointer: &mut CallbackPointer,
|
||||||
|
) -> CGEvent {
|
||||||
let (key_maps, event_source) = callback_pointer;
|
let (key_maps, event_source) = callback_pointer;
|
||||||
match tapLocation {
|
match tapLocation {
|
||||||
CGEventTapLocation::HID => {
|
CGEventTapLocation::HID => {
|
||||||
@ -400,15 +419,16 @@ pub extern fn callback(proxy: Pointer, event_type: CGEventType, mut event: CGEve
|
|||||||
_ => {}
|
_ => {}
|
||||||
};
|
};
|
||||||
|
|
||||||
key_maps.send_event(&mut event, &event_source).expect("macos shouldn't error...")
|
key_maps
|
||||||
|
.send_event(&mut event, &event_source)
|
||||||
|
.expect("macos shouldn't error...")
|
||||||
.unwrap_or_else(|| {
|
.unwrap_or_else(|| {
|
||||||
event.set_type(CGEventType::Null);
|
event.set_type(CGEventType::Null);
|
||||||
event
|
event
|
||||||
}) // None means return NULL
|
}) // None means return NULL
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Redefine macro for bitshifting from header as function here
|
|
||||||
pub fn CGEventMaskBit(eventType: CGEventType) -> CGEventMask {
|
|
||||||
1 << (eventType as u32)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/// Redefine macro for bitshifting from header as function here
|
||||||
|
pub fn CGEventMaskBit(eventType: CGEventType) -> CGEventMask {
|
||||||
|
1 << (eventType as u32)
|
||||||
|
}
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||||
fn main() {
|
fn main() {
|
||||||
let ret = rusty_keys::main_res();
|
let ret = rusty_keys::main_res();
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
|
use std::{collections::HashMap, convert::TryFrom};
|
||||||
use winapi::shared::minwindef::DWORD;
|
use winapi::shared::minwindef::DWORD;
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::convert::TryFrom;
|
|
||||||
|
|
||||||
// https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
|
// https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
|
||||||
|
|
||||||
@ -557,7 +556,11 @@ pub fn key_map() -> HashMap<&'static str, USizeableDWORD> {
|
|||||||
("P0", KEY_KP0),
|
("P0", KEY_KP0),
|
||||||
("PDOT", KEY_KPDOT),
|
("PDOT", KEY_KPDOT),
|
||||||
("PENT", KEY_KPENTER),
|
("PENT", KEY_KPENTER),
|
||||||
].iter().cloned().map(|(m, v)| (m, USizeableDWORD(v))).collect()
|
]
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.map(|(m, v)| (m, USizeableDWORD(v)))
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://www.reddit.com/r/rust/comments/9xth8g/why_no_from_conversion_from_u32_to_usize/
|
// https://www.reddit.com/r/rust/comments/9xth8g/why_no_from_conversion_from_u32_to_usize/
|
||||||
|
@ -1,24 +1,32 @@
|
|||||||
#![windows_subsystem = "windows"]
|
#![windows_subsystem = "windows"]
|
||||||
|
|
||||||
use crate::*;
|
use crate::*;
|
||||||
use std::env;
|
use std::{env, process::exit};
|
||||||
use std::process::exit;
|
|
||||||
|
|
||||||
use getopts::Options;
|
use getopts::Options;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
|
|
||||||
use winapi::um::winuser::{KBDLLHOOKSTRUCT, WH_KEYBOARD_LL, MSG, GetMessageW, CallNextHookEx, SetWindowsHookExW, INPUT_KEYBOARD, MapVirtualKeyW, LPINPUT, INPUT, KEYBDINPUT, SendInput, KEYEVENTF_SCANCODE, KEYEVENTF_KEYUP, WM_KEYUP, WM_KEYDOWN, MAPVK_VK_TO_VSC, ShowWindow, SW_HIDE};
|
use winapi::{
|
||||||
use winapi::shared::windef::{HHOOK__, HWND};
|
ctypes::c_int,
|
||||||
use winapi::shared::minwindef::{LRESULT, WPARAM, LPARAM, HINSTANCE};
|
shared::{
|
||||||
use winapi::shared::basetsd::ULONG_PTR;
|
basetsd::ULONG_PTR,
|
||||||
use winapi::ctypes::c_int;
|
minwindef::{HINSTANCE, LPARAM, LRESULT, WPARAM},
|
||||||
|
windef::{HHOOK__, HWND},
|
||||||
|
},
|
||||||
|
um::winuser::{
|
||||||
|
CallNextHookEx, GetMessageW, MapVirtualKeyW, SendInput, SetWindowsHookExW, ShowWindow,
|
||||||
|
INPUT, INPUT_KEYBOARD, KBDLLHOOKSTRUCT, KEYBDINPUT, KEYEVENTF_KEYUP, KEYEVENTF_SCANCODE,
|
||||||
|
LPINPUT, MAPVK_VK_TO_VSC, MSG, SW_HIDE, WH_KEYBOARD_LL, WM_KEYDOWN, WM_KEYUP,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
pub mod codes;
|
pub mod codes;
|
||||||
use codes::*;
|
use codes::*;
|
||||||
use std::sync::atomic::{AtomicPtr, Ordering};
|
use std::{
|
||||||
use std::mem::{zeroed, size_of};
|
mem::{size_of, zeroed},
|
||||||
use winapi::_core::ptr::null_mut;
|
sync::atomic::{AtomicPtr, Ordering},
|
||||||
use winapi::_core::mem::transmute_copy;
|
};
|
||||||
|
use winapi::_core::{mem::transmute_copy, ptr::null_mut};
|
||||||
|
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
@ -65,7 +73,12 @@ impl Keyboard<USizeableDWORD, InputEvent, LRESULT> for Device {
|
|||||||
self.send_mod_code_value(code, event.value as u32 == WM_KEYUP, event)
|
self.send_mod_code_value(code, event.value as u32 == WM_KEYUP, event)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_mod_code_value(&self, code: USizeableDWORD, up_not_down: bool, _event: &mut InputEvent) -> Result<LRESULT> {
|
fn send_mod_code_value(
|
||||||
|
&self,
|
||||||
|
code: USizeableDWORD,
|
||||||
|
up_not_down: bool,
|
||||||
|
_event: &mut InputEvent,
|
||||||
|
) -> Result<LRESULT> {
|
||||||
let flags = if up_not_down {
|
let flags = if up_not_down {
|
||||||
KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP
|
KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP
|
||||||
} else {
|
} else {
|
||||||
@ -132,7 +145,7 @@ unsafe extern "system" fn keybd_proc(code: c_int, w_param: WPARAM, l_param: LPAR
|
|||||||
kb_struct.vkCode, kb_struct.scanCode, kb_struct.flags, kb_struct.time, kb_struct.dwExtraInfo);
|
kb_struct.vkCode, kb_struct.scanCode, kb_struct.flags, kb_struct.time, kb_struct.dwExtraInfo);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
let mut input_event = InputEvent{
|
let mut input_event = InputEvent {
|
||||||
code,
|
code,
|
||||||
value: w_param,
|
value: w_param,
|
||||||
kb_hook_pointer: l_param,
|
kb_hook_pointer: l_param,
|
||||||
@ -142,13 +155,17 @@ unsafe extern "system" fn keybd_proc(code: c_int, w_param: WPARAM, l_param: LPAR
|
|||||||
// .unwrap() is ok because windows impl can actually never can fail
|
// .unwrap() is ok because windows impl can actually never can fail
|
||||||
//DEVICE.send(&mut input_event).unwrap()
|
//DEVICE.send(&mut input_event).unwrap()
|
||||||
//KEY_MAPPER.send_event(&mut input_event, &DEVICE).unwrap()
|
//KEY_MAPPER.send_event(&mut input_event, &DEVICE).unwrap()
|
||||||
KEY_MAPPER.lock().unwrap().send_event(&mut input_event, &DEVICE).unwrap()
|
KEY_MAPPER
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.send_event(&mut input_event, &DEVICE)
|
||||||
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_hook(
|
fn set_hook(
|
||||||
hook_id: i32,
|
hook_id: i32,
|
||||||
hook_ptr: &AtomicPtr<HHOOK__>,
|
hook_ptr: &AtomicPtr<HHOOK__>,
|
||||||
hook_proc: unsafe extern "system" fn (c_int, WPARAM, LPARAM) -> LRESULT,
|
hook_proc: unsafe extern "system" fn(c_int, WPARAM, LPARAM) -> LRESULT,
|
||||||
) {
|
) {
|
||||||
hook_ptr.store(
|
hook_ptr.store(
|
||||||
unsafe { SetWindowsHookExW(hook_id, Some(hook_proc), 0 as HINSTANCE, 0) },
|
unsafe { SetWindowsHookExW(hook_id, Some(hook_proc), 0 as HINSTANCE, 0) },
|
||||||
@ -172,7 +189,6 @@ fn send_keybd_input(flags: u32, key_code: USizeableDWORD) {
|
|||||||
unsafe { SendInput(1, &mut input as LPINPUT, size_of::<INPUT>() as c_int) };
|
unsafe { SendInput(1, &mut input as LPINPUT, size_of::<INPUT>() as c_int) };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn main_res() -> Result<()> {
|
pub fn main_res() -> Result<()> {
|
||||||
// this is just to cause the lazy_static init to run first, so if -h or -v is wanted, we do that
|
// this is just to cause the lazy_static init to run first, so if -h or -v is wanted, we do that
|
||||||
// and exit immediately... todo: how to avoid mutex/lazy_static entirely???
|
// and exit immediately... todo: how to avoid mutex/lazy_static entirely???
|
||||||
@ -188,7 +204,7 @@ pub fn main_res() -> Result<()> {
|
|||||||
// hide window
|
// hide window
|
||||||
// todo: probably should be tray icon someplace in future to quit, and error messages as windows popups etc...
|
// todo: probably should be tray icon someplace in future to quit, and error messages as windows popups etc...
|
||||||
let hwnd = GetConsoleWindow();
|
let hwnd = GetConsoleWindow();
|
||||||
ShowWindow( hwnd, SW_HIDE );
|
ShowWindow(hwnd, SW_HIDE);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut msg: MSG = unsafe { zeroed() };
|
let mut msg: MSG = unsafe { zeroed() };
|
||||||
@ -201,12 +217,14 @@ pub fn main_res() -> Result<()> {
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct Config {
|
struct Config {
|
||||||
config_file: String
|
config_file: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
fn new(config_file: String) -> Self {
|
fn new(config_file: String) -> Self {
|
||||||
Config { config_file: config_file }
|
Config {
|
||||||
|
config_file: config_file,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -234,7 +252,10 @@ fn parse_args() -> Config {
|
|||||||
|
|
||||||
default_configs.push("keymap.toml".to_string());
|
default_configs.push("keymap.toml".to_string());
|
||||||
|
|
||||||
let c_msg = format!("specify the keymap config file to use (default in order: {:?})", default_configs);
|
let c_msg = format!(
|
||||||
|
"specify the keymap config file to use (default in order: {:?})",
|
||||||
|
default_configs
|
||||||
|
);
|
||||||
|
|
||||||
let mut opts = Options::new();
|
let mut opts = Options::new();
|
||||||
opts.optflag("h", "help", "prints this help message");
|
opts.optflag("h", "help", "prints this help message");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user