summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilipp Gesang <phg@phi-gamma.net>2021-12-12 23:17:29 +0100
committerPhilipp Gesang <phg@phi-gamma.net>2021-12-12 23:19:45 +0100
commit92f35f8e90199e4d9dfbcc545be456f4c2d7a1ce (patch)
tree99decf47747cc32983dd0a149600e7e7256866ff
parent468341393863e35bec170528ab5a99ee26acb85a (diff)
downloadvtcol-92f35f8e90199e4d9dfbcc545be456f4c2d7a1ce.tar.gz
lib: implement “kb flags”
A const-genericized version of the “kb leds” implementation. Does seem to consistently run into EINVAL no matter what flags we provide. Also incomplete as KDGKBLED / KDSKBLED pack more info into higher bits of their argument.
-rw-r--r--src/lib.rs156
-rw-r--r--src/vtcol.rs260
2 files changed, 303 insertions, 113 deletions
diff --git a/src/lib.rs b/src/lib.rs
index 75595cd..5d777de 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -46,7 +46,7 @@ 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, KbLedFlags, KbLedState, Palette};
+ use super::{cvt_r, KbLeds, Palette};
use libc::ioctl;
use std::{io::Result, os::unix::io::AsRawFd};
@@ -96,7 +96,14 @@ pub mod ioctl
Ok(pal)
}
- pub fn kdgetled<F: AsRawFd>(fd: &F) -> Result<KbLedState>
+ #[allow(non_snake_case)]
+ pub fn kdg__led<
+ F: AsRawFd,
+ const GET: libc::c_ulong,
+ const SET: libc::c_ulong,
+ >(
+ fd: &F,
+ ) -> Result<KbLeds<GET, SET>>
{
let mut leds: libc::c_char = 0;
@@ -104,7 +111,7 @@ pub mod ioctl
unsafe {
ioctl(
fd.as_raw_fd(),
- KDGETLED,
+ GET,
std::mem::transmute::<&mut libc::c_char, *mut libc::c_void>(
&mut leds,
),
@@ -113,7 +120,7 @@ pub mod ioctl
})
.map(|_| ())?;
- Ok(KbLedState::from(leds))
+ Ok(KbLeds::from(leds))
}
/** If ``state`` is ``None`` it is taken to mean “revert to normal” as per
@@ -125,8 +132,15 @@ pub mod ioctl
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<()>
+ #[allow(non_snake_case)]
+ pub fn kds__led<
+ F: AsRawFd,
+ const GET: libc::c_ulong,
+ const SET: libc::c_ulong,
+ >(
+ fd: &F,
+ state: Option<KbLeds<GET, SET>>,
+ ) -> Result<()>
{
let leds: libc::c_ulong = if let Some(state) = state {
state.into()
@@ -138,7 +152,7 @@ pub mod ioctl
unsafe {
ioctl(
fd.as_raw_fd(),
- KDSETLED,
+ SET,
std::mem::transmute::<&libc::c_ulong, *const libc::c_void>(
&leds,
),
@@ -150,44 +164,6 @@ pub mod ioctl
Ok(())
}
- pub fn kdgkbled<F: AsRawFd>(fd: &F) -> Result<KbLedFlags>
- {
- let mut flags: libc::c_char = 0;
-
- cvt_r(&mut || {
- unsafe {
- ioctl(
- fd.as_raw_fd(),
- KDGKBLED,
- std::mem::transmute::<&mut libc::c_char, *mut libc::c_void>(
- &mut flags,
- ),
- )
- }
- })
- .map(|_| ())?;
-
- Ok(KbLedFlags::from(flags))
- }
-
- pub fn kdskbled<F: AsRawFd>(fd: &F, flags: KbLedFlags) -> Result<()>
- {
- let flags = libc::c_ulong::from(flags);
-
- cvt_r(&mut || {
- unsafe {
- ioctl(
- fd.as_raw_fd(),
- KDSKBLED,
- std::mem::transmute::<&libc::c_ulong, *const libc::c_void>(
- &flags,
- ),
- )
- }
- })
- .map(|_| ())
- }
-
pub fn kdgkbtype<F: AsRawFd>(fd: &F) -> Result<libc::c_char>
{
let mut kb: libc::c_char = 0;
@@ -202,12 +178,18 @@ pub mod ioctl
/** Base type which the LED state and flags are aliases of. */
#[derive(Clone, Copy, Debug)]
-pub struct KbLeds(u8);
+pub struct KbLeds<const GET: libc::c_ulong, const SET: libc::c_ulong>(u8);
-pub type KbLedFlags = KbLeds;
-pub type KbLedState = KbLeds;
+/* XXX why do we need this? the constants from ioctl:: don’t work */
+const KDGETLED: libc::c_ulong = 0x4b31;
+const KDSETLED: libc::c_ulong = 0x4b32;
+const KDGKBLED: libc::c_ulong = 0x4B64;
+const KDSKBLED: libc::c_ulong = 0x4B65;
-impl KbLeds
+pub type KbLedState = KbLeds<KDGETLED, KDSETLED>;
+pub type KbLedFlags = KbLeds<KDGKBLED, KDSKBLED>;
+
+impl<const GET: libc::c_ulong, const SET: libc::c_ulong> KbLeds<GET, SET>
{
pub fn new(cap: bool, num: bool, scr: bool) -> Self
{
@@ -221,18 +203,21 @@ impl KbLeds
}
#[inline]
- pub fn get(con: &Console) -> io::Result<Self> { ioctl::kdgetled(con) }
+ pub fn get(con: &Console) -> io::Result<Self>
+ {
+ ioctl::kdg__led::<Console, GET, SET>(con)
+ }
#[inline]
pub fn set(&self, con: &Console) -> io::Result<()>
{
- ioctl::kdsetled(con, Some(*self))
+ ioctl::kds__led::<Console, GET, SET>(con, Some(*self))
}
#[inline]
pub fn revert(con: &Console) -> io::Result<()>
{
- ioctl::kdsetled(con, None)
+ ioctl::kds__led::<Console, GET, SET>(con, None)
}
#[inline]
@@ -266,7 +251,8 @@ impl KbLeds
}
}
-impl fmt::Display for KbLeds
+impl<const GET: libc::c_ulong, const SET: libc::c_ulong> fmt::Display
+ for KbLeds<GET, SET>
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
{
@@ -280,7 +266,8 @@ impl fmt::Display for KbLeds
}
}
-impl From<libc::c_char> for KbLeds
+impl<const GET: libc::c_ulong, const SET: libc::c_ulong> From<libc::c_char>
+ for KbLeds<GET, SET>
{
fn from(leds: libc::c_char) -> Self
{
@@ -288,17 +275,20 @@ impl From<libc::c_char> for KbLeds
}
}
-impl From<KbLeds> for libc::c_ulong
+impl<const GET: libc::c_ulong, const SET: libc::c_ulong> From<KbLeds<GET, SET>>
+ for libc::c_ulong
{
- fn from(state: KbLeds) -> Self { state.0 as libc::c_ulong }
+ fn from(state: KbLeds<GET, SET>) -> Self { state.0 as libc::c_ulong }
}
-impl From<KbLeds> for u8
+impl<const GET: libc::c_ulong, const SET: libc::c_ulong> From<KbLeds<GET, SET>>
+ for u8
{
- fn from(state: KbLeds) -> Self { state.0 }
+ fn from(state: KbLeds<GET, SET>) -> Self { state.0 }
}
-impl TryFrom<u8> for KbLeds
+impl<const GET: libc::c_ulong, const SET: libc::c_ulong> TryFrom<u8>
+ for KbLeds<GET, SET>
{
type Error = io::Error;
@@ -321,49 +311,25 @@ impl TryFrom<u8> for KbLeds
#[cfg(test)]
mod kb_led_state
{
- use super::KbLeds;
+ use super::KbLedState;
#[test]
fn create()
{
- assert_eq!(0u8, KbLeds::new(false, false, false).into());
- assert_eq!(1u8, KbLeds::new(false, false, true).into());
- assert_eq!(2u8, KbLeds::new(false, true, false).into());
- assert_eq!(4u8, KbLeds::new(true, false, false).into());
- assert_eq!(6u8, KbLeds::new(true, true, false).into());
-
- assert_eq!(0u8, KbLeds::from(0u8 as libc::c_char).into());
- assert_eq!(1u8, KbLeds::from(1u8 as libc::c_char).into());
- assert_eq!(2u8, KbLeds::from(2u8 as libc::c_char).into());
- assert_eq!(4u8, KbLeds::from(4u8 as libc::c_char).into());
- assert_eq!(6u8, KbLeds::from(6u8 as libc::c_char).into());
+ 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(Clone, Copy, Debug)]
-//pub struct KbLedFlags(u8);
-
-//impl KbLedFlags {
-//pub fn new(cap: bool, num: bool, scr: bool) -> Self
-//{
-//let mut flags = 0u8;
-
-//flags |= (cap as u8) << 2;
-//flags |= (num as u8) << 1;
-//flags |= scr as u8;
-
-//Self(flags)
-//}
-//}
-
-//impl From<libc::c_char> for KbLedFlags
-//{
-//fn from(flags: libc::c_char) -> Self
-//{
-//Self::new(flags & 0x4 != 0, flags & 0x2 != 0, flags & 0x1 != 0)
-//}
-//}
-
#[derive(Debug)]
pub struct Fd(libc::c_int);
diff --git a/src/vtcol.rs b/src/vtcol.rs
index b24937b..a3ff57b 100644
--- a/src/vtcol.rs
+++ b/src/vtcol.rs
@@ -1,6 +1,6 @@
pub mod lib;
-use vtcol::{Console, Fade, KbLedState, Palette, Scheme};
+use vtcol::{Console, Fade, KbLedFlags, KbLedState, Palette, Scheme};
use anyhow::{anyhow, Result};
use std::{io::{self, BufWriter},
@@ -127,6 +127,105 @@ impl LedJob
} /* [impl LedJob] */
#[derive(Debug)]
+enum FlagJob
+{
+ /** Get keyboard flags. */
+ Get(bool),
+ /** Set all keyboard flags at once. */
+ Set(KbLedFlags),
+ /** Set keyboard LED state of individual LEDs. */
+ SetIndividual(Option<bool>, Option<bool>, Option<bool>),
+}
+
+impl FlagJob
+{
+ /** Get the keyboard flags (modifier locks). */
+ fn get(con: Option<String>, raw: bool) -> Result<()>
+ {
+ let fd = open_console(con.as_deref())?;
+ vrb!("console fd: {}", fd);
+
+ let leds = KbLedFlags::get(&fd)?;
+
+ if raw {
+ println!("{}", u8::from(leds));
+ } else {
+ println!("{}", leds);
+ }
+
+ Ok(())
+ }
+
+ /** Set the keyboard flags. */
+ fn set(con: Option<String>, st: KbLedFlags) -> Result<()>
+ {
+ let fd = open_console(con.as_deref())?;
+ vrb!("console fd: {}", fd);
+
+ st.set(&fd)?;
+ vrb!("applied");
+
+ Ok(())
+ }
+
+ /** Set / unset keyboard flags using the current as base. */
+ fn set_individual(
+ con: Option<String>,
+ cap: Option<bool>,
+ num: Option<bool>,
+ scr: Option<bool>,
+ ) -> Result<()>
+ {
+ let fd = open_console(con.as_deref())?;
+ vrb!("console fd: {}", fd);
+
+ let mut st = KbLedFlags::get(&fd)?;
+
+ cap.map(|b| st.set_cap(b));
+ num.map(|b| st.set_num(b));
+ scr.map(|b| st.set_scr(b));
+
+ st.set(&fd)?;
+ vrb!("applied");
+
+ Ok(())
+ }
+} /*[impl FlagJob] */
+
+impl Run for FlagJob
+{
+ fn run(self, console: Option<String>) -> Result<()>
+ {
+ match self {
+ Self::Get(raw) => Self::get(console, raw),
+ Self::Set(flags) => Self::set(console, flags),
+ Self::SetIndividual(c, n, s) =>
+ Self::set_individual(console, c, n, s),
+ }
+ }
+} /* [impl Run for FlagJob] */
+
+#[derive(Debug)]
+enum KbJob
+{
+ /** LED state ops. */
+ Leds(LedJob),
+ /** Flags. */
+ Flags(FlagJob),
+}
+
+impl Run for KbJob
+{
+ fn run(self, console: Option<String>) -> Result<()>
+ {
+ match self {
+ Self::Leds(leds) => leds.run(console),
+ Self::Flags(flags) => flags.run(console),
+ }
+ }
+} /* [impl Run for KbJob] */
+
+#[derive(Debug)]
enum ColorJob
{
/** List available schemes. */
@@ -286,7 +385,7 @@ enum Subcmd
/** Console palette ops. */
Colors(ColorJob),
/** Keyboard LED ops. */
- Leds(LedJob),
+ Kb(KbJob),
}
#[derive(Debug)]
@@ -545,6 +644,85 @@ impl<'a> Job
]),
),
),
+ )
+ .subcommand(
+ SubCommand::with_name("flags")
+ .about(
+ "operations regarding keyboard flags \
+ (modifier locks)",
+ )
+ .subcommand(
+ SubCommand::with_name("get")
+ .about("get flags")
+ .arg(
+ Arg::with_name("u8")
+ .short("8")
+ .long("u8")
+ .help("output raw flags as integer")
+ .takes_value(false),
+ ),
+ )
+ .subcommand(
+ SubCommand::with_name("set")
+ .about("set flags")
+ .arg(
+ Arg::with_name("u8")
+ .short("8")
+ .long("u8")
+ .help(
+ "provide desired flags as
+ integer",
+ )
+ .takes_value(true)
+ .required_unless_one(&[
+ "revert", "caps", "num",
+ "scroll",
+ ])
+ .conflicts_with_all(&[
+ "revert", "caps", "num",
+ "scroll",
+ ])
+ .value_name("STATE"),
+ )
+ .arg(
+ Arg::with_name("caps")
+ .short("c")
+ .long("caps")
+ .help("[de]activate Caps Lock flag")
+ .takes_value(true)
+ .possible_values(&["on", "off"])
+ .conflicts_with_all(&[
+ "revert", "u8",
+ ])
+ .value_name("STATE"),
+ )
+ .arg(
+ Arg::with_name("num")
+ .short("n")
+ .long("num")
+ .help("[de]activate Num Lock flag")
+ .takes_value(true)
+ .possible_values(&["on", "off"])
+ .conflicts_with_all(&[
+ "revert", "u8",
+ ])
+ .value_name("STATE"),
+ )
+ .arg(
+ Arg::with_name("scroll")
+ .short("s")
+ .long("scroll")
+ .help(
+ "[de]activate Scroll Lock flag",
+ )
+ .takes_value(true)
+ .possible_values(&["on", "off"])
+ .conflicts_with_all(&[
+ "revert", "u8",
+ ])
+ .value_name("STATE"),
+ ),
+ ),
),
);
@@ -681,13 +859,16 @@ impl<'a> Job
match subm.subcommand() {
("get", Some(subm)) => {
let raw = subm.is_present("u8");
- Ok(Self(con, Subcmd::Leds(LedJob::Get(raw))))
+ Ok(Self(
+ con,
+ Subcmd::Kb(KbJob::Leds(LedJob::Get(raw))),
+ ))
},
("set", Some(subm)) => {
if subm.is_present("revert") {
return Ok(Self(
con,
- Subcmd::Leds(LedJob::Revert),
+ Subcmd::Kb(KbJob::Leds(LedJob::Revert)),
));
}
if let Some(st) = subm.value_of("u8") {
@@ -695,7 +876,50 @@ impl<'a> Job
let st = KbLedState::try_from(st)?;
return Ok(Self(
con,
- Subcmd::Leds(LedJob::Set(st)),
+ Subcmd::Kb(KbJob::Leds(LedJob::Set(
+ st,
+ ))),
+ ));
+ }
+ let cap =
+ subm.value_of("caps").map(|a| a == "on");
+ let num =
+ subm.value_of("num").map(|a| a == "on");
+ let scr =
+ subm.value_of("scroll").map(|a| a == "on");
+ Ok(Self(
+ con,
+ Subcmd::Kb(KbJob::Leds(
+ LedJob::SetIndividual(cap, num, scr),
+ )),
+ ))
+ },
+ (leds_junk, _) =>
+ Err(anyhow!(
+ "invalid sub-sub-subcommand to kb leds: \
+ [{}]; try ``{} kb leds --help``",
+ leds_junk,
+ clap::crate_name!()
+ )),
+ },
+ ("flags", Some(subm)) =>
+ match subm.subcommand() {
+ ("get", Some(subm)) => {
+ let raw = subm.is_present("u8");
+ Ok(Self(
+ con,
+ Subcmd::Kb(KbJob::Flags(FlagJob::Get(raw))),
+ ))
+ },
+ ("set", Some(subm)) => {
+ if let Some(st) = subm.value_of("u8") {
+ let st: u8 = st.parse()?;
+ let st = KbLedFlags::try_from(st)?;
+ return Ok(Self(
+ con,
+ Subcmd::Kb(KbJob::Flags(FlagJob::Set(
+ st,
+ ))),
));
}
let cap =
@@ -706,32 +930,32 @@ impl<'a> Job
subm.value_of("scroll").map(|a| a == "on");
Ok(Self(
con,
- Subcmd::Leds(LedJob::SetIndividual(
- cap, num, scr,
+ Subcmd::Kb(KbJob::Flags(
+ FlagJob::SetIndividual(cap, num, scr),
)),
))
},
- (junk, _) =>
+ (flags_junk, _) =>
Err(anyhow!(
- "invalid sub-subcommand to leds: [{}]; \
- try ``{} leds --help``",
- junk,
+ "invalid sub-sub-subcommand to kb flags: \
+ [{}]; try ``{} kb flags --help``",
+ flags_junk,
clap::crate_name!()
)),
},
- (leds_junk, _) =>
+ (kb_junk, _) =>
Err(anyhow!(
- "invalid subcommand to kb leds [{}]; try ``{} \
+ "invalid sub-subcommand to kb [{}]; try ``{} kb \
--help``",
- leds_junk,
+ kb_junk,
clap::crate_name!()
)),
},
- (kb_junk, _) =>
+ (junk, _) =>
Err(anyhow!(
- "invalid subcommand to kb [{}]; try ``{} --help``",
- kb_junk,
+ "invalid subcommand [{}]; try ``{} --help``",
+ junk,
clap::crate_name!()
)),
}
@@ -749,7 +973,7 @@ impl<'a> Job
let Job(con, cmd) = self;
match cmd {
Subcmd::Colors(cols) => cols.run(con)?,
- Subcmd::Leds(leds) => leds.run(con)?,
+ Subcmd::Kb(kb) => kb.run(con)?,
}
Ok(())