Skip to content

Commit

Permalink
x11rb: Check if there are previous mappings for a keysym
Browse files Browse the repository at this point in the history
  • Loading branch information
pentamassiv committed Oct 21, 2023
1 parent e494681 commit a044f04
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 20 deletions.
60 changes: 53 additions & 7 deletions src/linux/keymap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use std::fmt::Display;

use log::{debug, trace};
pub(super) use xkbcommon::xkb::Keysym;
use xkeysym::KeyCode;

#[cfg(feature = "wayland")]
use crate::keycodes::ModifierBitflag;
Expand All @@ -18,7 +19,12 @@ const DEFAULT_DELAY: u32 = 12;

#[derive(Debug)]
pub struct KeyMap<Keycode> {
pub(super) keymap: HashMap<Keysym, Keycode>,
pub(super) additionally_mapped: HashMap<Keysym, Keycode>,
keysyms: Vec<u32>,
keycode_min: Keycode,
keycode_max: Keycode,
keysyms_per_keycode: u8,

unused_keycodes: VecDeque<Keycode>,
protected_keycodes: Vec<Keycode>, /* These keycodes cannot be unmapped, because they are
* currently held */
Expand Down Expand Up @@ -56,6 +62,8 @@ where
keycode_min: Keycode,
keycode_max: Keycode,
unused_keycodes: VecDeque<Keycode>,
keysyms_per_keycode: u8,
keysyms: Vec<u32>,
) -> Self {
let capacity: usize = keycode_max.try_into().unwrap() - keycode_min.try_into().unwrap();
let capacity = capacity + 1;
Expand All @@ -75,7 +83,11 @@ where
#[cfg(feature = "x11rb")]
let pending_delays = 0;
Self {
keymap,
additionally_mapped: keymap,
keysyms,
keycode_min,
keycode_max,
keysyms_per_keycode,
unused_keycodes,
protected_keycodes: held_keycodes,
needs_regeneration,
Expand All @@ -94,6 +106,35 @@ where
}
}

fn keysym_to_keycode(&self, keysym: Keysym) -> Option<Keycode> {
let keycode_min: usize = self.keycode_min.try_into().unwrap();
let keycode_max: usize = self.keycode_max.try_into().unwrap();

for j in 0..self.keysyms_per_keycode {
for i in keycode_min..=keycode_max {
let i: u32 = i.try_into().unwrap();
let min_keycode: u32 = keycode_min.try_into().unwrap();
let keycode = KeyCode::from(i);
let min_keycode = KeyCode::from(min_keycode);
if let Some(ks) = xkeysym::keysym(
keycode,
j,
min_keycode,
self.keysyms_per_keycode,
&self.keysyms,
) {
if ks == keysym {
let i: usize = i.try_into().unwrap();
let i: Keycode = i.try_into().unwrap();
trace!("found keysym in row {i}, col {j}");
return Some(i);
}
}
}
}
None
}

