diff options
author | Philipp Gesang <phg@phi-gamma.net> | 2021-12-08 19:07:54 +0100 |
---|---|---|
committer | Philipp Gesang <phg@phi-gamma.net> | 2021-12-08 19:49:22 +0100 |
commit | 480435ff68a910eabc011e44f5a63b43536a4d02 (patch) | |
tree | 1a0f66ff14ac1a34f54d9e12f5d6646eac03003f /src | |
parent | 21404d069e9c77489cebcf9e7c8995233abaca28 (diff) | |
download | vtcol-480435ff68a910eabc011e44f5a63b43536a4d02.tar.gz |
add ioctl wrappers for KDGETLED / KDSETLED
Diffstat (limited to 'src')
-rw-r--r-- | src/lib.rs | 124 |
1 files changed, 119 insertions, 5 deletions
@@ -46,17 +46,19 @@ fn cvt_r<T: IsMinusOne>(f: &mut dyn FnMut() -> T) -> io::Result<T> /** Wrappers for ``ioctl_console(2)`` functionality. */ pub mod ioctl { - use super::{cvt_r, Palette}; + use super::{cvt_r, KbLedState, Palette}; use libc::ioctl; - use std::{io, os::unix::io::AsRawFd}; + use std::{io::Result, os::unix::io::AsRawFd}; /* XXX: can we get these into ``libc``? */ pub const KDGKBTYPE: libc::c_ulong = 0x4b33; /* kd.h */ pub const GIO_CMAP: libc::c_ulong = 0x00004B70; /* kd.h */ pub const PIO_CMAP: libc::c_ulong = 0x00004B71; /* kd.h */ pub const KB_101: libc::c_char = 0x0002; /* kd.h */ + pub const KDGETLED: libc::c_ulong = 0x4b31; /* kd.h */ + pub const KDSETLED: libc::c_ulong = 0x4b32; /* kd.h */ - pub fn kdgkbtype<F: AsRawFd>(fd: &F) -> io::Result<libc::c_char> + pub fn kdgkbtype<F: AsRawFd>(fd: &F) -> Result<libc::c_char> { let mut kb: libc::c_char = 0; @@ -67,7 +69,7 @@ pub mod ioctl Ok(kb) } - pub fn pio_cmap<F: AsRawFd>(fd: &F, pal: &Palette) -> io::Result<()> + pub fn pio_cmap<F: AsRawFd>(fd: &F, pal: &Palette) -> Result<()> { /* cvt_r because technically it can’t be ruled out that we hit EINTR. */ cvt_r(&mut || { @@ -82,7 +84,7 @@ pub mod ioctl .map(|_| ()) } - pub fn gio_cmap<F: AsRawFd>(fd: &F) -> io::Result<Palette> + pub fn gio_cmap<F: AsRawFd>(fd: &F) -> Result<Palette> { let mut pal = Palette::new(); @@ -101,6 +103,118 @@ pub mod ioctl .map(|_| ())?; Ok(pal) } + + pub fn kdgetled<F: AsRawFd>(fd: &F) -> Result<KbLedState> + { + let mut leds: libc::c_char = 0; + + cvt_r(&mut || { + unsafe { + ioctl( + fd.as_raw_fd(), + KDGETLED, + std::mem::transmute::<&mut libc::c_char, *mut libc::c_void>( + &mut leds, + ), + ) + } + }) + .map(|_| ())?; + + Ok(KbLedState::from(leds)) + } + + /** If ``state`` is ``None`` it is taken to mean “revert to normal” as per + the man page: + + KDSETLED + Set the LEDs. The LEDs are set to correspond to the lower three + bits of the unsigned long integer in argp. However, if a higher + order bit is set, the LEDs revert to normal: displaying the state + of the keyboard functions of caps lock, num lock, and scroll lock. + */ + + pub fn kdsetled<F: AsRawFd>(fd: &F, state: Option<KbLedState>) + -> Result<()> + { + let leds: libc::c_char = if let Some(state) = state { + state.into() + } else { + libc::c_char::MAX + }; + + cvt_r(&mut || { + unsafe { + ioctl( + fd.as_raw_fd(), + KDSETLED, + std::mem::transmute::<&libc::c_char, *const libc::c_void>( + &leds, + ), + ) + } + }) + .map(|_| ())?; + + Ok(()) + } +} + +#[derive(Debug)] +pub struct KbLedState(u8); + +impl KbLedState +{ + fn new(cap: bool, num: bool, scr: bool) -> Self + { + let mut state = 0u8; + + state |= (cap as u8) << 2; + state |= (num as u8) << 1; + state |= scr as u8; + + Self(state) + } +} + +impl From<libc::c_char> for KbLedState +{ + fn from(leds: libc::c_char) -> Self + { + Self::new(leds & 0x4 != 0, leds & 0x2 != 0, leds & 0x1 != 0) + } +} + +impl From<KbLedState> for libc::c_char +{ + fn from(state: KbLedState) -> Self { state.0 as libc::c_char } +} + +impl From<KbLedState> for u8 +{ + fn from(state: KbLedState) -> Self { state.0 } +} + +#[cfg(test)] +mod kb_led_state +{ + use super::KbLedState; + + #[test] + fn create() + { + assert_eq!(0u8, KbLedState::new(false, false, false).into()); + assert_eq!(1u8, KbLedState::new(false, false, true).into()); + assert_eq!(2u8, KbLedState::new(false, true, false).into()); + assert_eq!(4u8, KbLedState::new(true, false, false).into()); + assert_eq!(6u8, KbLedState::new(true, true, false).into()); + + assert_eq!(0u8, KbLedState::from(0u8 as libc::c_char).into()); + assert_eq!(1u8, KbLedState::from(1u8 as libc::c_char).into()); + assert_eq!(2u8, KbLedState::from(2u8 as libc::c_char).into()); + assert_eq!(4u8, KbLedState::from(4u8 as libc::c_char).into()); + assert_eq!(6u8, KbLedState::from(6u8 as libc::c_char).into()); + } } #[derive(Debug)] |