Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wayland: Fix simulating input in general #237

Merged
merged 6 commits into from
Nov 1, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
162 changes: 108 additions & 54 deletions src/linux/wayland.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,66 +103,88 @@ impl Con {
return Err(NewConError::EstablishCon("wayland roundtrip not possible"));
};

// Setup virtual keyboard
let virtual_keyboard = if let Some(seat) = state.seat.as_ref() {
state
.keyboard_manager
.as_ref()
.map(|vk_mgr| vk_mgr.create_virtual_keyboard(seat, &qh, ()))
} else {
None
let (virtual_keyboard, input_method, virtual_pointer) = (None, None, None);

let base_time = Instant::now();

let mut unused_keycodes = VecDeque::with_capacity(255 - 8 + 1); // All keycodes are unused when initialized
for n in 8..=255 {
unused_keycodes.push_back(n as Keycode);
}

// 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);

let mut connection = Self {
keymap,
event_queue,
state,
virtual_keyboard,
input_method,
virtual_pointer,
base_time,
};

// Setup input method
let input_method = if let Some(seat) = state.seat.as_ref() {
state
connection.init_protocols()?;

if connection.apply_keymap().is_err() {
return Err(NewConError::EstablishCon("unable to apply the keymap"));
};
Ok(connection)
}

/// Try to set up all the protocols. An error is returned, if no protocol is
/// available
fn init_protocols(&mut self) -> Result<(), NewConError> {
let qh = self.event_queue.handle();

if let Some(seat) = self.state.seat.as_ref() {
// Setup virtual keyboard
self.virtual_keyboard = self
.state
.keyboard_manager
.as_ref()
.map(|vk_mgr| vk_mgr.create_virtual_keyboard(seat, &qh, ()));
// Setup input method
self.input_method = self
.state
.im_manager
.as_ref()
.map(|im_mgr| (im_mgr.get_input_method(seat, &qh, ()), 0))
} else {
None
.map(|im_mgr| (im_mgr.get_input_method(seat, &qh, ()), 0));
};

// Setup virtual pointer
let virtual_pointer = state
self.virtual_pointer = self
.state
.pointer_manager
.as_ref()
.map(|vp_mgr| vp_mgr.create_virtual_pointer(state.seat.as_ref(), &qh, ()));
.map(|vp_mgr| vp_mgr.create_virtual_pointer(self.state.seat.as_ref(), &qh, ()));

// Try to authenticate for the KDE Fake Input protocol
// TODO: Get this protocol to work
if let Some(kde_input) = &state.kde_input {
if let Some(kde_input) = &self.state.kde_input {
let application = "enigo".to_string();
let reason = "enter keycodes or move the mouse".to_string();
kde_input.authenticate(application, reason);
}

let base_time = Instant::now();

let mut unused_keycodes = VecDeque::with_capacity(255 - 8 + 1); // All keycodes are unused when initialized
for n in 8..=255 {
unused_keycodes.push_back(n as Keycode);
}

// 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);
trace!(
"protocols available\nvirtual_keyboard: {}\ninput_method: {}\nvirtual_pointer: {}",
self.virtual_keyboard.is_some(),
self.input_method.is_some(),
self.virtual_pointer.is_some(),
);

if virtual_keyboard.is_none() && input_method.is_none() && virtual_pointer.is_none() {
if self.virtual_keyboard.is_none()
&& self.input_method.is_none()
&& self.virtual_pointer.is_none()
{
return Err(NewConError::EstablishCon(
"no protocol available to simulate input",
));
}

Ok(Self {
keymap,
event_queue,
state,
virtual_keyboard,
input_method,
virtual_pointer,
base_time,
})
Ok(())
}

/// Get the duration since the Keymap was created
Expand All @@ -183,12 +205,20 @@ impl Con {
let keycode = keycode - 8; // Adjust by 8 due to the xkb/xwayland requirements

if direction == Direction::Press || direction == Direction::Click {
trace!("vk.key({time}, {keycode}, 1)");
vk.key(time, keycode, 1);
self.flush()?;
// TODO: Change to flush()
if self.event_queue.roundtrip(&mut self.state).is_err() {
return Err(InputError::Simulate("The roundtrip on Wayland failed"));
}
}
if direction == Direction::Release || direction == Direction::Click {
trace!("vk.key({time}, {keycode}, 0)");
vk.key(time, keycode, 0);
self.flush()?;
// TODO: Change to flush()
if self.event_queue.roundtrip(&mut self.state).is_err() {
return Err(InputError::Simulate("The roundtrip on Wayland failed"));
}
}
return Ok(());
}
Expand All @@ -200,8 +230,12 @@ impl Con {
fn send_modifier_event(&mut self, modifiers: ModifierBitflag) -> InputResult<()> {
if let Some(vk) = &self.virtual_keyboard {
is_alive(vk)?;
trace!("vk.modifiers({modifiers}, 0, 0, 0)");
vk.modifiers(modifiers, 0, 0, 0);
self.flush()?;
// TODO: Change to flush()
if self.event_queue.roundtrip(&mut self.state).is_err() {
return Err(InputError::Simulate("The roundtrip on Wayland failed"));
}
return Ok(());
}
Err(InputError::Simulate("no way to enter modifier"))
Expand All @@ -212,6 +246,7 @@ impl Con {
/// # Errors
/// TODO
fn apply_keymap(&mut self) -> InputResult<()> {
trace!("apply_keymap(&mut self)");
if let Some(vk) = &self.virtual_keyboard {
is_alive(vk)?;
let Ok(keymap_res) = self.keymap.regenerate() else {
Expand All @@ -223,8 +258,12 @@ impl Con {
// There should always be a file at this point so unwrapping is fine
// here
if let Some(keymap_size) = keymap_res {
trace!("update wayland keymap");
vk.keymap(1, self.keymap.file.as_ref().unwrap().as_fd(), keymap_size);
self.flush()?;
// TODO: Change to flush()
if self.event_queue.roundtrip(&mut self.state).is_err() {
return Err(InputError::Simulate("The roundtrip on Wayland failed"));
}
}
return Ok(());
}
Expand All @@ -234,7 +273,10 @@ impl Con {
/// Flush the Wayland queue
fn flush(&self) -> InputResult<()> {
match self.event_queue.flush() {
Ok(()) => Ok(()),
Ok(()) => {
trace!("flushed event queue");
Ok(())
}
Err(e) => {
error!("{:?}", e);
Err(InputError::Simulate("could not flush wayland queue"))
Expand Down Expand Up @@ -263,6 +305,10 @@ impl Drop for Con {
if self.flush().is_err() {
error!("could not flush wayland queue");
}
trace!("wayland objects were destroyed");

// TODO: Change to flush()
let _ = self.event_queue.roundtrip(&mut self.state);
}
}

Expand Down Expand Up @@ -524,25 +570,25 @@ impl Drop for WaylandState {

impl KeyboardControllableNext for Con {
fn fast_text_entry(&mut self, text: &str) -> InputResult<Option<()>> {
if let Some((im, serial)) = &mut self.input_method {
if let Some((im, serial)) = self.input_method.as_mut() {
is_alive(im)?;
trace!("fast text input with imput_method protocol");
im.commit_string(text.to_string());
im.commit(*serial);
*serial = serial.wrapping_add(1);
self.flush()?;
// TODO: Change to flush()
if self.event_queue.roundtrip(&mut self.state).is_err() {
return Err(InputError::Simulate("The roundtrip on Wayland failed"));
}
return Ok(Some(()));
}
Ok(None)
}

fn enter_key(&mut self, key: Key, direction: Direction) -> InputResult<()> {
let keycode = self.keymap.key_to_keycode(&(), key)?;

// Apply the new keymap if there were any changes
self.apply_keymap()?;

// Send the events to the compositor
if let Ok(modifier) = Modifier::try_from(key) {
trace!("it is a modifier: {modifier:?}");
if direction == Direction::Click || direction == Direction::Press {
let modifiers = self
.keymap
Expand All @@ -556,13 +602,16 @@ impl KeyboardControllableNext for Con {
self.send_modifier_event(modifiers)?;
}
} else {
let keycode = self.keymap.key_to_keycode(&(), key)?;

// Apply the new keymap if there were any changes
self.apply_keymap()?;
self.send_key_event(keycode, direction)?;
// Let the keymap know that the key was held/no longer held
// This is important to avoid unmapping held keys
self.keymap.enter_key(keycode, direction);
}

// Let the keymap know that the key was held/no longer held
// This is important to avoid unmapping held keys
self.keymap.enter_key(keycode, direction);

Ok(())
}
}
Expand Down Expand Up @@ -604,12 +653,14 @@ impl MouseControllableNext for Con {

if direction == Direction::Press || direction == Direction::Click {
let time = self.get_time();
trace!("vp.button({time}, {button}, wl_pointer::ButtonState::Pressed)");
vp.button(time, button, wl_pointer::ButtonState::Pressed);
vp.frame(); // TODO: Check if this is needed
}

if direction == Direction::Release || direction == Direction::Click {
let time = self.get_time();
trace!("vp.button({time}, {button}, wl_pointer::ButtonState::Released)");
vp.button(time, button, wl_pointer::ButtonState::Released);
vp.frame(); // TODO: Check if this is needed
}
Expand All @@ -631,6 +682,7 @@ impl MouseControllableNext for Con {
let time = self.get_time();
match coordinate {
Coordinate::Relative => {
trace!("vp.motion({time}, {x}, {y})");
vp.motion(time, x as f64, y as f64);
}
Coordinate::Absolute => {
Expand All @@ -644,6 +696,7 @@ impl MouseControllableNext for Con {
"the absolute coordinates cannot be negative",
));
};
trace!("vp.motion_absolute({time}, {x}, {y}, u32::MAX, u32::MAX)");
vp.motion_absolute(
time,
x,
Expand Down Expand Up @@ -671,6 +724,7 @@ impl MouseControllableNext for Con {
Axis::Horizontal => wl_pointer::Axis::HorizontalScroll,
Axis::Vertical => wl_pointer::Axis::VerticalScroll,
};
trace!("vp.axis(time, axis, length.into())");
vp.axis(time, axis, length.into());
vp.frame(); // TODO: Check if this is needed
}
Expand Down
Loading