// Try to enter the key
#[allow(clippy::unnecessary_wraps)]
pub fn key_to_keycode<C: Bind<Keycode>>(&mut self, c: &C, key: Key) -> InputResult<Keycode> {
Expand All @@ -107,7 +148,12 @@ where
// Unwrapping here is okay, because the fn only returns an error if it was a
// Key::Raw and we test that before
let sym = Keysym::try_from(key).unwrap();
if let Some(&keycode) = self.keymap.get(&sym) {

if let Some(keycode) = self.keysym_to_keycode(sym) {
return Ok(keycode);
}

if let Some(&keycode) = self.additionally_mapped.get(&sym) {
// The keysym is already mapped and cached in the keymap
keycode
} else {
Expand Down Expand Up @@ -147,7 +193,7 @@ where
return Err(InputError::Mapping(format!("{keysym:?}")));
};
self.needs_regeneration = true;
self.keymap.insert(keysym, unused_keycode);
self.additionally_mapped.insert(keysym, unused_keycode);
debug!("mapped keycode {} to keysym {:?}", unused_keycode, keysym);
Ok(unused_keycode)
}
Expand All @@ -171,7 +217,7 @@ where
};
self.needs_regeneration = true;
self.unused_keycodes.push_back(keycode);
self.keymap.remove(&keysym);
self.additionally_mapped.remove(&keysym);
debug!("unmapped keysym {:?}", keysym);
Ok(())
}
Expand Down Expand Up @@ -215,7 +261,7 @@ where
// Unmap all keys, if all keycodes are already being used
// TODO: Don't unmap the keycodes if they will be needed next
if self.unused_keycodes.is_empty() {
let mapped_keys = self.keymap.clone();
let mapped_keys = self.additionally_mapped.clone();
let held_keycodes = self.protected_keycodes.clone();
let mut made_room = false;

Expand Down Expand Up @@ -265,7 +311,7 @@ where
// Move the virtual cursor of the file to the end of the part of the keymap that
// is always the same so we only overwrite the parts that can change.
keymap_file.seek(SeekFrom::Start(KEYMAP_BEGINNING.len() as u64))?;
for (&keysym, &keycode) in &self.keymap {
for (&keysym, &keycode) in &self.additionally_mapped {
write!(
keymap_file,
"
Expand Down
5 changes: 4 additions & 1 deletion src/linux/wayland.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,10 @@ impl Con {
for n in 8..=255 {
unused_keycodes.push_back(n as Keycode);
}
let keymap = KeyMap::new(8, 255, unused_keycodes);

// TODO: Double check this and adjust it
let (keysyms_per_keycode, keysyms) = (0, vec![]);
let keymap = KeyMap::new(8, 255, unused_keycodes, keysyms_per_keycode, keysyms);

if virtual_keyboard.is_none() && input_method.is_none() && virtual_pointer.is_none() {
return Err(NewConError::EstablishCon(
Expand Down
45 changes: 33 additions & 12 deletions src/linux/x11rb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,12 +70,21 @@ impl Con {
let screen = setup.roots[screen_idx].clone();
let min_keycode = setup.min_keycode;
let max_keycode = setup.max_keycode;
let unused_keycodes = Self::find_unused_keycodes(&connection, min_keycode, max_keycode)?; // Check if a mapping is possible
let (keysyms_per_keycode, keysyms) =
Self::get_keybord_mapping(&connection, min_keycode, max_keycode)?; // Check if a mapping is possible
let unused_keycodes =
Self::unused_keycodes(min_keycode, max_keycode, keysyms_per_keycode, &keysyms); // Check if a mapping is possible

if unused_keycodes.is_empty() {
return Err(NewConError::NoEmptyKeycodes);
}
let keymap = KeyMap::new(min_keycode, max_keycode, unused_keycodes);
let keymap = KeyMap::new(
min_keycode,
max_keycode,
unused_keycodes,
keysyms_per_keycode,
keysyms,
);

// Get the keycodes of the modifiers
let modifiers = Self::find_modifier_keycodes(&connection)?;
Expand All @@ -101,30 +110,39 @@ impl Con {
}

/// Find keycodes that have not yet been mapped any keysyms
fn find_unused_keycodes(
fn get_keybord_mapping(
connection: &CompositorConnection,
keycode_min: Keycode,
keycode_max: Keycode,
) -> Result<VecDeque<Keycode>, ReplyError> {
let mut unused_keycodes: VecDeque<Keycode> =
VecDeque::with_capacity((keycode_max - keycode_min) as usize);

) -> Result<(u8, Vec<u32>), ReplyError> {
let GetKeyboardMappingReply {
keysyms_per_keycode,
keysyms,
..
} = connection
.get_keyboard_mapping(keycode_min, keycode_max - keycode_min)?
.get_keyboard_mapping(keycode_min, keycode_max - keycode_min + 1)?
.reply()?;

//let keysyms = keysyms.into_iter().map(|s| Keysym::from(s)).collect();
Ok((keysyms_per_keycode, keysyms))
}

fn unused_keycodes(
keycode_min: Keycode,
keycode_max: Keycode,
keysyms_per_keycode: u8,
keysyms: &[u32],
) -> VecDeque<Keycode> {
let mut unused_keycodes: VecDeque<Keycode> =
VecDeque::with_capacity((keycode_max - keycode_min) as usize);

// Split the mapping into the chunks of keysyms that are mapped to each keycode
trace!("initial keymap:");
let keysyms = keysyms.chunks(keysyms_per_keycode as usize);
for (syms, kc) in keysyms.zip(keycode_min..=keycode_max) {
// Check if the keycode is unused

if log::log_enabled!(log::Level::Trace) {
let syms_name: Vec<Keysym> = syms.into_iter().map(|&s| Keysym::from(s)).collect();
let syms_name: Vec<Keysym> = syms.iter().map(|&s| Keysym::from(s)).collect();
trace!("{kc}: {syms_name:?}");
}

Expand All @@ -133,8 +151,9 @@ impl Con {
}
}
debug!("unused keycodes: {unused_keycodes:?}");
Ok(unused_keycodes)
unused_keycodes
}

/// Find the keycodes that must be used for the modifiers
fn find_modifier_keycodes(
connection: &CompositorConnection,
Expand Down Expand Up @@ -200,7 +219,7 @@ impl Drop for Con {
// Map all previously mapped keycodes to the NoSymbol keysym to revert all
// changes
debug!("x11rb connection was dropped");
for &keycode in self.keymap.keymap.values() {
for &keycode in self.keymap.additionally_mapped.values() {
match self.connection.bind_key(keycode, NO_SYMBOL) {
Ok(()) => debug!("unmapped keycode {keycode:?}"),
Err(e) => error!("unable to unmap keycode {keycode:?}. {e:?}"),
Expand Down Expand Up @@ -268,6 +287,7 @@ impl KeyboardControllableNext for Con {
error!("{e}");
InputError::Simulate("error when using xtest_fake_input with x11rb: {e:?}")
})?;
trace!("press");
}

// TODO: Check if we need to update the delays again
Expand All @@ -289,6 +309,7 @@ impl KeyboardControllableNext for Con {
error!("{e}");
InputError::Simulate("error when using xtest_fake_input with x11rb: {e:?}")
})?;
trace!("released");
}

self.connection.sync()
Expand Down

0 comments on commit a044f04

Please sign in to comment.