Support autorepeats and getting keymap entries (#46)
* Support getting and setting auto repeat settings Signed-off-by: Sean Young <sean@mess.org> * Retrieving and updating keymap entries Signed-off-by: Sean Young <sean@mess.org> * Add missing keycodes and missing aliases The aliases are #defines in input-event-codes.h. Signed-off-by: Sean Young <sean@mess.org>
This commit is contained in:
parent
d694443d53
commit
ed4245c380
6 changed files with 210 additions and 21 deletions
|
@ -198,6 +198,7 @@ macro_rules! evdev_enum {
|
|||
}
|
||||
impl std::fmt::Debug for $t {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
#[allow(unreachable_patterns)]
|
||||
match *self {
|
||||
$(Self::$c => f.pad(stringify!($c)),)*
|
||||
_ => write!(f, "unknown key: {}", self.0),
|
||||
|
|
|
@ -94,6 +94,7 @@ pub use attribute_set::{AttributeSet, AttributeSetRef};
|
|||
pub use constants::*;
|
||||
pub use device_state::DeviceState;
|
||||
pub use inputid::*;
|
||||
pub use raw_stream::AutoRepeat;
|
||||
pub use scancodes::*;
|
||||
pub use sync_stream::*;
|
||||
|
||||
|
|
|
@ -38,6 +38,8 @@ const ABSINFO_ZERO: libc::input_absinfo = libc::input_absinfo {
|
|||
pub(crate) const ABS_VALS_INIT: [libc::input_absinfo; AbsoluteAxisType::COUNT] =
|
||||
[ABSINFO_ZERO; AbsoluteAxisType::COUNT];
|
||||
|
||||
const INPUT_KEYMAP_BY_INDEX: u8 = 1;
|
||||
|
||||
/// A physical or virtual device supported by evdev.
|
||||
///
|
||||
/// Each device corresponds to a path typically found in `/dev/input`, and supports access via
|
||||
|
@ -59,13 +61,20 @@ pub struct RawDevice {
|
|||
supported_switch: Option<AttributeSet<SwitchType>>,
|
||||
supported_led: Option<AttributeSet<LedType>>,
|
||||
supported_misc: Option<AttributeSet<MiscType>>,
|
||||
auto_repeat: Option<AutoRepeat>,
|
||||
// ff: Option<AttributeSet<_>>,
|
||||
// ff_stat: Option<FFStatus>,
|
||||
// rep: Option<Repeat>,
|
||||
supported_snd: Option<AttributeSet<SoundType>>,
|
||||
pub(crate) event_buf: Vec<libc::input_event>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct AutoRepeat {
|
||||
pub delay: u32,
|
||||
pub period: u32,
|
||||
}
|
||||
|
||||
impl RawDevice {
|
||||
/// Opens a device, given its system path.
|
||||
///
|
||||
|
@ -198,6 +207,25 @@ impl RawDevice {
|
|||
None
|
||||
};
|
||||
|
||||
let auto_repeat = if ty.contains(EventType::REPEAT) {
|
||||
let mut auto_repeat: AutoRepeat = AutoRepeat {
|
||||
delay: 0,
|
||||
period: 0,
|
||||
};
|
||||
|
||||
unsafe {
|
||||
sys::eviocgrep(
|
||||
file.as_raw_fd(),
|
||||
&mut auto_repeat as *mut AutoRepeat as *mut [u32; 2],
|
||||
)
|
||||
.map_err(nix_err)?
|
||||
};
|
||||
|
||||
Some(auto_repeat)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Ok(RawDevice {
|
||||
file,
|
||||
ty,
|
||||
|
@ -214,6 +242,7 @@ impl RawDevice {
|
|||
supported_led,
|
||||
supported_misc,
|
||||
supported_snd,
|
||||
auto_repeat,
|
||||
event_buf: Vec::new(),
|
||||
})
|
||||
}
|
||||
|
@ -238,6 +267,11 @@ impl RawDevice {
|
|||
InputId::from(self.id)
|
||||
}
|
||||
|
||||
/// Returns the current auto repeat settings
|
||||
pub fn get_auto_repeat(&self) -> Option<AutoRepeat> {
|
||||
self.auto_repeat.clone()
|
||||
}
|
||||
|
||||
/// Returns the set of supported "properties" for the device (see `INPUT_PROP_*` in kernel headers)
|
||||
pub fn properties(&self) -> &AttributeSetRef<PropType> {
|
||||
&self.props
|
||||
|
@ -360,10 +394,6 @@ impl RawDevice {
|
|||
self.supported_misc.as_deref()
|
||||
}
|
||||
|
||||
// pub fn supported_repeats(&self) -> Option<Repeat> {
|
||||
// self.rep
|
||||
// }
|
||||
|
||||
/// Returns the set of supported simple sounds supported by a device.
|
||||
///
|
||||
/// You can use these to make really annoying beep sounds come from an internal self-test
|
||||
|
@ -493,6 +523,99 @@ impl RawDevice {
|
|||
.map_err(nix_err)
|
||||
}
|
||||
|
||||
/// Update the auto repeat delays
|
||||
#[inline]
|
||||
pub fn update_auto_repeat(&mut self, repeat: &AutoRepeat) -> io::Result<()> {
|
||||
unsafe {
|
||||
sys::eviocsrep(
|
||||
self.as_raw_fd(),
|
||||
repeat as *const AutoRepeat as *const [u32; 2],
|
||||
)
|
||||
}
|
||||
.map(|_| {
|
||||
self.auto_repeat = Some(repeat.clone());
|
||||
})
|
||||
.map_err(nix_err)
|
||||
}
|
||||
|
||||
/// Retrieve the scancode for a keycode, if any
|
||||
pub fn get_scancode_by_keycode(&self, keycode: u32) -> io::Result<Vec<u8>> {
|
||||
let mut keymap = libc::input_keymap_entry {
|
||||
flags: 0,
|
||||
len: 0,
|
||||
index: 0,
|
||||
keycode,
|
||||
scancode: [0u8; 32],
|
||||
};
|
||||
|
||||
unsafe { sys::eviocgkeycode_v2(self.as_raw_fd(), &mut keymap) }
|
||||
.map(|_| keymap.scancode[..keymap.len as usize].to_vec())
|
||||
.map_err(nix_err)
|
||||
}
|
||||
|
||||
/// Retrieve the keycode and scancode by index, starting at 0
|
||||
pub fn get_scancode_by_index(&self, index: u16) -> io::Result<(u32, Vec<u8>)> {
|
||||
let mut keymap = libc::input_keymap_entry {
|
||||
flags: INPUT_KEYMAP_BY_INDEX,
|
||||
len: 0,
|
||||
index,
|
||||
keycode: 0,
|
||||
scancode: [0u8; 32],
|
||||
};
|
||||
|
||||
unsafe { sys::eviocgkeycode_v2(self.as_raw_fd(), &mut keymap) }
|
||||
.map(|_| {
|
||||
(
|
||||
keymap.keycode,
|
||||
keymap.scancode[..keymap.len as usize].to_vec(),
|
||||
)
|
||||
})
|
||||
.map_err(nix_err)
|
||||
}
|
||||
|
||||
/// Update a scancode by index. The return value is the previous keycode
|
||||
pub fn update_scancode_by_index(
|
||||
&self,
|
||||
index: u16,
|
||||
keycode: u32,
|
||||
scancode: &[u8],
|
||||
) -> io::Result<u32> {
|
||||
let len = scancode.len();
|
||||
|
||||
let mut keymap = libc::input_keymap_entry {
|
||||
flags: INPUT_KEYMAP_BY_INDEX,
|
||||
len: len as u8,
|
||||
index,
|
||||
keycode,
|
||||
scancode: [0u8; 32],
|
||||
};
|
||||
|
||||
keymap.scancode[..len].copy_from_slice(scancode);
|
||||
|
||||
unsafe { sys::eviocskeycode_v2(self.as_raw_fd(), &keymap) }
|
||||
.map(|keycode| keycode as u32)
|
||||
.map_err(nix_err)
|
||||
}
|
||||
|
||||
/// Update a scancode. The return value is the previous keycode
|
||||
pub fn update_scancode(&self, keycode: u32, scancode: &[u8]) -> io::Result<u32> {
|
||||
let len = scancode.len();
|
||||
|
||||
let mut keymap = libc::input_keymap_entry {
|
||||
flags: 0,
|
||||
len: len as u8,
|
||||
index: 0,
|
||||
keycode,
|
||||
scancode: [0u8; 32],
|
||||
};
|
||||
|
||||
keymap.scancode[..len].copy_from_slice(scancode);
|
||||
|
||||
unsafe { sys::eviocskeycode_v2(self.as_raw_fd(), &keymap) }
|
||||
.map(|keycode| keycode as u32)
|
||||
.map_err(nix_err)
|
||||
}
|
||||
|
||||
#[cfg(feature = "tokio")]
|
||||
#[inline]
|
||||
pub fn into_event_stream(self) -> io::Result<EventStream> {
|
||||
|
|
|
@ -188,6 +188,7 @@ evdev_enum!(
|
|||
KEY_MSDOS = 151,
|
||||
KEY_COFFEE = 152, /* AL Terminal Lock/Screensaver */
|
||||
KEY_DIRECTION = 153,
|
||||
KEY_ROTATE_DISPLAY = 153,
|
||||
KEY_CYCLEWINDOWS = 154,
|
||||
KEY_MAIL = 155,
|
||||
KEY_BOOKMARKS = 156, /* AC Bookmarks */
|
||||
|
@ -362,6 +363,7 @@ evdev_enum!(
|
|||
KEY_SUBTITLE = 0x172,
|
||||
KEY_ANGLE = 0x173,
|
||||
KEY_ZOOM = 0x174,
|
||||
KEY_FULL_SCREEN = 0x174,
|
||||
KEY_MODE = 0x175,
|
||||
KEY_KEYBOARD = 0x176,
|
||||
KEY_SCREEN = 0x177,
|
||||
|
@ -479,6 +481,10 @@ evdev_enum!(
|
|||
KEY_NUMERIC_9 = 0x209,
|
||||
KEY_NUMERIC_STAR = 0x20a,
|
||||
KEY_NUMERIC_POUND = 0x20b,
|
||||
KEY_NUMERIC_A = 0x20c, /* Phone key A - HUT Telephony 0xb9 */
|
||||
KEY_NUMERIC_B = 0x20d,
|
||||
KEY_NUMERIC_C = 0x20e,
|
||||
KEY_NUMERIC_D = 0x20f,
|
||||
KEY_CAMERA_FOCUS = 0x210,
|
||||
KEY_WPS_BUTTON = 0x211, /* WiFi Protected Setup key */
|
||||
KEY_TOUCHPAD_TOGGLE = 0x212, /* Request switch touchpad on or off */
|
||||
|
@ -498,14 +504,16 @@ evdev_enum!(
|
|||
BTN_DPAD_DOWN = 0x221,
|
||||
BTN_DPAD_LEFT = 0x222,
|
||||
BTN_DPAD_RIGHT = 0x223,
|
||||
KEY_ALS_TOGGLE = 0x230, /* Ambient light sensor */
|
||||
KEY_BUTTONCONFIG = 0x240, /* AL Button Configuration */
|
||||
KEY_TASKMANAGER = 0x241, /* AL Task/Project Manager */
|
||||
KEY_JOURNAL = 0x242, /* AL Log/Journal/Timecard */
|
||||
KEY_CONTROLPANEL = 0x243, /* AL Control Panel */
|
||||
KEY_APPSELECT = 0x244, /* AL Select Task/Application */
|
||||
KEY_SCREENSAVER = 0x245, /* AL Screen Saver */
|
||||
KEY_VOICECOMMAND = 0x246, /* Listening Voice Command */
|
||||
KEY_ALS_TOGGLE = 0x230, /* Ambient light sensor */
|
||||
KEY_BUTTONCONFIG = 0x240, /* AL Button Configuration */
|
||||
KEY_TASKMANAGER = 0x241, /* AL Task/Project Manager */
|
||||
KEY_JOURNAL = 0x242, /* AL Log/Journal/Timecard */
|
||||
KEY_CONTROLPANEL = 0x243, /* AL Control Panel */
|
||||
KEY_APPSELECT = 0x244, /* AL Select Task/Application */
|
||||
KEY_SCREENSAVER = 0x245, /* AL Screen Saver */
|
||||
KEY_VOICECOMMAND = 0x246, /* Listening Voice Command */
|
||||
KEY_ASSISTANT = 0x247,
|
||||
KEY_KBD_LAYOUT_NEXT = 0x248,
|
||||
KEY_BRIGHTNESS_MIN = 0x250, /* Set Brightness to Minimum */
|
||||
KEY_BRIGHTNESS_MAX = 0x251, /* Set Brightness to Maximum */
|
||||
KEY_KBDINPUTASSIST_PREV = 0x260,
|
||||
|
@ -514,6 +522,27 @@ evdev_enum!(
|
|||
KEY_KBDINPUTASSIST_NEXTGROUP = 0x263,
|
||||
KEY_KBDINPUTASSIST_ACCEPT = 0x264,
|
||||
KEY_KBDINPUTASSIST_CANCEL = 0x265,
|
||||
KEY_RIGHT_UP = 0x266,
|
||||
KEY_RIGHT_DOWN = 0x267,
|
||||
KEY_LEFT_UP = 0x268,
|
||||
KEY_LEFT_DOWN = 0x269,
|
||||
KEY_ROOT_MENU = 0x26a,
|
||||
KEY_MEDIA_TOP_MENU = 0x26b,
|
||||
KEY_NUMERIC_11 = 0x26c,
|
||||
KEY_NUMERIC_12 = 0x26d,
|
||||
KEY_AUDIO_DESC = 0x26e,
|
||||
KEY_3D_MODE = 0x26f,
|
||||
KEY_NEXT_FAVORITE = 0x270,
|
||||
KEY_STOP_RECORD = 0x271,
|
||||
KEY_PAUSE_RECORD = 0x272,
|
||||
KEY_VOD = 0x273, /* Video on Demand */
|
||||
KEY_UNMUTE = 0x274,
|
||||
KEY_FASTREVERSE = 0x275,
|
||||
KEY_SLOWREVERSE = 0x276,
|
||||
KEY_DATA = 0x277,
|
||||
KEY_ONSCREEN_KEYBOARD = 0x278,
|
||||
KEY_PRIVACY_SCREEN_TOGGLE = 0x279,
|
||||
KEY_SELECTIVE_SCREENSHOT = 0x27a,
|
||||
BTN_TRIGGER_HAPPY1 = 0x2c0,
|
||||
BTN_TRIGGER_HAPPY2 = 0x2c1,
|
||||
BTN_TRIGGER_HAPPY3 = 0x2c2,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::constants::*;
|
||||
use crate::device_state::DeviceState;
|
||||
use crate::raw_stream::RawDevice;
|
||||
use crate::{AttributeSet, AttributeSetRef, InputEvent, InputEventKind, InputId, Key};
|
||||
use crate::{AttributeSet, AttributeSetRef, AutoRepeat, InputEvent, InputEventKind, InputId, Key};
|
||||
use std::os::unix::io::{AsRawFd, RawFd};
|
||||
use std::path::Path;
|
||||
use std::time::SystemTime;
|
||||
|
@ -85,6 +85,44 @@ impl Device {
|
|||
self.raw.input_id()
|
||||
}
|
||||
|
||||
/// Returns a struct containing the delay and period for auto repeat
|
||||
pub fn get_auto_repeat(&self) -> Option<AutoRepeat> {
|
||||
self.raw.get_auto_repeat()
|
||||
}
|
||||
|
||||
/// Update the delay and period for autorepeat
|
||||
pub fn update_auto_repeat(&mut self, repeat: &AutoRepeat) -> io::Result<()> {
|
||||
self.raw.update_auto_repeat(repeat)
|
||||
}
|
||||
|
||||
/// Retrieve the scancode for a keycode, if any
|
||||
pub fn get_scancode_by_keycode(&self, keycode: Key) -> io::Result<Vec<u8>> {
|
||||
self.raw.get_scancode_by_keycode(keycode.code() as u32)
|
||||
}
|
||||
|
||||
/// Retrieve the keycode and scancode by index, starting at 0
|
||||
pub fn get_scancode_by_index(&self, index: u16) -> io::Result<(u32, Vec<u8>)> {
|
||||
self.raw.get_scancode_by_index(index)
|
||||
}
|
||||
|
||||
/// Update a scancode. The return value is the previous keycode
|
||||
pub fn update_scancode(&self, keycode: Key, scancode: &[u8]) -> io::Result<Key> {
|
||||
self.raw
|
||||
.update_scancode(keycode.code() as u32, scancode)
|
||||
.map(|keycode| Key::new(keycode as u16))
|
||||
}
|
||||
|
||||
/// Update a scancode by index. The return value is the previous keycode
|
||||
pub fn update_scancode_by_index(
|
||||
&self,
|
||||
index: u16,
|
||||
keycode: Key,
|
||||
scancode: &[u8],
|
||||
) -> io::Result<u32> {
|
||||
self.raw
|
||||
.update_scancode_by_index(index, keycode.code() as u32, scancode)
|
||||
}
|
||||
|
||||
/// Returns the set of supported "properties" for the device (see `INPUT_PROP_*` in kernel headers)
|
||||
pub fn properties(&self) -> &AttributeSetRef<PropType> {
|
||||
self.raw.properties()
|
||||
|
@ -207,10 +245,6 @@ impl Device {
|
|||
self.raw.misc_properties()
|
||||
}
|
||||
|
||||
// pub fn supported_repeats(&self) -> Option<Repeat> {
|
||||
// self.rep
|
||||
// }
|
||||
|
||||
/// Returns the set of supported simple sounds supported by a device.
|
||||
///
|
||||
/// You can use these to make really annoying beep sounds come from an internal self-test
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use libc::c_int;
|
||||
use libc::{ff_effect, input_absinfo, input_id, uinput_setup};
|
||||
use libc::{ff_effect, input_absinfo, input_id, input_keymap_entry, uinput_setup};
|
||||
// use libc::{
|
||||
// ff_condition_effect, ff_constant_effect, ff_envelope, ff_periodic_effect, ff_ramp_effect,
|
||||
// ff_replay, ff_rumble_effect, ff_trigger, input_event, input_keymap_entry,
|
||||
|
@ -15,10 +15,11 @@ ioctl_read!(eviocgkeycode, b'E', 0x04, [::libc::c_uint; 2]);
|
|||
ioctl_read!(eviocgrep, b'E', 0x03, [::libc::c_uint; 2]);
|
||||
ioctl_read!(eviocgversion, b'E', 0x01, ::libc::c_int);
|
||||
ioctl_write_int!(eviocrmff, b'E', 0x81);
|
||||
// ioctl!(read eviocgkeycode_v2 with b'E', 0x04; /*struct*/ input_keymap_entry);
|
||||
|
||||
ioctl_read!(eviocgkeycode_v2, b'E', 0x04, input_keymap_entry);
|
||||
// TODO #define EVIOCSFF _IOC ( _IOC_WRITE , 'E' , 0x80 , sizeof ( struct ff_effect ) )
|
||||
ioctl_write_ptr!(eviocskeycode, b'E', 0x04, [::libc::c_uint; 2]);
|
||||
// ioctl!(write_int eviocskeycode_v2 with b'E', 0x04; /*struct*/ input_keymap_entry);
|
||||
ioctl_write_ptr!(eviocskeycode_v2, b'E', 0x04, input_keymap_entry);
|
||||
ioctl_write_ptr!(eviocsrep, b'E', 0x03, [::libc::c_uint; 2]);
|
||||
|
||||
ioctl_read_buf!(eviocgname, b'E', 0x06, u8);
|
||||
|
|
Loading…
Reference in a new issue