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 {
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),

View file

@ -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::*;

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] =
[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> {

View file

@ -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,

View file

@ -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

View file

@ -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);