summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/lib.rs124
1 files changed, 119 insertions, 5 deletions
diff --git a/src/lib.rs b/src/lib.rs
index c652565..681177c 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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)]