From 59977d8310dd1ebca923e3334b14581e6acfc25c Mon Sep 17 00:00:00 2001 From: Antikyth <104020300+Antikyth@users.noreply.github.com> Date: Fri, 3 Feb 2023 17:03:51 +0000 Subject: [PATCH] SetModifierMapping request + reply, GetModifierMapping request + reply 120 out of 120 requests! --- src/x11/reply/input.rs | 225 ++++++++++++++++++++++++++++++++++++++- src/x11/request/input.rs | 217 +++++++++++++++++++++++++++++++++++++ 2 files changed, 439 insertions(+), 3 deletions(-) diff --git a/src/x11/reply/input.rs b/src/x11/reply/input.rs index 886366ec..4701b594 100644 --- a/src/x11/reply/input.rs +++ b/src/x11/reply/input.rs @@ -16,6 +16,7 @@ extern crate self as xrb; +use array_init::array_init; use derivative::Derivative; use xrbk::{Buf, BufMut, ConstantX11Size, ReadResult, Readable, Writable, WriteResult, X11Size}; @@ -32,6 +33,7 @@ use crate::{ Coords, FocusWindow, GrabStatus, + Keycode, Keysym, ModifierMask, Timestamp, @@ -337,7 +339,7 @@ derive_xrb! { /// The [keysyms] mapped to a particular [keycode]. /// /// [keysyms]: Keysym -/// [keycode]: crate::Keycode +/// [keycode]: Keycode pub type KeyMapping = Vec; /// The [reply] to a [`GetKeyboardMapping` request]. @@ -362,7 +364,7 @@ pub struct GetKeyboardMapping { /// The mapping of [keysyms] for each [keycode] in the specified `range`. /// - /// [keycode]: crate::Keycode + /// [keycode]: Keycode /// [keysyms]: Keysym pub mappings: Vec, } @@ -543,7 +545,7 @@ derive_xrb! { /// /// See [`KeyboardOptions::auto_repeat_mode`] for more information. /// - /// [keycodes]: crate::Keycode + /// [keycodes]: Keycode /// [auto repeat mode]: crate::set::KeyboardOptions::auto_repeat_mode /// /// [`KeyboardOptions::auto_repeat_mode`]: crate::set::KeyboardOptions::auto_repeat_mode @@ -682,3 +684,220 @@ derive_xrb! { pub mappings: Vec>, } } + +/// Whether a [`SetModifierMapping` request] was [successful]. +/// +/// This is used in the [`SetModifierMapping` reply]. +/// +/// [successful]: SetModifierMappingStatus::Success +/// +/// [`SetModifierMapping` request]: request::SetModifierMapping +/// [`SetModifierMapping` reply]: SetModifierMapping +#[derive(Debug, Hash, PartialEq, Eq, X11Size, Readable, Writable)] +pub enum SetModifierMappingStatus { + /// The [`SetModifierMapping` request] was successful. + /// + /// [`SetModifierMapping` request]: request::SetModifierMapping + Success, + + /// The [`SetModifierMapping` request] failed because either the currently + /// mapped modifier keys or specified new modifier keys are currently held. + /// + /// A [`SetModifierMapping` request] cannot be applied unless both the + /// currently mapped modifier keys and the keys which are specified to be + /// the new modifier keys are not held. + /// + /// [`SetModifierMapping` request]: request::SetModifierMapping + Busy, + /// The [`SetModifierMapping` request] failed because the X server rejected + /// it. + /// + /// The X server rejects a [`SetModifierMapping` request] if it has placed + /// some additional bounds on the modifiers which it is enforcing. For + /// example, this could be because multiple keys per modifier are not + /// supported or because auto-repeat cannot be disabled for certain keys. + /// + /// [`SetModifierMapping` request]: request::SetModifierMapping + Rejected, +} + +derive_xrb! { + /// The [reply] to a [`SetModifierMapping` request]. + /// + /// [reply]: Reply + /// + /// [`SetModifierMapping` request]: request::SetModifierMapping + #[derive(Derivative, Debug, X11Size, Readable, Writable)] + #[derivative(Hash, PartialEq, Eq)] + pub struct SetModifierMapping: Reply for request::SetModifierMapping { + /// The sequence number identifying the [request] that generated this + /// [reply]. + /// + /// See [`Reply::sequence`] for more information. + /// + /// [request]: crate::message::Request + /// [reply]: Reply + /// + /// [`Reply::sequence`]: Reply::sequence + #[sequence] + #[derivative(Hash = "ignore", PartialEq = "ignore")] + pub sequence: u16, + + /// Whether the [`SetModifierMapping` request] was [successful]. + /// + /// See [`SetModifierMappingStatus`] for more information. + /// + /// [successful]: SetModifierMappingStatus::Success + /// + /// [`SetModifierMapping` request]: request::SetModifierMapping + #[metabyte] + pub status: SetModifierMappingStatus, + + [_; 24], + } +} + +/// The [reply] to a [`GetModifierMapping` request]. +/// +/// [reply]: Reply +/// +/// [`GetModifierMapping` request]: request::GetModifierMapping +#[derive(Derivative, Debug)] +#[derivative(Hash, PartialEq, Eq)] +pub struct GetModifierMapping { + /// The sequence number identifying the [request] that generated this + /// [reply]. + /// + /// See [`Reply::sequence`] for more information. + /// + /// [request]: crate::message::Request + /// [reply]: Reply + /// + /// [`Reply::sequence`]: Reply::sequence + #[derivative(Hash = "ignore", PartialEq = "ignore")] + pub sequence: u16, + + /// The [keycodes] mapped to the shift modifier. + /// + /// [keycodes]: Keycode + pub shift_keycodes: Vec, + /// The [keycodes] mapped to the caps lock modifier. + /// + /// [keycodes]: Keycode + pub capslock_keycodes: Vec, + /// The [keycodes] mapped to the control modifier. + /// + /// [keycodes]: Keycode + pub ctrl_keycodes: Vec, + + /// The [keycodes] mapped to the Mod1 modifier. + /// + /// [keycodes]: Keycode + pub mod1_keycodes: Vec, + /// The [keycodes] mapped to the Mod2 modifier. + /// + /// [keycodes]: Keycode + pub mod2_keycodes: Vec, + /// The [keycodes] mapped to the Mod3 modifier. + /// + /// [keycodes]: Keycode + pub mod3_keycodes: Vec, + /// The [keycodes] mapped to the Mod4 modifier. + /// + /// This is typically the key variously called 'super', 'meta', 'windows + /// key', 'cmd', etc. + /// + /// [keycodes]: Keycode + pub mod4_keycodes: Vec, + /// The [keycodes] mapped to the Mod5 modifier. + /// + /// [keycodes]: Keycode + pub mod5_keycodes: Vec, +} + +impl GetModifierMapping { + fn max_keycodes_len(&self) -> usize { + [ + &self.shift_keycodes, + &self.capslock_keycodes, + &self.ctrl_keycodes, + &self.mod1_keycodes, + &self.mod2_keycodes, + &self.mod3_keycodes, + &self.mod4_keycodes, + &self.mod5_keycodes, + ] + .into_iter() + .map(Vec::len) + .max() + .expect("there's definitely more than one element") + } +} + +impl Reply for GetModifierMapping { + type Request = request::GetModifierMapping; + + fn sequence(&self) -> u16 { + self.sequence + } +} + +impl X11Size for GetModifierMapping { + fn x11_size(&self) -> usize { + const HEADER: usize = 8; + const CONSTANT_SIZES: usize = HEADER + 24; + + let keycodes_size = self.max_keycodes_len() * Keycode::X11_SIZE; + + CONSTANT_SIZES + (8 * keycodes_size) + } +} + +impl Readable for GetModifierMapping { + fn read_from(buf: &mut impl Buf) -> ReadResult + where + Self: Sized, + { + const HEADER: usize = 8; + const ALIGNMENT: usize = 4; + + // FIXME: the first 4 bytes of the header should be read separately, with the + // metabyte position and sequence being given as context. That applies to + // all replies. + buf.advance(1); + + let keycodes_per_modifier = buf.get_u8(); + let sequence = buf.get_u16(); + + let total_size = ((buf.get_u32() as usize) * ALIGNMENT) - HEADER; + let buf = &mut buf.take(total_size); + + let [shift_keycodes, capslock_keycodes, ctrl_keycodes, mod1_keycodes, mod2_keycodes, mod3_keycodes, mod4_keycodes, mod5_keycodes] = + array_init(|_| { + let mut keycodes = vec![]; + + for _ in 0..keycodes_per_modifier { + match buf.get_u8() { + 0 => {}, + code => keycodes.push(Keycode(code)), + } + } + + keycodes + }); + + Ok(Self { + sequence, + + shift_keycodes, + capslock_keycodes, + ctrl_keycodes, + + mod1_keycodes, + mod2_keycodes, + mod3_keycodes, + mod4_keycodes, + mod5_keycodes, + }) + } +} diff --git a/src/x11/request/input.rs b/src/x11/request/input.rs index 17693e7a..2f7bcb27 100644 --- a/src/x11/request/input.rs +++ b/src/x11/request/input.rs @@ -26,6 +26,7 @@ use xrbk::{ }; use xrbk_macro::{derive_xrb, Readable, Writable, X11Size}; +use array_init::array_init; use std::ops::RangeInclusive; use thiserror::Error; @@ -1914,3 +1915,219 @@ derive_xrb! { #[derive(Debug, Hash, PartialEq, Eq, X11Size, Readable, Writable)] pub struct GetButtonMapping: Request(117) -> reply::GetButtonMapping; } + +/// A [request] that sets the mapping of [keycodes] for each modifier. +/// +/// Each modifier has zero or more [keycodes] mapped to it. For example, the +/// shift modifier typically has both ⇧ Left Shift and +/// ⇧ Right Shift keycodes mapped to it, while the caps lock modifier +/// only has one Caps Lock key mapped to it. +/// +/// If no [keycodes] are mapped to a modifier, that modifier is disabled. +/// +/// See also: [`GetModifierMapping`]. +/// +/// # Events generated +/// A [`MappingChange` event] is generated if this [request] is [successful] in +/// changing the modifier mapping. +/// +/// # Replies +/// This [request] generates a [`SetModifierMapping` reply]. +/// +/// # Errors +/// A [`Value` error] is generated if any of the specified [keycodes] are either +/// less than the [`min_keycode`] or greater than the [`max_keycode`] returned +/// during [connection setup]. +/// +/// [keycodes]: Keycode +/// [request]: Request +/// [connection setup]: crate::connection::InitConnection +/// +/// [successful]: reply::SetModifierMappingStatus::Success +/// +/// [`min_keycode`]: crate::connection::ConnectionSuccess::min_keycode +/// [`max_keycode`]: crate::connection::ConnectionSuccess::max_keycode +/// +/// [`SetModifierMapping` request]: SetModifierMapping +/// [`SetModifierMapping` reply]: reply::SetModifierMapping +/// +/// [`MappingChange` event]: crate::x11::event::MappingChange +/// +/// [`Value` error]: error::Value +#[derive(Debug, Hash, PartialEq, Eq)] +pub struct SetModifierMapping { + /// The [keycodes] mapped to the shift modifier. + /// + /// [keycodes]: Keycode + pub shift_keycodes: Vec, + /// The [keycodes] mapped to the caps lock modifier. + /// + /// [keycodes]: Keycode + pub capslock_keycodes: Vec, + /// The [keycodes] mapped to the control modifier. + /// + /// [keycodes]: Keycode + pub ctrl_keycodes: Vec, + + /// The [keycodes] mapped to the Mod1 modifier. + /// + /// [keycodes]: Keycode + pub mod1_keycodes: Vec, + /// The [keycodes] mapped to the Mod2 modifier. + /// + /// [keycodes]: Keycode + pub mod2_keycodes: Vec, + /// The [keycodes] mapped to the Mod3 modifier. + /// + /// [keycodes]: Keycode + pub mod3_keycodes: Vec, + /// The [keycodes] mapped to the Mod4 modifier. + /// + /// This is typically the key variously called 'super', 'meta', 'windows + /// key', 'cmd', etc. + /// + /// [keycodes]: Keycode + pub mod4_keycodes: Vec, + /// The [keycodes] mapped to the Mod5 modifier. + /// + /// [keycodes]: Keycode + pub mod5_keycodes: Vec, +} + +impl SetModifierMapping { + fn max_keycodes_len(&self) -> usize { + [ + &self.shift_keycodes, + &self.capslock_keycodes, + &self.ctrl_keycodes, + &self.mod1_keycodes, + &self.mod2_keycodes, + &self.mod3_keycodes, + &self.mod4_keycodes, + &self.mod5_keycodes, + ] + .into_iter() + .map(Vec::len) + .max() + .expect("there's definitely more than one element") + } +} + +impl Request for SetModifierMapping { + type OtherErrors = error::Value; + type Reply = reply::SetModifierMapping; + + const MAJOR_OPCODE: u8 = 118; + const MINOR_OPCODE: Option = None; +} + +impl X11Size for SetModifierMapping { + fn x11_size(&self) -> usize { + const HEADER: usize = 4; + + let keycodes_size = self.max_keycodes_len() * Keycode::X11_SIZE; + + HEADER + (8 * keycodes_size) + } +} + +impl Readable for SetModifierMapping { + fn read_from(buf: &mut impl Buf) -> ReadResult + where + Self: Sized, + { + const ALIGNMENT: usize = 4; + + let keycodes_per_modifier = buf.get_u8(); + + let total_size = usize::from(buf.get_u16()) * ALIGNMENT; + let buf = &mut buf.take(total_size); + + let [shift_keycodes, capslock_keycodes, ctrl_keycodes, mod1_keycodes, mod2_keycodes, mod3_keycodes, mod4_keycodes, mod5_keycodes] = + array_init(|_| { + let mut keycodes = vec![]; + + for _ in 0..keycodes_per_modifier { + match buf.get_u8() { + 0 => {}, + code => keycodes.push(Keycode(code)), + } + } + + keycodes + }); + + Ok(Self { + shift_keycodes, + capslock_keycodes, + ctrl_keycodes, + + mod1_keycodes, + mod2_keycodes, + mod3_keycodes, + mod4_keycodes, + mod5_keycodes, + }) + } +} + +impl Writable for SetModifierMapping { + fn write_to(&self, buf: &mut impl BufMut) -> WriteResult { + const HEADER: usize = 4; + + let max_keycodes_len = self.max_keycodes_len(); + let keycodes_size = max_keycodes_len * Keycode::X11_SIZE; + + let buf = &mut buf.limit(HEADER + (8 * keycodes_size)); + + // For each keycodes field, we want to make sure that they are written + // as the same length as the longest list. Fortunately, that is easy to + // do, because (a) the order of each list does not matter, and (b) a `0` + // means that position is simply ignored, so we can just fill the + // remaining positions with `0`s. + + for field in [ + &self.shift_keycodes, + &self.capslock_keycodes, + &self.ctrl_keycodes, + &self.mod1_keycodes, + &self.mod2_keycodes, + &self.mod3_keycodes, + &self.mod4_keycodes, + &self.mod5_keycodes, + ] { + for index in 0..max_keycodes_len { + match field.get(index) { + Some(Keycode(code)) => buf.put_u8(*code), + None => buf.put_u8(0), + } + } + } + + Ok(()) + } +} + +derive_xrb! { + /// A [request] that returns the [keycodes] currently mapped to each + /// modifier. + /// + /// Each modifier has zero or more [keycodes] mapped to it. For example, the + /// shift modifier typically has both ⇧ Left Shift and + /// ⇧ Right Shift keycodes mapped to it, while the caps lock + /// modifier only has one Caps Lock key mapped to it. + /// + /// If no [keycodes] are mapped to a modifier, that modifier is disabled. + /// + /// See also: [`SetModifierMapping`]. + /// + /// # Replies + /// This [request] generates a [`GetModifierMapping` reply]. + /// + /// [keycodes]: Keycode + /// [request]: Request + /// + /// [`GetModifierMapping` reply]: reply::GetModifierMapping + #[derive(Debug, Hash, PartialEq, Eq, X11Size, Readable, Writable)] + pub struct GetModifierMapping: Request(119) -> reply::GetModifierMapping; +}