diff options
| -rw-r--r-- | src/lib.rs | 156 | ||||
| -rw-r--r-- | src/vtcol.rs | 260 | 
2 files changed, 303 insertions, 113 deletions
@@ -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(())  | 
