Fix assorted linux issues (#10061)

- Fix a bug where modifiers would be dispatched before they changed
- Add a secondary modifier
- Improve keybindings

Release Notes:

- N/A
This commit is contained in:
Mikayla Maki 2024-04-01 17:22:59 -07:00 committed by GitHub
parent e0cd96db7b
commit 1da2441e7b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
20 changed files with 220 additions and 154 deletions

View file

@ -1510,12 +1510,12 @@ impl Interactivity {
};
if self.location.is_some()
&& text_bounds.contains(&cx.mouse_position())
&& cx.modifiers().command
&& cx.modifiers().secondary()
{
let command_held = cx.modifiers().command;
let secondary_held = cx.modifiers().secondary();
cx.on_key_event({
move |e: &crate::ModifiersChangedEvent, _phase, cx| {
if e.modifiers.command != command_held
if e.modifiers.secondary() != secondary_held
&& text_bounds.contains(&cx.mouse_position())
{
cx.refresh();

View file

@ -37,7 +37,7 @@ impl Keystroke {
control: self.modifiers.control,
alt: false,
shift: false,
command: false,
platform: false,
function: false,
},
key: ime_key.to_string(),
@ -62,7 +62,7 @@ impl Keystroke {
let mut control = false;
let mut alt = false;
let mut shift = false;
let mut command = false;
let mut platform = false;
let mut function = false;
let mut key = None;
let mut ime_key = None;
@ -73,8 +73,13 @@ impl Keystroke {
"ctrl" => control = true,
"alt" => alt = true,
"shift" => shift = true,
"cmd" => command = true,
"fn" => function = true,
#[cfg(target_os = "macos")]
"cmd" => platform = true,
#[cfg(target_os = "linux")]
"super" => platform = true,
#[cfg(target_os = "windows")]
"win" => platform = true,
_ => {
if let Some(next) = components.peek() {
if next.is_empty() && source.ends_with('-') {
@ -101,7 +106,7 @@ impl Keystroke {
control,
alt,
shift,
command,
platform,
function,
},
key,
@ -114,7 +119,7 @@ impl Keystroke {
/// be able to simulate typing "space", etc.
pub fn with_simulated_ime(mut self) -> Self {
if self.ime_key.is_none()
&& !self.modifiers.command
&& !self.modifiers.platform
&& !self.modifiers.control
&& !self.modifiers.function
&& !self.modifiers.alt
@ -147,8 +152,15 @@ impl std::fmt::Display for Keystroke {
if self.modifiers.alt {
f.write_char('⌥')?;
}
if self.modifiers.command {
if self.modifiers.platform {
#[cfg(target_os = "macos")]
f.write_char('⌘')?;
#[cfg(target_os = "linux")]
f.write_char('❖')?;
#[cfg(target_os = "windows")]
f.write_char('⊞')?;
}
if self.modifiers.shift {
f.write_char('⇧')?;
@ -188,7 +200,8 @@ pub struct Modifiers {
/// The command key, on macos
/// the windows key, on windows
pub command: bool,
/// the super key, on linux
pub platform: bool,
/// The function key
pub function: bool,
@ -197,7 +210,22 @@ pub struct Modifiers {
impl Modifiers {
/// Returns true if any modifier key is pressed
pub fn modified(&self) -> bool {
self.control || self.alt || self.shift || self.command || self.function
self.control || self.alt || self.shift || self.platform || self.function
}
/// Whether the semantically 'secondary' modifier key is pressed
/// On macos, this is the command key
/// On windows and linux, this is the control key
pub fn secondary(&self) -> bool {
#[cfg(target_os = "macos")]
{
return self.platform;
}
#[cfg(not(target_os = "macos"))]
{
return self.control;
}
}
/// helper method for Modifiers with no modifiers
@ -205,10 +233,45 @@ impl Modifiers {
Default::default()
}
/// helper method for Modifiers with just command
/// helper method for Modifiers with just the command key
pub fn command() -> Modifiers {
Modifiers {
command: true,
platform: true,
..Default::default()
}
}
/// A helper method for Modifiers with just the secondary key pressed
pub fn secondary_key() -> Modifiers {
#[cfg(target_os = "macos")]
{
Modifiers {
platform: true,
..Default::default()
}
}
#[cfg(not(target_os = "macos"))]
{
Modifiers {
control: true,
..Default::default()
}
}
}
/// helper method for Modifiers with just the windows key
pub fn windows() -> Modifiers {
Modifiers {
platform: true,
..Default::default()
}
}
/// helper method for Modifiers with just the super key
pub fn super_key() -> Modifiers {
Modifiers {
platform: true,
..Default::default()
}
}
@ -233,7 +296,7 @@ impl Modifiers {
pub fn command_shift() -> Modifiers {
Modifiers {
shift: true,
command: true,
platform: true,
..Default::default()
}
}
@ -243,7 +306,7 @@ impl Modifiers {
(other.control || !self.control)
&& (other.alt || !self.alt)
&& (other.shift || !self.shift)
&& (other.command || !self.command)
&& (other.platform || !self.platform)
&& (other.function || !self.function)
}
}

View file

@ -190,7 +190,7 @@ impl WaylandClient {
control: false,
alt: false,
function: false,
command: false,
platform: false,
},
scroll_direction: -1.0,
axis_source: AxisSource::Wheel,
@ -692,6 +692,11 @@ impl Dispatch<wl_keyboard::WlKeyboard, ()> for WaylandClientState {
group,
..
} => {
let focused_window = state.keyboard_focused_window.clone();
let Some(focused_window) = focused_window else {
return;
};
let keymap_state = state.keymap_state.as_mut().unwrap();
keymap_state.update_mask(mods_depressed, mods_latched, mods_locked, 0, 0, group);
@ -707,14 +712,22 @@ impl Dispatch<wl_keyboard::WlKeyboard, ()> for WaylandClientState {
state.modifiers.shift = shift;
state.modifiers.alt = alt;
state.modifiers.control = control;
state.modifiers.command = command;
state.modifiers.platform = command;
let input = PlatformInput::ModifiersChanged(ModifiersChangedEvent {
modifiers: state.modifiers,
});
drop(state);
focused_window.handle_input(input);
}
wl_keyboard::Event::Key {
key,
state: WEnum::Value(key_state),
..
} => {
let focused_window = &state.keyboard_focused_window;
let focused_window = state.keyboard_focused_window.clone();
let Some(focused_window) = focused_window else {
return;
};
@ -725,80 +738,56 @@ impl Dispatch<wl_keyboard::WlKeyboard, ()> for WaylandClientState {
let keysym = keymap_state.key_get_one_sym(keycode);
match key_state {
wl_keyboard::KeyState::Pressed => {
let input = if keysym.is_modifier_key() {
PlatformInput::ModifiersChanged(ModifiersChangedEvent {
modifiers: state.modifiers,
wl_keyboard::KeyState::Pressed if !keysym.is_modifier_key() => {
let input = PlatformInput::KeyDown(KeyDownEvent {
keystroke: Keystroke::from_xkb(keymap_state, state.modifiers, keycode),
is_held: false, // todo(linux)
});
state.repeat.current_id += 1;
state.repeat.current_keysym = Some(keysym);
let rate = state.repeat.characters_per_second;
let delay = state.repeat.delay;
let id = state.repeat.current_id;
let this = this.clone();
let timer = Timer::from_duration(delay);
let state_ = Rc::clone(&this.client_state_inner);
let input_ = input.clone();
state
.loop_handle
.insert_source(timer, move |event, _metadata, shared_data| {
let state_ = state_.borrow_mut();
let is_repeating = id == state_.repeat.current_id
&& state_.repeat.current_keysym.is_some()
&& state_.keyboard_focused_window.is_some();
if !is_repeating {
return TimeoutAction::Drop;
}
let focused_window =
state_.keyboard_focused_window.as_ref().unwrap().clone();
drop(state_);
focused_window.handle_input(input_.clone());
TimeoutAction::ToDuration(Duration::from_secs(1) / rate)
})
} else {
PlatformInput::KeyDown(KeyDownEvent {
keystroke: Keystroke::from_xkb(
keymap_state,
state.modifiers,
keycode,
),
is_held: false, // todo(linux)
})
};
if !keysym.is_modifier_key() {
state.repeat.current_id += 1;
state.repeat.current_keysym = Some(keysym);
let rate = state.repeat.characters_per_second;
let delay = state.repeat.delay;
let id = state.repeat.current_id;
let this = this.clone();
let timer = Timer::from_duration(delay);
let state_ = Rc::clone(&this.client_state_inner);
let input_ = input.clone();
state
.loop_handle
.insert_source(timer, move |event, _metadata, shared_data| {
let state_ = state_.borrow_mut();
let is_repeating = id == state_.repeat.current_id
&& state_.repeat.current_keysym.is_some()
&& state_.keyboard_focused_window.is_some();
if !is_repeating {
return TimeoutAction::Drop;
}
let focused_window =
state_.keyboard_focused_window.as_ref().unwrap().clone();
drop(state_);
focused_window.handle_input(input_.clone());
TimeoutAction::ToDuration(Duration::from_secs(1) / rate)
})
.unwrap();
}
.unwrap();
drop(state);
focused_window.handle_input(input);
}
wl_keyboard::KeyState::Released => {
let input = if keysym.is_modifier_key() {
PlatformInput::ModifiersChanged(ModifiersChangedEvent {
modifiers: state.modifiers,
})
} else {
PlatformInput::KeyUp(KeyUpEvent {
keystroke: Keystroke::from_xkb(
keymap_state,
state.modifiers,
keycode,
),
})
};
wl_keyboard::KeyState::Released if !keysym.is_modifier_key() => {
let input = PlatformInput::KeyUp(KeyUpEvent {
keystroke: Keystroke::from_xkb(keymap_state, state.modifiers, keycode),
});
if !keysym.is_modifier_key() {
state.repeat.current_keysym = None;
}
state.repeat.current_keysym = None;
drop(state);

View file

@ -18,7 +18,7 @@ pub(crate) fn modifiers_from_state(state: xproto::KeyButMask) -> Modifiers {
control: state.contains(xproto::KeyButMask::CONTROL),
alt: state.contains(xproto::KeyButMask::MOD1),
shift: state.contains(xproto::KeyButMask::SHIFT),
command: state.contains(xproto::KeyButMask::MOD4),
platform: state.contains(xproto::KeyButMask::MOD4),
function: false,
}
}

View file

@ -77,7 +77,7 @@ unsafe fn read_modifiers(native_event: id) -> Modifiers {
control,
alt,
shift,
command,
platform: command,
function,
}
}
@ -323,7 +323,7 @@ unsafe fn parse_keystroke(native_event: id) -> Keystroke {
control,
alt,
shift,
command,
platform: command,
function,
},
key,

View file

@ -279,7 +279,7 @@ impl MacPlatform {
let mut mask = NSEventModifierFlags::empty();
for (modifier, flag) in &[
(
keystroke.modifiers.command,
keystroke.modifiers.platform,
NSEventModifierFlags::NSCommandKeyMask,
),
(

View file

@ -853,7 +853,7 @@ impl PlatformWindow for MacWindow {
control,
alt,
shift,
command,
platform: command,
function,
}
}

View file

@ -239,7 +239,7 @@ impl WindowsWindowInner {
control: self.is_virtual_key_pressed(VK_CONTROL),
alt: self.is_virtual_key_pressed(VK_MENU),
shift: self.is_virtual_key_pressed(VK_SHIFT),
command: self.is_virtual_key_pressed(VK_LWIN) || self.is_virtual_key_pressed(VK_RWIN),
platform: self.is_virtual_key_pressed(VK_LWIN) || self.is_virtual_key_pressed(VK_RWIN),
function: false,
}
}