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:
Sean Young 2021-07-20 17:40:49 +01:00 committed by GitHub
parent d694443d53
commit ed4245c380
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 210 additions and 21 deletions

View file

@ -198,6 +198,7 @@ macro_rules! evdev_enum {
} }
impl std::fmt::Debug for $t { impl std::fmt::Debug for $t {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
#[allow(unreachable_patterns)]
match *self { match *self {
$(Self::$c => f.pad(stringify!($c)),)* $(Self::$c => f.pad(stringify!($c)),)*
_ => write!(f, "unknown key: {}", self.0), _ => write!(f, "unknown key: {}", self.0),

View file

@ -94,6 +94,7 @@ pub use attribute_set::{AttributeSet, AttributeSetRef};
pub use constants::*; pub use constants::*;
pub use device_state::DeviceState; pub use device_state::DeviceState;
pub use inputid::*; pub use inputid::*;
pub use raw_stream::AutoRepeat;
pub use scancodes::*; pub use scancodes::*;
pub use sync_stream::*; pub use sync_stream::*;

View file

@ -38,6 +38,8 @@ const ABSINFO_ZERO: libc::input_absinfo = libc::input_absinfo {
pub(crate) const ABS_VALS_INIT: [libc::input_absinfo; AbsoluteAxisType::COUNT] = pub(crate) const ABS_VALS_INIT: [libc::input_absinfo; AbsoluteAxisType::COUNT] =
[ABSINFO_ZERO; AbsoluteAxisType::COUNT]; [ABSINFO_ZERO; AbsoluteAxisType::COUNT];
const INPUT_KEYMAP_BY_INDEX: u8 = 1;
/// A physical or virtual device supported by evdev. /// A physical or virtual device supported by evdev.
/// ///
/// Each device corresponds to a path typically found in `/dev/input`, and supports access via /// 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_switch: Option<AttributeSet<SwitchType>>,
supported_led: Option<AttributeSet<LedType>>, supported_led: Option<AttributeSet<LedType>>,
supported_misc: Option<AttributeSet<MiscType>>, supported_misc: Option<AttributeSet<MiscType>>,
auto_repeat: Option<AutoRepeat>,
// ff: Option<AttributeSet<_>>, // ff: Option<AttributeSet<_>>,
// ff_stat: Option<FFStatus>, // ff_stat: Option<FFStatus>,
// rep: Option<Repeat>,
supported_snd: Option<AttributeSet<SoundType>>, supported_snd: Option<AttributeSet<SoundType>>,
pub(crate) event_buf: Vec<libc::input_event>, pub(crate) event_buf: Vec<libc::input_event>,
} }
#[derive(Debug, Clone)]
#[repr(C)]
pub struct AutoRepeat {
pub delay: u32,
pub period: u32,
}
impl RawDevice { impl RawDevice {
/// Opens a device, given its system path. /// Opens a device, given its system path.
/// ///
@ -198,6 +207,25 @@ impl RawDevice {
None 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 { Ok(RawDevice {
file, file,
ty, ty,
@ -214,6 +242,7 @@ impl RawDevice {
supported_led, supported_led,
supported_misc, supported_misc,
supported_snd, supported_snd,
auto_repeat,
event_buf: Vec::new(), event_buf: Vec::new(),
}) })
} }
@ -238,6 +267,11 @@ impl RawDevice {
InputId::from(self.id) 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) /// Returns the set of supported "properties" for the device (see `INPUT_PROP_*` in kernel headers)
pub fn properties(&self) -> &AttributeSetRef<PropType> { pub fn properties(&self) -> &AttributeSetRef<PropType> {
&self.props &self.props
@ -360,10 +394,6 @@ impl RawDevice {
self.supported_misc.as_deref() 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. /// 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 /// 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) .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")] #[cfg(feature = "tokio")]
#[inline] #[inline]
pub fn into_event_stream(self) -> io::Result<EventStream> { pub fn into_event_stream(self) -> io::Result<EventStream> {

View file

@ -188,6 +188,7 @@ evdev_enum!(
KEY_MSDOS = 151, KEY_MSDOS = 151,
KEY_COFFEE = 152, /* AL Terminal Lock/Screensaver */ KEY_COFFEE = 152, /* AL Terminal Lock/Screensaver */
KEY_DIRECTION = 153, KEY_DIRECTION = 153,
KEY_ROTATE_DISPLAY = 153,
KEY_CYCLEWINDOWS = 154, KEY_CYCLEWINDOWS = 154,
KEY_MAIL = 155, KEY_MAIL = 155,
KEY_BOOKMARKS = 156, /* AC Bookmarks */ KEY_BOOKMARKS = 156, /* AC Bookmarks */
@ -362,6 +363,7 @@ evdev_enum!(
KEY_SUBTITLE = 0x172, KEY_SUBTITLE = 0x172,
KEY_ANGLE = 0x173, KEY_ANGLE = 0x173,
KEY_ZOOM = 0x174, KEY_ZOOM = 0x174,
KEY_FULL_SCREEN = 0x174,
KEY_MODE = 0x175, KEY_MODE = 0x175,
KEY_KEYBOARD = 0x176, KEY_KEYBOARD = 0x176,
KEY_SCREEN = 0x177, KEY_SCREEN = 0x177,
@ -479,6 +481,10 @@ evdev_enum!(
KEY_NUMERIC_9 = 0x209, KEY_NUMERIC_9 = 0x209,
KEY_NUMERIC_STAR = 0x20a, KEY_NUMERIC_STAR = 0x20a,
KEY_NUMERIC_POUND = 0x20b, 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_CAMERA_FOCUS = 0x210,
KEY_WPS_BUTTON = 0x211, /* WiFi Protected Setup key */ KEY_WPS_BUTTON = 0x211, /* WiFi Protected Setup key */
KEY_TOUCHPAD_TOGGLE = 0x212, /* Request switch touchpad on or off */ KEY_TOUCHPAD_TOGGLE = 0x212, /* Request switch touchpad on or off */
@ -506,6 +512,8 @@ evdev_enum!(
KEY_APPSELECT = 0x244, /* AL Select Task/Application */ KEY_APPSELECT = 0x244, /* AL Select Task/Application */
KEY_SCREENSAVER = 0x245, /* AL Screen Saver */ KEY_SCREENSAVER = 0x245, /* AL Screen Saver */
KEY_VOICECOMMAND = 0x246, /* Listening Voice Command */ KEY_VOICECOMMAND = 0x246, /* Listening Voice Command */
KEY_ASSISTANT = 0x247,
KEY_KBD_LAYOUT_NEXT = 0x248,
KEY_BRIGHTNESS_MIN = 0x250, /* Set Brightness to Minimum */ KEY_BRIGHTNESS_MIN = 0x250, /* Set Brightness to Minimum */
KEY_BRIGHTNESS_MAX = 0x251, /* Set Brightness to Maximum */ KEY_BRIGHTNESS_MAX = 0x251, /* Set Brightness to Maximum */
KEY_KBDINPUTASSIST_PREV = 0x260, KEY_KBDINPUTASSIST_PREV = 0x260,
@ -514,6 +522,27 @@ evdev_enum!(
KEY_KBDINPUTASSIST_NEXTGROUP = 0x263, KEY_KBDINPUTASSIST_NEXTGROUP = 0x263,
KEY_KBDINPUTASSIST_ACCEPT = 0x264, KEY_KBDINPUTASSIST_ACCEPT = 0x264,
KEY_KBDINPUTASSIST_CANCEL = 0x265, 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_HAPPY1 = 0x2c0,
BTN_TRIGGER_HAPPY2 = 0x2c1, BTN_TRIGGER_HAPPY2 = 0x2c1,
BTN_TRIGGER_HAPPY3 = 0x2c2, BTN_TRIGGER_HAPPY3 = 0x2c2,

View file

@ -1,7 +1,7 @@
use crate::constants::*; use crate::constants::*;
use crate::device_state::DeviceState; use crate::device_state::DeviceState;
use crate::raw_stream::RawDevice; 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::os::unix::io::{AsRawFd, RawFd};
use std::path::Path; use std::path::Path;
use std::time::SystemTime; use std::time::SystemTime;
@ -85,6 +85,44 @@ impl Device {
self.raw.input_id() 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) /// Returns the set of supported "properties" for the device (see `INPUT_PROP_*` in kernel headers)
pub fn properties(&self) -> &AttributeSetRef<PropType> { pub fn properties(&self) -> &AttributeSetRef<PropType> {
self.raw.properties() self.raw.properties()
@ -207,10 +245,6 @@ impl Device {
self.raw.misc_properties() self.raw.misc_properties()
} }
// pub fn supported_repeats(&self) -> Option<Repeat> {
// self.rep
// }
/// Returns the set of supported simple sounds supported by a device. /// 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 /// You can use these to make really annoying beep sounds come from an internal self-test

View file

@ -1,5 +1,5 @@
use libc::c_int; 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::{ // use libc::{
// ff_condition_effect, ff_constant_effect, ff_envelope, ff_periodic_effect, ff_ramp_effect, // 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, // 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!(eviocgrep, b'E', 0x03, [::libc::c_uint; 2]);
ioctl_read!(eviocgversion, b'E', 0x01, ::libc::c_int); ioctl_read!(eviocgversion, b'E', 0x01, ::libc::c_int);
ioctl_write_int!(eviocrmff, b'E', 0x81); 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 ) ) // 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_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_write_ptr!(eviocsrep, b'E', 0x03, [::libc::c_uint; 2]);
ioctl_read_buf!(eviocgname, b'E', 0x06, u8); ioctl_read_buf!(eviocgname, b'E', 0x06, u8);