commit e7081b91130adb07f42687288b1d8fdeb8cae5f6
parent 8b7bfcc67fc84ec5aa4e86a859741a74a4e65456
Author: deurzen <m.deurzen@tum.de>
Date: Sun, 20 Jun 2021 04:43:41 +0200
input handling overhaul
Diffstat:
12 files changed, 1461 insertions(+), 695 deletions(-)
diff --git a/src/core/binding.rs b/src/core/binding.rs
@@ -1,13 +1,12 @@
use crate::model::Model;
-use winsys::input::KeyCode;
-use winsys::input::MouseEventKey;
-use winsys::input::MouseShortcut;
+use winsys::input::KeyInput;
+use winsys::input::MouseInput;
use winsys::window::Window;
use std::collections::HashMap;
-pub type KeyAction = Box<dyn FnMut(&mut Model<'_>)>;
-pub type MouseAction = Box<dyn FnMut(&mut Model<'_>, Option<Window>)>;
-pub type KeyBindings = HashMap<KeyCode, KeyAction>;
-pub type MouseBindings = HashMap<(MouseEventKey, MouseShortcut), (MouseAction, bool)>;
+pub type KeyAction = fn(&mut Model<'_>);
+pub type MouseAction = fn(&mut Model<'_>, Option<Window>) -> bool;
+pub type KeyBindings = HashMap<KeyInput, KeyAction>;
+pub type MouseBindings = HashMap<MouseInput, MouseAction>;
diff --git a/src/core/macros.rs b/src/core/macros.rs
@@ -1,4 +1,13 @@
#[macro_export]
+macro_rules! hashset {
+ ($( $val: expr ),*) => {{
+ let mut set = ::std::collections::HashSet::new();
+ $( set.insert($val); )*
+ set
+ }}
+}
+
+#[macro_export]
macro_rules! call(
($($method:tt)+) => {
|arg| $($method)+(arg)
diff --git a/src/core/main.rs b/src/core/main.rs
@@ -24,6 +24,9 @@ use winsys::geometry::Edge;
use winsys::xdata::xconnection::XConnection;
pub use winsys::Result;
+use std::collections::HashMap;
+use std::collections::HashSet;
+
#[macro_use]
mod macros;
@@ -59,6 +62,14 @@ use compare::MatchMethod;
use jump::JumpCriterium;
use layout::LayoutKind;
use model::Model;
+use winsys::input::Button;
+use winsys::input::Key;
+use winsys::input::KeyInput;
+use winsys::input::Modifier;
+use winsys::input::MouseEventKind;
+use winsys::input::MouseInput;
+use winsys::input::MouseInputTarget;
+use winsys::window::Window;
use workspace::ClientSelector;
pub fn main() -> Result<()> {
@@ -79,288 +90,427 @@ pub fn main() -> Result<()> {
}
fn init_bindings() -> (MouseBindings, KeyBindings) {
- // (kind, target, focus): "[modifiers]-button" => action
- let mouse_bindings = build_mouse_bindings!(
- // client state modifiers
- (Press, Client, true):
- "1-C-Right" => do_internal_mouse_block!(model, window, {
+ let mut mouse_bindings = MouseBindings::new();
+ let mut key_bindings = KeyBindings::new();
+
+ mouse_bindings.insert(
+ MouseInput {
+ target: MouseInputTarget::Client,
+ button: Button::Right,
+ modifiers: hashset!(Modifier::Alt, Modifier::Ctrl),
+ },
+ |model: &mut Model<'_>, window: Option<Window>| -> bool {
if let Some(window) = window {
model.set_floating_window(window, Toggle::Reverse);
}
- }),
- (Press, Client, true):
- "1-C-S-Middle" => do_internal_mouse_block!(model, window, {
+
+ true
+ },
+ );
+
+ mouse_bindings.insert(
+ MouseInput {
+ target: MouseInputTarget::Client,
+ button: Button::Middle,
+ modifiers: hashset!(Modifier::Alt, Modifier::Ctrl, Modifier::Shift),
+ },
+ |model: &mut Model<'_>, window: Option<Window>| -> bool {
if let Some(window) = window {
model.set_fullscreen_window(window, Toggle::Reverse);
}
- }),
- // free client arrangers
- (Press, Client, true):
- "1-Middle" => do_internal_mouse_block!(model, window, {
+ true
+ },
+ );
+
+ mouse_bindings.insert(
+ MouseInput {
+ target: MouseInputTarget::Client,
+ button: Button::Middle,
+ modifiers: hashset!(Modifier::Alt),
+ },
+ |model: &mut Model<'_>, window: Option<Window>| -> bool {
if let Some(window) = window {
model.center_window(window);
}
- }),
- (Press, Client, true):
- "1-Left" => do_internal_mouse_block!(model, window, {
+
+ true
+ },
+ );
+
+ mouse_bindings.insert(
+ MouseInput {
+ target: MouseInputTarget::Client,
+ button: Button::Left,
+ modifiers: hashset!(Modifier::Alt),
+ },
+ |model: &mut Model<'_>, window: Option<Window>| -> bool {
if let Some(window) = window {
model.start_moving(window);
}
- }),
- (Press, Client, true):
- "1-Right" => do_internal_mouse_block!(model, window, {
+
+ true
+ },
+ );
+
+ mouse_bindings.insert(
+ MouseInput {
+ target: MouseInputTarget::Client,
+ button: Button::Right,
+ modifiers: hashset!(Modifier::Alt),
+ },
+ |model: &mut Model<'_>, window: Option<Window>| -> bool {
if let Some(window) = window {
model.start_resizing(window);
}
- }),
- (Press, Client, false):
- "1-C-S-ScrollDown" => do_internal_mouse_block!(model, window, {
+
+ true
+ },
+ );
+
+ mouse_bindings.insert(
+ MouseInput {
+ target: MouseInputTarget::Client,
+ button: Button::ScrollDown,
+ modifiers: hashset!(Modifier::Alt, Modifier::Ctrl, Modifier::Shift),
+ },
+ |model: &mut Model<'_>, window: Option<Window>| -> bool {
if let Some(window) = window {
model.grow_ratio_window(window, -15);
}
- }),
- (Press, Client, false):
- "1-C-S-ScrollUp" => do_internal_mouse_block!(model, window, {
+
+ true
+ },
+ );
+
+ mouse_bindings.insert(
+ MouseInput {
+ target: MouseInputTarget::Client,
+ button: Button::ScrollUp,
+ modifiers: hashset!(Modifier::Alt, Modifier::Ctrl, Modifier::Shift),
+ },
+ |model: &mut Model<'_>, window: Option<Window>| -> bool {
if let Some(window) = window {
model.grow_ratio_window(window, 15);
}
- }),
-
- // client order modifiers
- (Press, Global, false):
- "1-ScrollDown" => do_internal_mouse!(cycle_focus, Direction::Forward),
- (Press, Global, false):
- "1-ScrollUp" => do_internal_mouse!(cycle_focus, Direction::Backward),
-
- // workspace activators
- (Press, Global, false):
- "1-S-ScrollUp" => do_internal_mouse!(activate_next_workspace, Direction::Backward),
- (Press, Global, false):
- "1-S-ScrollDown" => do_internal_mouse!(activate_next_workspace, Direction::Forward),
-
- // workspace client movement
- (Press, Client, false):
- "1-Forward" => do_internal_mouse_block!(model, window, {
+
+ true
+ },
+ );
+
+ mouse_bindings.insert(
+ MouseInput {
+ target: MouseInputTarget::Client,
+ button: Button::ScrollUp,
+ modifiers: hashset!(Modifier::Alt),
+ },
+ |model: &mut Model<'_>, _: Option<Window>| -> bool {
+ model.cycle_focus(Direction::Backward);
+ false
+ }
+ );
+
+ mouse_bindings.insert(
+ MouseInput {
+ target: MouseInputTarget::Client,
+ button: Button::ScrollDown,
+ modifiers: hashset!(Modifier::Alt),
+ },
+ |model: &mut Model<'_>, _: Option<Window>| -> bool {
+ model.cycle_focus(Direction::Forward);
+ false
+ }
+ );
+
+ mouse_bindings.insert(
+ MouseInput {
+ target: MouseInputTarget::Global,
+ button: Button::ScrollUp,
+ modifiers: hashset!(Modifier::Alt, Modifier::Shift),
+ },
+ |model: &mut Model<'_>, _: Option<Window>| -> bool {
+ model.activate_next_workspace(Direction::Backward);
+ false
+ }
+ );
+
+ mouse_bindings.insert(
+ MouseInput {
+ target: MouseInputTarget::Global,
+ button: Button::ScrollDown,
+ modifiers: hashset!(Modifier::Alt, Modifier::Shift),
+ },
+ |model: &mut Model<'_>, _: Option<Window>| -> bool {
+ model.activate_next_workspace(Direction::Forward);
+ false
+ }
+ );
+
+ mouse_bindings.insert(
+ MouseInput {
+ target: MouseInputTarget::Client,
+ button: Button::Backward,
+ modifiers: hashset!(Modifier::Alt),
+ },
+ |model: &mut Model<'_>, window: Option<Window>| -> bool {
if let Some(window) = window {
- model.move_window_to_next_workspace(window, Direction::Forward);
+ model.move_window_to_next_workspace(window, Direction::Backward);
}
- }),
- (Press, Client, false):
- "1-Backward" => do_internal_mouse_block!(model, window, {
+
+ false
+ }
+ );
+
+ mouse_bindings.insert(
+ MouseInput {
+ target: MouseInputTarget::Client,
+ button: Button::Forward,
+ modifiers: hashset!(Modifier::Alt),
+ },
+ |model: &mut Model<'_>, window: Option<Window>| -> bool {
if let Some(window) = window {
- model.move_window_to_next_workspace(window, Direction::Backward);
+ model.move_window_to_next_workspace(window, Direction::Forward);
}
- }),
- // NOPs
- (Release, Global, false):
- "1-ScrollDown" => do_nothing!(),
- (Release, Global, false):
- "1-ScrollUp" => do_nothing!(),
+ false
+ }
);
- // "[modifiers]-key" => action
- let key_bindings = build_key_bindings!(
- "1-C-S-q" => do_internal!(exit),
-
- // client state modifiers
- "1-c" => do_internal!(kill_focus),
- "1-S-space" => do_internal!(set_floating_focus, Toggle::Reverse),
- "1-f" => do_internal!(set_fullscreen_focus, Toggle::Reverse),
- "1-x" => do_internal!(set_stick_focus, Toggle::Reverse),
- "1-2-C-f" => do_internal!(set_contained_focus, Toggle::Reverse),
- "1-2-C-i" => do_internal!(set_invincible_focus, Toggle::Reverse),
- "1-2-C-p" => do_internal!(set_producing_focus, Toggle::Reverse),
- "1-2-C-y" => do_internal!(set_iconifyable_focus, Toggle::Reverse),
- "1-y" => do_internal!(set_iconify_focus, Toggle::On),
- "1-u" => do_internal!(pop_deiconify),
- "1-2-u" => do_internal_block!(model, {
- model.deiconify_all(model.active_workspace());
- }),
-
- // free client arrangers
- "1-C-space" => do_internal!(center_focus),
- "1-C-h" => do_internal!(nudge_focus, Edge::Left, 15),
- "1-C-j" => do_internal!(nudge_focus, Edge::Bottom, 15),
- "1-C-k" => do_internal!(nudge_focus, Edge::Top, 15),
- "1-C-l" => do_internal!(nudge_focus, Edge::Right, 15),
- "1-C-S-h" => do_internal!(stretch_focus, Edge::Left, 15),
- "1-C-S-j" => do_internal!(stretch_focus, Edge::Bottom, 15),
- "1-C-S-k" => do_internal!(stretch_focus, Edge::Top, 15),
- "1-C-S-l" => do_internal!(stretch_focus, Edge::Right, 15),
- "1-C-S-y" => do_internal!(stretch_focus, Edge::Left, -15),
- "1-C-S-u" => do_internal!(stretch_focus, Edge::Bottom, -15),
- "1-C-S-i" => do_internal!(stretch_focus, Edge::Top, -15),
- "1-C-S-o" => do_internal!(stretch_focus, Edge::Right, -15),
- "1-C-Left" => do_internal!(snap_focus, Edge::Left),
- "1-C-Down" => do_internal!(snap_focus, Edge::Bottom),
- "1-C-Up" => do_internal!(snap_focus, Edge::Top),
- "1-C-Right" => do_internal!(snap_focus, Edge::Right),
-
- // client order modifiers
- "1-j" => do_internal!(cycle_focus, Direction::Forward),
- "1-k" => do_internal!(cycle_focus, Direction::Backward),
- "1-S-j" => do_internal!(drag_focus, Direction::Forward),
- "1-S-k" => do_internal!(drag_focus, Direction::Backward),
- "1-S-semicolon" => do_internal!(rotate_clients, Direction::Forward),
- "1-S-comma" => do_internal!(rotate_clients, Direction::Backward),
-
- // zone creators
- "1-C-Return" => do_internal!(create_layout_zone),
- "1-C-S-Return" => do_internal!(create_tab_zone),
- "1-C-C" => do_internal!(delete_zone),
-
- // zone order modifiers
- // "1-C-j" => do_internal!(cycle_zones, Direction::Forward),
- // "1-C-k" => do_internal!(cycle_zones, Direction::Backward),
-
- // active workspace layout modifiers
- "1-S-f" => do_internal!(set_layout, LayoutKind::Float),
- "1-S-l" => do_internal!(set_layout, LayoutKind::BLFloat),
- "1-z" => do_internal!(set_layout, LayoutKind::SingleFloat),
- "1-S-z" => do_internal!(set_layout, LayoutKind::BLSingleFloat),
- "1-m" => do_internal!(set_layout, LayoutKind::Monocle),
- "1-g" => do_internal!(set_layout, LayoutKind::Center),
- "1-t" => do_internal!(set_layout, LayoutKind::Stack),
- "1-S-t" => do_internal!(set_layout, LayoutKind::SStack),
- "1-C-S-p" => do_internal!(set_layout, LayoutKind::Paper),
- "1-2-C-S-p" => do_internal!(set_layout, LayoutKind::SPaper),
- "1-C-S-b" => do_internal!(set_layout, LayoutKind::BStack),
- "1-2-C-S-b" => do_internal!(set_layout, LayoutKind::SBStack),
- "1-S-y" => do_internal!(set_layout, LayoutKind::Horz),
- "1-C-y" => do_internal!(set_layout, LayoutKind::SHorz),
- "1-S-v" => do_internal!(set_layout, LayoutKind::Vert),
- "1-C-v" => do_internal!(set_layout, LayoutKind::SVert),
- "1-C-S-f" => do_internal!(apply_float_retain_region),
- "1-space" => do_internal!(toggle_layout),
-
- // active workspace layout data modifiers
- "1-plus" => do_internal!(change_gap_size, Change::Inc(5u32)),
- "1-minus" => do_internal!(change_gap_size, Change::Dec(5u32)),
- "1-S-equal" => do_internal!(reset_gap_size),
- "1-i" => do_internal!(change_main_count, Change::Inc(1u32)),
- "1-d" => do_internal!(change_main_count, Change::Dec(1u32)),
- "1-l" => do_internal!(change_main_factor, Change::Inc(0.05f32)),
- "1-h" => do_internal!(change_main_factor, Change::Dec(0.05f32)),
- "1-S-Left" => do_internal!(change_margin, Edge::Left, Change::Inc(5i32)),
- "1-C-S-Left" => do_internal!(change_margin, Edge::Left, Change::Dec(5i32)),
- "1-S-Up" => do_internal!(change_margin, Edge::Top, Change::Inc(5i32)),
- "1-C-S-Up" => do_internal!(change_margin, Edge::Top, Change::Dec(5i32)),
- "1-S-Down" => do_internal!(change_margin, Edge::Bottom, Change::Inc(5i32)),
- "1-C-S-Down" => do_internal!(change_margin, Edge::Bottom, Change::Dec(5i32)),
- "1-S-Right" => do_internal!(change_margin, Edge::Right, Change::Inc(5i32)),
- "1-C-S-Right" => do_internal!(change_margin, Edge::Right, Change::Dec(5i32)),
- "1-C-S-equal" => do_internal!(reset_margin),
- "1-2-C-S-l" => do_internal!(copy_prev_layout_data),
- "1-2-C-S-equal" => do_internal!(reset_layout_data),
-
- // workspace activators
- "1-Escape" => do_internal!(toggle_workspace),
- "1-bracketleft" => do_internal!(activate_next_workspace, Direction::Backward),
- "1-bracketright" => do_internal!(activate_next_workspace, Direction::Forward),
- "1-1" => do_internal!(activate_workspace, 0),
- "1-2" => do_internal!(activate_workspace, 1),
- "1-3" => do_internal!(activate_workspace, 2),
- "1-4" => do_internal!(activate_workspace, 3),
- "1-5" => do_internal!(activate_workspace, 4),
- "1-6" => do_internal!(activate_workspace, 5),
- "1-7" => do_internal!(activate_workspace, 6),
- "1-8" => do_internal!(activate_workspace, 7),
- "1-9" => do_internal!(activate_workspace, 8),
- "1-0" => do_internal!(activate_workspace, 9),
-
- // workspace client movers
- "1-S-bracketleft" => do_internal!(move_focus_to_next_workspace, Direction::Backward),
- "1-S-bracketright" => do_internal!(move_focus_to_next_workspace, Direction::Forward),
- "1-S-1" => do_internal!(move_focus_to_workspace, 0),
- "1-S-2" => do_internal!(move_focus_to_workspace, 1),
- "1-S-3" => do_internal!(move_focus_to_workspace, 2),
- "1-S-4" => do_internal!(move_focus_to_workspace, 3),
- "1-S-5" => do_internal!(move_focus_to_workspace, 4),
- "1-S-6" => do_internal!(move_focus_to_workspace, 5),
- "1-S-7" => do_internal!(move_focus_to_workspace, 6),
- "1-S-8" => do_internal!(move_focus_to_workspace, 7),
- "1-S-9" => do_internal!(move_focus_to_workspace, 8),
- "1-S-0" => do_internal!(move_focus_to_workspace, 9),
-
- // placeable region modifiers
- "1-v" => do_internal!(toggle_screen_struts),
-
- // client jump criteria
- "1-b" => do_internal!(jump_client,
- JumpCriterium::ByClass(MatchMethod::Equals("qutebrowser"))
- ),
- "1-S-b" => do_internal!(jump_client,
- JumpCriterium::ByClass(MatchMethod::Equals("Firefox"))
- ),
- "1-C-b" => do_internal!(jump_client,
- JumpCriterium::ByClass(MatchMethod::Equals("Chromium"))
- ),
- "1-2-space" => do_internal!(jump_client,
- JumpCriterium::ByClass(MatchMethod::Equals("Spotify"))
- ),
- "1-e" => do_internal_block!(model, {
- model.jump_client(JumpCriterium::ByName(
- MatchMethod::Contains("[vim]"),
- ));
- }),
- "1-slash" => do_internal_block!(model, {
- model.jump_client(JumpCriterium::OnWorkspaceBySelector(
- model.active_workspace(),
- &ClientSelector::Last,
- ));
- }),
- "1-period" => do_internal_block!(model, {
- model.jump_client(JumpCriterium::OnWorkspaceBySelector(
- model.active_workspace(),
- &ClientSelector::AtMaster,
- ));
- }),
- "1-comma" => do_internal_block!(model, {
- model.jump_client(JumpCriterium::OnWorkspaceBySelector(
- model.active_workspace(),
- &ClientSelector::First,
- ));
- }),
-
- // external spawn commands
- "XF86AudioPlay", "1-2-p" => spawn_external!("playerctl play-pause"),
- "XF86AudioPrev", "1-2-k" => spawn_external!("playerctl previous"),
- "XF86AudioNext", "1-2-j" => spawn_external!("playerctl next"),
- "1-2-BackSpace" => spawn_external!("playerctl stop"),
- "XF86AudioMute" => spawn_external!("amixer -D pulse sset Master toggle"),
- "XF86AudioLowerVolume" => spawn_external!("amixer -D pulse sset Master 5%-"),
- "XF86AudioRaiseVolume" => spawn_external!("amixer -D pulse sset Master 5%+"),
-
- "1-Return" => spawn_external!("st"),
- "1-S-Return" => spawn_external!(concat!("st -n ", WM_NAME!(), ":cf")),
-
- "1-p" => spawn_external!("dmenu_run"),
- "1-q" => spawn_external!("qutebrowser"),
- "1-S-q" => spawn_external!("firefox"),
- "1-C-q" => spawn_external!("chromium"),
-
- "1-C-e" => spawn_external!("st -g 140x42 -e zsh -i -c neomutt"),
- "1-C-s" => spawn_external!("st -g 80x42 -e zsh -i -c sncli"),
- "1-C-i" => spawn_external!("st -g 80x42 -e zsh -i -c irssi"),
-
- "S-XF86AudioMute" => spawn_external!("amixer -D pulse sset Capture toggle"),
- "XF86AudioMicMute" => spawn_external!("amixer -D pulse sset Capture toggle"),
-
- // external shell commands
- "1-S-p" => spawn_from_shell!("$HOME/bin/dmenupass"),
- "1-C-p" => spawn_from_shell!("$HOME/bin/dmenupass --copy"),
- "1-S-o" => spawn_from_shell!("$HOME/bin/dmenunotify"),
- "Print", "1-2-slash" => spawn_from_shell!(
- "maim -u -m 1 -s \
- $(date +$HOME/screenshots/scrots/SS_%Y-%h-%d_%H-%M-%S.png)"
- ),
- "S-Print", "1-2-S-slash" => spawn_from_shell!(
- "maim -u -m 1 \
- $(date +$HOME/screenshots/scrots/SS_%Y-%h-%d_%H-%M-%S.png)"
- ),
+ key_bindings.insert(
+ KeyInput {
+ key: Key::Escape,
+ modifiers: hashset!(Modifier::Alt, Modifier::Ctrl, Modifier::Shift),
+ },
+ |model: &mut Model<'_>| {
+ model.exit();
+ }
);
+ key_bindings.insert(
+ KeyInput {
+ key: Key::J,
+ modifiers: hashset!(Modifier::Alt),
+ },
+ |model: &mut Model<'_>| {
+ model.cycle_focus(Direction::Forward);
+ }
+ );
+
+ key_bindings.insert(
+ KeyInput {
+ key: Key::K,
+ modifiers: hashset!(Modifier::Alt),
+ },
+ |model: &mut Model<'_>| {
+ model.cycle_focus(Direction::Backward);
+ }
+ );
+
+ // // (kind, target, focus): "[modifiers]-button" => action
+ // let mouse_bindings = build_mouse_bindings!(
+ // }),
+
+ // // "[modifiers]-key" => action
+ // let key_bindings = build_key_bindings!(
+ // "1-C-S-q" => do_internal!(exit),
+
+ // // client state modifiers
+ // "1-c" => do_internal!(kill_focus),
+ // "1-S-space" => do_internal!(set_floating_focus, Toggle::Reverse),
+ // "1-f" => do_internal!(set_fullscreen_focus, Toggle::Reverse),
+ // "1-x" => do_internal!(set_stick_focus, Toggle::Reverse),
+ // "1-2-C-f" => do_internal!(set_contained_focus, Toggle::Reverse),
+ // "1-2-C-i" => do_internal!(set_invincible_focus, Toggle::Reverse),
+ // "1-2-C-p" => do_internal!(set_producing_focus, Toggle::Reverse),
+ // "1-2-C-y" => do_internal!(set_iconifyable_focus, Toggle::Reverse),
+ // "1-y" => do_internal!(set_iconify_focus, Toggle::On),
+ // "1-u" => do_internal!(pop_deiconify),
+ // "1-2-u" => do_internal_block!(model, {
+ // model.deiconify_all(model.active_workspace());
+ // }),
+
+ // // free client arrangers
+ // "1-C-space" => do_internal!(center_focus),
+ // "1-C-h" => do_internal!(nudge_focus, Edge::Left, 15),
+ // "1-C-j" => do_internal!(nudge_focus, Edge::Bottom, 15),
+ // "1-C-k" => do_internal!(nudge_focus, Edge::Top, 15),
+ // "1-C-l" => do_internal!(nudge_focus, Edge::Right, 15),
+ // "1-C-S-h" => do_internal!(stretch_focus, Edge::Left, 15),
+ // "1-C-S-j" => do_internal!(stretch_focus, Edge::Bottom, 15),
+ // "1-C-S-k" => do_internal!(stretch_focus, Edge::Top, 15),
+ // "1-C-S-l" => do_internal!(stretch_focus, Edge::Right, 15),
+ // "1-C-S-y" => do_internal!(stretch_focus, Edge::Left, -15),
+ // "1-C-S-u" => do_internal!(stretch_focus, Edge::Bottom, -15),
+ // "1-C-S-i" => do_internal!(stretch_focus, Edge::Top, -15),
+ // "1-C-S-o" => do_internal!(stretch_focus, Edge::Right, -15),
+ // "1-C-Left" => do_internal!(snap_focus, Edge::Left),
+ // "1-C-Down" => do_internal!(snap_focus, Edge::Bottom),
+ // "1-C-Up" => do_internal!(snap_focus, Edge::Top),
+ // "1-C-Right" => do_internal!(snap_focus, Edge::Right),
+
+ // // client order modifiers
+ // "1-j" => do_internal!(cycle_focus, Direction::Forward),
+ // "1-k" => do_internal!(cycle_focus, Direction::Backward),
+ // "1-S-j" => do_internal!(drag_focus, Direction::Forward),
+ // "1-S-k" => do_internal!(drag_focus, Direction::Backward),
+ // "1-S-semicolon" => do_internal!(rotate_clients, Direction::Forward),
+ // "1-S-comma" => do_internal!(rotate_clients, Direction::Backward),
+
+ // // zone creators
+ // "1-C-Return" => do_internal!(create_layout_zone),
+ // "1-C-S-Return" => do_internal!(create_tab_zone),
+ // "1-C-C" => do_internal!(delete_zone),
+
+ // // zone order modifiers
+ // // "1-C-j" => do_internal!(cycle_zones, Direction::Forward),
+ // // "1-C-k" => do_internal!(cycle_zones, Direction::Backward),
+
+ // // active workspace layout modifiers
+ // "1-S-f" => do_internal!(set_layout, LayoutKind::Float),
+ // "1-S-l" => do_internal!(set_layout, LayoutKind::BLFloat),
+ // "1-z" => do_internal!(set_layout, LayoutKind::SingleFloat),
+ // "1-S-z" => do_internal!(set_layout, LayoutKind::BLSingleFloat),
+ // "1-m" => do_internal!(set_layout, LayoutKind::Monocle),
+ // "1-g" => do_internal!(set_layout, LayoutKind::Center),
+ // "1-t" => do_internal!(set_layout, LayoutKind::Stack),
+ // "1-S-t" => do_internal!(set_layout, LayoutKind::SStack),
+ // "1-C-S-p" => do_internal!(set_layout, LayoutKind::Paper),
+ // "1-2-C-S-p" => do_internal!(set_layout, LayoutKind::SPaper),
+ // "1-C-S-b" => do_internal!(set_layout, LayoutKind::BStack),
+ // "1-2-C-S-b" => do_internal!(set_layout, LayoutKind::SBStack),
+ // "1-S-y" => do_internal!(set_layout, LayoutKind::Horz),
+ // "1-C-y" => do_internal!(set_layout, LayoutKind::SHorz),
+ // "1-S-v" => do_internal!(set_layout, LayoutKind::Vert),
+ // "1-C-v" => do_internal!(set_layout, LayoutKind::SVert),
+ // "1-C-S-f" => do_internal!(apply_float_retain_region),
+ // "1-space" => do_internal!(toggle_layout),
+
+ // // active workspace layout data modifiers
+ // "1-plus" => do_internal!(change_gap_size, Change::Inc(5u32)),
+ // "1-minus" => do_internal!(change_gap_size, Change::Dec(5u32)),
+ // "1-S-equal" => do_internal!(reset_gap_size),
+ // "1-i" => do_internal!(change_main_count, Change::Inc(1u32)),
+ // "1-d" => do_internal!(change_main_count, Change::Dec(1u32)),
+ // "1-l" => do_internal!(change_main_factor, Change::Inc(0.05f32)),
+ // "1-h" => do_internal!(change_main_factor, Change::Dec(0.05f32)),
+ // "1-S-Left" => do_internal!(change_margin, Edge::Left, Change::Inc(5i32)),
+ // "1-C-S-Left" => do_internal!(change_margin, Edge::Left, Change::Dec(5i32)),
+ // "1-S-Up" => do_internal!(change_margin, Edge::Top, Change::Inc(5i32)),
+ // "1-C-S-Up" => do_internal!(change_margin, Edge::Top, Change::Dec(5i32)),
+ // "1-S-Down" => do_internal!(change_margin, Edge::Bottom, Change::Inc(5i32)),
+ // "1-C-S-Down" => do_internal!(change_margin, Edge::Bottom, Change::Dec(5i32)),
+ // "1-S-Right" => do_internal!(change_margin, Edge::Right, Change::Inc(5i32)),
+ // "1-C-S-Right" => do_internal!(change_margin, Edge::Right, Change::Dec(5i32)),
+ // "1-C-S-equal" => do_internal!(reset_margin),
+ // "1-2-C-S-l" => do_internal!(copy_prev_layout_data),
+ // "1-2-C-S-equal" => do_internal!(reset_layout_data),
+
+ // // workspace activators
+ // "1-Escape" => do_internal!(toggle_workspace),
+ // "1-bracketleft" => do_internal!(activate_next_workspace, Direction::Backward),
+ // "1-bracketright" => do_internal!(activate_next_workspace, Direction::Forward),
+ // "1-1" => do_internal!(activate_workspace, 0),
+ // "1-2" => do_internal!(activate_workspace, 1),
+ // "1-3" => do_internal!(activate_workspace, 2),
+ // "1-4" => do_internal!(activate_workspace, 3),
+ // "1-5" => do_internal!(activate_workspace, 4),
+ // "1-6" => do_internal!(activate_workspace, 5),
+ // "1-7" => do_internal!(activate_workspace, 6),
+ // "1-8" => do_internal!(activate_workspace, 7),
+ // "1-9" => do_internal!(activate_workspace, 8),
+ // "1-0" => do_internal!(activate_workspace, 9),
+
+ // // workspace client movers
+ // "1-S-bracketleft" => do_internal!(move_focus_to_next_workspace, Direction::Backward),
+ // "1-S-bracketright" => do_internal!(move_focus_to_next_workspace, Direction::Forward),
+ // "1-S-1" => do_internal!(move_focus_to_workspace, 0),
+ // "1-S-2" => do_internal!(move_focus_to_workspace, 1),
+ // "1-S-3" => do_internal!(move_focus_to_workspace, 2),
+ // "1-S-4" => do_internal!(move_focus_to_workspace, 3),
+ // "1-S-5" => do_internal!(move_focus_to_workspace, 4),
+ // "1-S-6" => do_internal!(move_focus_to_workspace, 5),
+ // "1-S-7" => do_internal!(move_focus_to_workspace, 6),
+ // "1-S-8" => do_internal!(move_focus_to_workspace, 7),
+ // "1-S-9" => do_internal!(move_focus_to_workspace, 8),
+ // "1-S-0" => do_internal!(move_focus_to_workspace, 9),
+
+ // // placeable region modifiers
+ // "1-v" => do_internal!(toggle_screen_struts),
+
+ // // client jump criteria
+ // "1-b" => do_internal!(jump_client,
+ // JumpCriterium::ByClass(MatchMethod::Equals("qutebrowser"))
+ // ),
+ // "1-S-b" => do_internal!(jump_client,
+ // JumpCriterium::ByClass(MatchMethod::Equals("Firefox"))
+ // ),
+ // "1-C-b" => do_internal!(jump_client,
+ // JumpCriterium::ByClass(MatchMethod::Equals("Chromium"))
+ // ),
+ // "1-2-space" => do_internal!(jump_client,
+ // JumpCriterium::ByClass(MatchMethod::Equals("Spotify"))
+ // ),
+ // "1-e" => do_internal_block!(model, {
+ // model.jump_client(JumpCriterium::ByName(
+ // MatchMethod::Contains("[vim]"),
+ // ));
+ // }),
+ // "1-slash" => do_internal_block!(model, {
+ // model.jump_client(JumpCriterium::OnWorkspaceBySelector(
+ // model.active_workspace(),
+ // &ClientSelector::Last,
+ // ));
+ // }),
+ // "1-period" => do_internal_block!(model, {
+ // model.jump_client(JumpCriterium::OnWorkspaceBySelector(
+ // model.active_workspace(),
+ // &ClientSelector::AtMaster,
+ // ));
+ // }),
+ // "1-comma" => do_internal_block!(model, {
+ // model.jump_client(JumpCriterium::OnWorkspaceBySelector(
+ // model.active_workspace(),
+ // &ClientSelector::First,
+ // ));
+ // }),
+
+ // // external spawn commands
+ // "XF86AudioPlay", "1-2-p" => spawn_external!("playerctl play-pause"),
+ // "XF86AudioPrev", "1-2-k" => spawn_external!("playerctl previous"),
+ // "XF86AudioNext", "1-2-j" => spawn_external!("playerctl next"),
+ // "1-2-BackSpace" => spawn_external!("playerctl stop"),
+ // "XF86AudioMute" => spawn_external!("amixer -D pulse sset Master toggle"),
+ // "XF86AudioLowerVolume" => spawn_external!("amixer -D pulse sset Master 5%-"),
+ // "XF86AudioRaiseVolume" => spawn_external!("amixer -D pulse sset Master 5%+"),
+
+ // "1-Return" => spawn_external!("st"),
+ // "1-S-Return" => spawn_external!(concat!("st -n ", WM_NAME!(), ":cf")),
+
+ // "1-p" => spawn_external!("dmenu_run"),
+ // "1-q" => spawn_external!("qutebrowser"),
+ // "1-S-q" => spawn_external!("firefox"),
+ // "1-C-q" => spawn_external!("chromium"),
+
+ // "1-C-e" => spawn_external!("st -g 140x42 -e zsh -i -c neomutt"),
+ // "1-C-s" => spawn_external!("st -g 80x42 -e zsh -i -c sncli"),
+ // "1-C-i" => spawn_external!("st -g 80x42 -e zsh -i -c irssi"),
+
+ // "S-XF86AudioMute" => spawn_external!("amixer -D pulse sset Capture toggle"),
+ // "XF86AudioMicMute" => spawn_external!("amixer -D pulse sset Capture toggle"),
+
+ // // external shell commands
+ // "1-S-p" => spawn_from_shell!("$HOME/bin/dmenupass"),
+ // "1-C-p" => spawn_from_shell!("$HOME/bin/dmenupass --copy"),
+ // "1-S-o" => spawn_from_shell!("$HOME/bin/dmenunotify"),
+ // "Print", "1-2-slash" => spawn_from_shell!(
+ // "maim -u -m 1 -s \
+ // $(date +$HOME/screenshots/scrots/SS_%Y-%h-%d_%H-%M-%S.png)"
+ // ),
+ // "S-Print", "1-2-S-slash" => spawn_from_shell!(
+ // "maim -u -m 1 \
+ // $(date +$HOME/screenshots/scrots/SS_%Y-%h-%d_%H-%M-%S.png)"
+ // ),
+ // );
+
(mouse_bindings, key_bindings)
}
diff --git a/src/core/model.rs b/src/core/model.rs
@@ -47,13 +47,13 @@ use winsys::geometry::Edge;
use winsys::geometry::Pos;
use winsys::geometry::Region;
use winsys::hints::Hints;
-use winsys::input::EventTarget;
use winsys::input::Grip;
-use winsys::input::KeyCode;
+use winsys::input::KeyEvent;
+use winsys::input::KeyInput;
use winsys::input::MouseEvent;
-use winsys::input::MouseEventKey;
use winsys::input::MouseEventKind;
-use winsys::input::MouseShortcut;
+use winsys::input::MouseInput;
+use winsys::input::MouseInputTarget;
use winsys::screen::Screen;
use winsys::window::IcccmWindowState;
use winsys::window::Window;
@@ -163,11 +163,11 @@ impl<'model> Model<'model> {
.init_wm_properties(WM_NAME!(), &defaults::WORKSPACE_NAMES);
model.conn.grab_bindings(
- &key_bindings.keys().into_iter().collect::<Vec<&KeyCode>>(),
+ &key_bindings.keys().into_iter().collect::<Vec<&KeyInput>>(),
&mouse_bindings
.keys()
.into_iter()
- .collect::<Vec<&(MouseEventKey, MouseShortcut)>>(),
+ .collect::<Vec<&MouseInput>>(),
);
model
@@ -2512,6 +2512,10 @@ impl<'model> Model<'model> {
&self,
pos: &Pos,
) {
+ if !self.move_buffer.is_occupied() {
+ return;
+ }
+
let client = self
.move_buffer
.window()
@@ -2574,6 +2578,10 @@ impl<'model> Model<'model> {
&self,
pos: &Pos,
) {
+ if !self.resize_buffer.is_occupied() {
+ return;
+ }
+
let client = self
.resize_buffer
.window()
@@ -2650,10 +2658,11 @@ impl<'model> Model<'model> {
match event {
Event::Mouse {
event,
- } => self.handle_mouse(event, &mut mouse_bindings),
+ on_root,
+ } => self.handle_mouse(event, on_root, &mut mouse_bindings),
Event::Key {
- key_code,
- } => self.handle_key(key_code, &mut key_bindings),
+ event,
+ } => self.handle_key(event, &mut key_bindings),
Event::MapRequest {
window,
ignore,
@@ -2745,27 +2754,22 @@ impl<'model> Model<'model> {
fn handle_mouse(
&mut self,
event: MouseEvent,
+ on_root: bool,
mouse_bindings: &mut MouseBindings,
) {
- let mut window = event.window;
- let subwindow = event.subwindow;
+ let mut input = event.input;
+ let window = event.window;
match event.kind {
MouseEventKind::Release => {
- if self.move_buffer.is_occupied() {
- self.stop_moving();
- return;
- } else if self.resize_buffer.is_occupied() {
- self.stop_resizing();
- return;
- }
+ self.stop_moving();
+ self.stop_resizing();
+
+ return;
},
MouseEventKind::Motion => {
- if self.move_buffer.is_occupied() {
- self.handle_move(&event.root_rpos);
- } else if self.resize_buffer.is_occupied() {
- self.handle_resize(&event.root_rpos);
- }
+ self.handle_move(&event.root_rpos);
+ self.handle_resize(&event.root_rpos);
return;
},
@@ -2774,22 +2778,15 @@ impl<'model> Model<'model> {
{
// handle global mouse bindings
- let binding = mouse_bindings.get_mut(&(
- MouseEventKey {
- kind: event.kind,
- target: EventTarget::Global,
- },
- event.shortcut.clone(),
- ));
+ input.target = MouseInputTarget::Global;
+ let binding = mouse_bindings.get_mut(&input);
- if let Some((action, moves_focus)) = binding {
- action(self, None);
-
- if *moves_focus {
+ if let Some(action) = binding {
+ if action(self, None) {
// TODO: config.focus_follows_mouse
if let Some(focus) = self.focus.get() {
- if window != focus {
- self.focus_window(window);
+ if window.is_some() && window != Some(focus) {
+ self.focus_window(window.unwrap());
}
}
}
@@ -2798,55 +2795,39 @@ impl<'model> Model<'model> {
}
}
- if event.on_root {
- if let Some(subwindow) = subwindow {
- window = subwindow;
- } else {
- // handle root-targeted mouse bindings
- let binding = mouse_bindings.get_mut(&(
- MouseEventKey {
- kind: event.kind,
- target: EventTarget::Root,
- },
- event.shortcut,
- ));
-
- if let Some((action, _)) = binding {
- action(self, None);
- }
+ if on_root {
+ // handle root-targeted mouse bindings
+ input.target = MouseInputTarget::Root;
+ let binding = mouse_bindings.get_mut(&input);
+ if let Some(action) = binding {
+ action(self, None);
return;
}
}
{
// handle client-targeted mouse bindings
- let binding = mouse_bindings.get_mut(&(
- MouseEventKey {
- kind: event.kind,
- target: EventTarget::Client,
- },
- event.shortcut.clone(),
- ));
-
- if let Some(window) = self.window(window) {
- if let Some((action, moves_focus)) = binding {
- action(self, Some(window));
-
- if *moves_focus {
- // TODO: config.focus_follows_mouse
- if let Some(focus) = self.focus.get() {
- if window != focus {
- self.focus_window(window);
+ input.target = MouseInputTarget::Client;
+ let binding = mouse_bindings.get_mut(&input);
+
+ if let Some(window) = event.window {
+ if let Some(window) = self.window(window) {
+ if let Some(action) = binding {
+ if action(self, Some(window)) {
+ // TODO: config.focus_follows_mouse
+ if let Some(focus) = self.focus.get() {
+ if window != focus {
+ self.focus_window(window);
+ }
}
}
- }
- } else {
- // TODO: config.focus_follows_mouse
- if event.kind != MouseEventKind::Release {
- if let Some(focus) = self.focus.get() {
- if window != focus {
- self.focus_window(window);
+ } else {
+ if event.kind != MouseEventKind::Release {
+ if let Some(focus) = self.focus.get() {
+ if window != focus {
+ self.focus_window(window);
+ }
}
}
}
@@ -2858,11 +2839,11 @@ impl<'model> Model<'model> {
#[inline(always)]
fn handle_key(
&mut self,
- key_code: KeyCode,
+ event: KeyEvent,
key_bindings: &mut KeyBindings,
) {
- if let Some(action) = key_bindings.get_mut(&key_code.clone()) {
- debug!("processing key binding: {:?}", key_code);
+ if let Some(action) = key_bindings.get_mut(&event.input) {
+ debug!("processing key binding: {:?}", event.input);
action(self);
}
}
diff --git a/src/core/util.rs b/src/core/util.rs
@@ -3,10 +3,7 @@ use crate::change::Direction;
use crate::identify::Index;
use winsys::input::Button;
-use winsys::input::CodeMap;
-use winsys::input::KeyCode;
use winsys::input::Modifier;
-use winsys::input::MouseShortcut;
use std::cmp::Ord;
use std::hash::BuildHasher;
@@ -156,111 +153,111 @@ impl Util {
.ok();
}
- pub fn system_keycodes() -> CodeMap {
- match Command::new("xmodmap").arg("-pke").output() {
- Err(e) => panic!("unable to fetch keycodes via xmodmap: {}", e),
- Ok(o) => match String::from_utf8(o.stdout) {
- Err(e) => panic!("invalid utf8 from xmodmap: {}", e),
- Ok(s) => s
- .lines()
- .flat_map(|l| {
- let mut words = l.split_whitespace();
- let key_code: u8 = words.nth(1).unwrap().parse().unwrap();
+ // pub fn system_keycodes() -> CodeMap {
+ // match Command::new("xmodmap").arg("-pke").output() {
+ // Err(e) => panic!("unable to fetch keycodes via xmodmap: {}", e),
+ // Ok(o) => match String::from_utf8(o.stdout) {
+ // Err(e) => panic!("invalid utf8 from xmodmap: {}", e),
+ // Ok(s) => s
+ // .lines()
+ // .flat_map(|l| {
+ // let mut words = l.split_whitespace();
+ // let key_code: u8 = words.nth(1).unwrap().parse().unwrap();
- words.skip(1).map(move |name| (name.into(), key_code))
- })
- .collect::<CodeMap>(),
- },
- }
- }
+ // words.skip(1).map(move |name| (name.into(), key_code))
+ // })
+ // .collect::<CodeMap>(),
+ // },
+ // }
+ // }
- pub fn parse_key_binding(
- key_binding: impl Into<String>,
- keycodes: &CodeMap,
- ) -> Option<KeyCode> {
- let s = key_binding.into();
- let mut constituents: Vec<&str> = s.split('-').collect();
+ // pub fn parse_key_binding(
+ // key_binding: impl Into<String>,
+ // keycodes: &CodeMap,
+ // ) -> Option<KeyCode> {
+ // let s = key_binding.into();
+ // let mut constituents: Vec<&str> = s.split('-').collect();
- match keycodes.get(constituents.remove(constituents.len() - 1)) {
- Some(&code) => {
- let mask = constituents
- .iter()
- .map(|&modifier| match modifier {
- "A" | "Alt" | "Meta" => u16::from(ModMask::M1),
- "M" | "Super" => u16::from(ModMask::M4),
- "S" | "Shift" => u16::from(ModMask::SHIFT),
- "C" | "Ctrl" | "Control" => u16::from(ModMask::CONTROL),
- "1" | "Mod" => u16::from(if cfg!(debug_assertions) {
- ModMask::M1
- } else {
- ModMask::M4
- }),
- "2" | "Sec" => u16::from(if cfg!(debug_assertions) {
- ModMask::M4
- } else {
- ModMask::M1
- }),
- _ => panic!("invalid modifier: {}", s),
- })
- .fold(0, |acc, modifier| acc | modifier);
+ // match keycodes.get(constituents.remove(constituents.len() - 1)) {
+ // Some(&code) => {
+ // let mask = constituents
+ // .iter()
+ // .map(|&modifier| match modifier {
+ // "A" | "Alt" | "Meta" => u16::from(ModMask::M1),
+ // "M" | "Super" => u16::from(ModMask::M4),
+ // "S" | "Shift" => u16::from(ModMask::SHIFT),
+ // "C" | "Ctrl" | "Control" => u16::from(ModMask::CONTROL),
+ // "1" | "Mod" => u16::from(if cfg!(debug_assertions) {
+ // ModMask::M1
+ // } else {
+ // ModMask::M4
+ // }),
+ // "2" | "Sec" => u16::from(if cfg!(debug_assertions) {
+ // ModMask::M4
+ // } else {
+ // ModMask::M1
+ // }),
+ // _ => panic!("invalid modifier: {}", s),
+ // })
+ // .fold(0, |acc, modifier| acc | modifier);
- Some(KeyCode {
- mask,
- code,
- })
- },
- None => None,
- }
- }
+ // Some(KeyCode {
+ // mask,
+ // code,
+ // })
+ // },
+ // None => None,
+ // }
+ // }
- pub fn parse_mouse_binding(mouse_binding: impl Into<String>) -> Option<MouseShortcut> {
- let s = mouse_binding.into();
- let mut constituents: Vec<&str> = s.split('-').collect();
+ // pub fn parse_mouse_binding(mouse_binding: impl Into<String>) -> Option<MouseShortcut> {
+ // let s = mouse_binding.into();
+ // let mut constituents: Vec<&str> = s.split('-').collect();
- let button = match constituents.remove(constituents.len() - 1) {
- "1" | "Left" => Button::Left,
- "2" | "Middle" => Button::Middle,
- "3" | "Right" => Button::Right,
- "4" | "ScrollUp" => Button::ScrollUp,
- "5" | "ScrollDown" => Button::ScrollDown,
- "8" | "Backward" => Button::Backward,
- "9" | "Forward" => Button::Forward,
- s => panic!("invalid button: {}", s),
- };
+ // let button = match constituents.remove(constituents.len() - 1) {
+ // "1" | "Left" => Button::Left,
+ // "2" | "Middle" => Button::Middle,
+ // "3" | "Right" => Button::Right,
+ // "4" | "ScrollUp" => Button::ScrollUp,
+ // "5" | "ScrollDown" => Button::ScrollDown,
+ // "8" | "Backward" => Button::Backward,
+ // "9" | "Forward" => Button::Forward,
+ // s => panic!("invalid button: {}", s),
+ // };
- let mut modifiers = constituents
- .iter()
- .map(|&modifier| match modifier {
- "A" | "Alt" | "Meta" => Modifier::Alt,
- "AGr" | "AltGr" => Modifier::AltGr,
- "M" | "Super" => Modifier::Super,
- "S" | "Shift" => Modifier::Shift,
- "C" | "Ctrl" | "Control" => Modifier::Ctrl,
- "N" | "NumLock" => Modifier::NumLock,
- "L" | "ScrollLock" => Modifier::ScrollLock,
- "1" | "Mod" => {
- if cfg!(debug_assertions) {
- Modifier::Alt
- } else {
- Modifier::Super
- }
- },
- "2" | "Sec" => {
- if cfg!(debug_assertions) {
- Modifier::Super
- } else {
- Modifier::Alt
- }
- },
- _ => panic!("invalid modifier: {}", s),
- })
- .collect::<Vec<Modifier>>();
+ // let mut modifiers = constituents
+ // .iter()
+ // .map(|&modifier| match modifier {
+ // "A" | "Alt" | "Meta" => Modifier::Alt,
+ // "AGr" | "AltGr" => Modifier::AltGr,
+ // "M" | "Super" => Modifier::Super,
+ // "S" | "Shift" => Modifier::Shift,
+ // "C" | "Ctrl" | "Control" => Modifier::Ctrl,
+ // "N" | "NumLock" => Modifier::NumLock,
+ // "L" | "ScrollLock" => Modifier::ScrollLock,
+ // "1" | "Mod" => {
+ // if cfg!(debug_assertions) {
+ // Modifier::Alt
+ // } else {
+ // Modifier::Super
+ // }
+ // },
+ // "2" | "Sec" => {
+ // if cfg!(debug_assertions) {
+ // Modifier::Super
+ // } else {
+ // Modifier::Alt
+ // }
+ // },
+ // _ => panic!("invalid modifier: {}", s),
+ // })
+ // .collect::<Vec<Modifier>>();
- modifiers.sort();
+ // modifiers.sort();
- Some(MouseShortcut {
- button,
- modifiers,
- })
- }
+ // Some(MouseShortcut {
+ // button,
+ // modifiers,
+ // })
+ // }
}
diff --git a/src/winsys/connection.rs b/src/winsys/connection.rs
@@ -6,7 +6,8 @@ use crate::geometry::Region;
use crate::geometry::Strut;
use crate::hints::Hints;
use crate::hints::SizeHints;
-use crate::input::*;
+use crate::input::KeyInput;
+use crate::input::MouseInput;
use crate::screen::Screen;
use crate::window::IcccmWindowState;
use crate::window::Window;
@@ -135,8 +136,8 @@ pub trait Connection {
);
fn grab_bindings(
&self,
- key_codes: &[&KeyCode],
- mouse_bindings: &[&(MouseEventKey, MouseShortcut)],
+ key_codes: &[&KeyInput],
+ mouse_bindings: &[&MouseInput],
);
fn regrab_buttons(
&self,
diff --git a/src/winsys/event.rs b/src/winsys/event.rs
@@ -4,7 +4,7 @@ use crate::geometry::Dim;
use crate::geometry::Pos;
use crate::geometry::Region;
use crate::input::Grip;
-use crate::input::KeyCode;
+use crate::input::KeyEvent;
use crate::input::MouseEvent;
use crate::screen::Screen;
use crate::window::Window;
@@ -15,9 +15,10 @@ use crate::window::WindowType;
pub enum Event {
Mouse {
event: MouseEvent,
+ on_root: bool,
},
Key {
- key_code: KeyCode,
+ event: KeyEvent,
},
MapRequest {
window: Window,
diff --git a/src/winsys/geometry.rs b/src/winsys/geometry.rs
@@ -24,7 +24,7 @@ pub enum Corner {
BottomRight,
}
-#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq)]
+#[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)]
pub struct Pos {
pub x: i32,
pub y: i32,
diff --git a/src/winsys/input.rs b/src/winsys/input.rs
@@ -6,9 +6,13 @@ use crate::geometry::Pos;
use crate::window::Window;
use std::collections::HashMap;
+use std::collections::HashSet;
use std::convert::TryFrom;
+use std::hash::Hash;
+use std::hash::Hasher;
use std::vec::Vec;
+use anyhow::anyhow;
use strum::EnumIter;
use strum::IntoEnumIterator;
@@ -32,12 +36,33 @@ impl Grip {
}
}
-pub type CodeMap = HashMap<String, u8>;
+#[repr(u8)]
+#[derive(Debug, PartialEq, EnumIter, Eq, Hash, Clone, Copy, PartialOrd, Ord)]
+pub enum Modifier {
+ Ctrl = 1 << 0,
+ Shift = 1 << 1,
+ Alt = 1 << 2,
+ AltGr = 1 << 3,
+ Super = 1 << 4,
+ NumLock = 1 << 5,
+ ScrollLock = 1 << 6,
+}
-#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
-pub struct KeyCode {
- pub mask: u16,
- pub code: u8,
+impl TryFrom<&str> for Modifier {
+ type Error = anyhow::Error;
+
+ fn try_from(val: &str) -> Result<Self> {
+ match val {
+ "C" => Ok(Self::Ctrl),
+ "A" => Ok(Self::Alt),
+ "S" => Ok(Self::Shift),
+ "M" => Ok(Self::Super),
+ "AltGr" => Ok(Self::Alt),
+ "Num" => Ok(Self::NumLock),
+ "Scroll" => Ok(Self::ScrollLock),
+ _ => Err(anyhow!("unable to resolve \"{}\" to modifier", val)),
+ }
+ }
}
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
@@ -51,36 +76,6 @@ pub enum Button {
Forward,
}
-#[derive(Debug, PartialEq, EnumIter, Eq, Hash, Clone, Copy, PartialOrd, Ord)]
-pub enum Modifier {
- Ctrl,
- Shift,
- Alt,
- AltGr,
- Super,
- NumLock,
- ScrollLock,
-}
-
-#[derive(Debug, PartialEq, Eq, Hash, Clone)]
-pub struct MouseShortcut {
- pub button: Button,
- pub modifiers: Vec<Modifier>,
-}
-
-impl MouseShortcut {
- pub fn new(
- button: Button,
- mut modifiers: Vec<Modifier>,
- ) -> Self {
- modifiers.sort();
- Self {
- button,
- modifiers,
- }
- }
-}
-
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
pub enum MouseEventKind {
Press,
@@ -89,55 +84,244 @@ pub enum MouseEventKind {
}
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
-pub enum EventTarget {
+pub enum MouseInputTarget {
Global,
Root,
Client,
}
-#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
-pub struct MouseEventKey {
- pub kind: MouseEventKind,
- pub target: EventTarget,
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct MouseInput {
+ pub target: MouseInputTarget,
+ pub button: Button,
+ pub modifiers: HashSet<Modifier>,
}
-#[derive(Debug, Clone)]
+impl Hash for MouseInput {
+ fn hash<H: Hasher>(
+ &self,
+ state: &mut H,
+ ) {
+ self.button.hash(state);
+ self.modifiers
+ .iter()
+ .fold(0u8, |acc, &m| acc | m as u8)
+ .hash(state);
+ }
+}
+
+#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct MouseEvent {
pub kind: MouseEventKind,
- pub window: Window,
- pub subwindow: Option<Window>,
- pub on_root: bool,
+ pub input: MouseInput,
+ pub window: Option<Window>,
pub root_rpos: Pos,
- pub window_rpos: Pos,
- pub shortcut: MouseShortcut,
}
-impl MouseEvent {
- pub fn new(
- kind: MouseEventKind,
- window: Window,
- subwindow: Option<Window>,
- root: Window,
- root_rx: i16,
- root_ry: i16,
- window_rx: i16,
- window_ry: i16,
- shortcut: MouseShortcut,
- ) -> Self {
- Self {
- kind,
- window,
- subwindow,
- on_root: window == root,
- root_rpos: Pos {
- x: root_rx as i32,
- y: root_ry as i32,
- },
- window_rpos: Pos {
- x: window_rx as i32,
- y: window_ry as i32,
- },
- shortcut,
- }
+#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
+pub enum Key {
+ Any,
+ Backspace,
+ Tab,
+ Clear,
+ Return,
+ Shift,
+ Control,
+ Alt,
+ Super,
+ Menu,
+ Pause,
+ CapsLock,
+ Escape,
+ Space,
+ ExclamationMark,
+ QuotationMark,
+ QuestionMark,
+ NumberSign,
+ DollarSign,
+ PercentSign,
+ AtSign,
+ Ampersand,
+ Apostrophe,
+ LeftParenthesis,
+ RightParenthesis,
+ LeftBracket,
+ RightBracket,
+ LeftBrace,
+ RightBrace,
+ Underscore,
+ Grave,
+ Bar,
+ Tilde,
+ QuoteLeft,
+ Asterisk,
+ Plus,
+ Comma,
+ Minus,
+ Period,
+ Slash,
+ BackSlash,
+ Colon,
+ SemiColon,
+ Less,
+ Equal,
+ Greater,
+ PageUp,
+ PageDown,
+ End,
+ Home,
+ Left,
+ Up,
+ Right,
+ Down,
+ Select,
+ Print,
+ Execute,
+ PrintScreen,
+ Insert,
+ Delete,
+ Help,
+ Zero,
+ One,
+ Two,
+ Three,
+ Four,
+ Five,
+ Six,
+ Seven,
+ Eight,
+ Nine,
+ A,
+ B,
+ C,
+ D,
+ E,
+ F,
+ G,
+ H,
+ I,
+ J,
+ K,
+ L,
+ M,
+ N,
+ O,
+ P,
+ Q,
+ R,
+ S,
+ T,
+ U,
+ V,
+ W,
+ X,
+ Y,
+ Z,
+ NumPad0,
+ NumPad1,
+ NumPad2,
+ NumPad3,
+ NumPad4,
+ NumPad5,
+ NumPad6,
+ NumPad7,
+ NumPad8,
+ NumPad9,
+ Multiply,
+ Add,
+ Seperator,
+ Subtract,
+ Decimal,
+ Divide,
+ F1,
+ F2,
+ F3,
+ F4,
+ F5,
+ F6,
+ F7,
+ F8,
+ F9,
+ F10,
+ F11,
+ F12,
+ F13,
+ F14,
+ F15,
+ F16,
+ F17,
+ F18,
+ F19,
+ F20,
+ F21,
+ F22,
+ F23,
+ F24,
+ Numlock,
+ ScrollLock,
+ LeftShift,
+ RightShift,
+ LeftControl,
+ RightContol,
+ LeftAlt,
+ RightAlt,
+ LeftSuper,
+ RightSuper,
+ BrowserBack,
+ BrowserForward,
+ BrowserRefresh,
+ BrowserStop,
+ BrowserSearch,
+ BrowserFavorites,
+ BrowserHome,
+ VolumeMute,
+ VolumeDown,
+ VolumeUp,
+ NextTrack,
+ PreviousTrack,
+ StopMedia,
+ PlayPause,
+ LaunchMail,
+ SelectMedia,
+ LaunchAppA,
+ LaunchAppB,
+ LaunchAppC,
+ LaunchAppD,
+ LaunchAppE,
+ LaunchAppF,
+ LaunchApp0,
+ LaunchApp1,
+ LaunchApp2,
+ LaunchApp3,
+ LaunchApp4,
+ LaunchApp5,
+ LaunchApp6,
+ LaunchApp7,
+ LaunchApp8,
+ LaunchApp9,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct KeyInput {
+ pub key: Key,
+ pub modifiers: HashSet<Modifier>,
+}
+
+impl Hash for KeyInput {
+ fn hash<H: Hasher>(
+ &self,
+ state: &mut H,
+ ) {
+ self.key.hash(state);
+ self.modifiers
+ .iter()
+ .fold(0u8, |acc, &m| acc | m as u8)
+ .hash(state);
}
}
+
+#[derive(Debug, Clone, Hash, PartialEq, Eq)]
+pub struct KeyEvent {
+ pub input: KeyInput,
+ pub window: Option<Window>,
+}
diff --git a/src/winsys/xdata/event.rs b/src/winsys/xdata/event.rs
@@ -3,7 +3,6 @@ pub use super::super::event::*;
use crate::geometry::Pos;
use crate::geometry::Region;
-use crate::input::KeyCode;
use crate::screen::Screen;
use crate::window::Window;
use crate::window::WindowState;
diff --git a/src/winsys/xdata/input.rs b/src/winsys/xdata/input.rs
@@ -18,21 +18,33 @@ use x11rb::protocol::xproto::KeyPressEvent;
use x11rb::protocol::xproto::ModMask;
use x11rb::protocol::xproto::MotionNotifyEvent;
-impl KeyCode {
- pub fn from_press_event(event: &KeyPressEvent) -> Self {
- Self {
- mask: event.state,
- code: event.detail,
- }
+impl From<Modifier> for u16 {
+ fn from(modifier: Modifier) -> u16 {
+ u16::from(match modifier {
+ Modifier::Ctrl => ModMask::CONTROL,
+ Modifier::Shift => ModMask::SHIFT,
+ Modifier::Alt => ModMask::M1,
+ Modifier::Super => ModMask::M4,
+ Modifier::AltGr => ModMask::M3,
+ Modifier::NumLock => ModMask::M2,
+ Modifier::ScrollLock => ModMask::M5,
+ })
}
+}
+
+impl TryFrom<ModMask> for Modifier {
+ type Error = anyhow::Error;
- pub fn without_mask(
- &self,
- mask: ModMask,
- ) -> Self {
- Self {
- mask: self.mask & !(u16::from(mask)),
- code: self.code,
+ fn try_from(val: ModMask) -> Result<Self> {
+ match val {
+ ModMask::CONTROL => Ok(Modifier::Ctrl),
+ ModMask::SHIFT => Ok(Modifier::Shift),
+ ModMask::M1 => Ok(Modifier::Alt),
+ ModMask::M4 => Ok(Modifier::Super),
+ ModMask::M3 => Ok(Modifier::AltGr),
+ ModMask::M2 => Ok(Modifier::NumLock),
+ ModMask::M5 => Ok(Modifier::ScrollLock),
+ _ => Err(anyhow!("no matching modifier for value {}", u16::from(val))),
}
}
}
@@ -67,134 +79,3 @@ impl TryFrom<u8> for Button {
}
}
}
-
-impl Modifier {
- pub fn was_held(
- &self,
- mask: u16,
- ) -> bool {
- mask & u16::from(*self) > 0
- }
-}
-
-impl From<Modifier> for u16 {
- fn from(modifier: Modifier) -> u16 {
- u16::from(match modifier {
- Modifier::Ctrl => ModMask::CONTROL,
- Modifier::Shift => ModMask::SHIFT,
- Modifier::Alt => ModMask::M1,
- Modifier::Super => ModMask::M4,
- Modifier::AltGr => ModMask::M3,
- Modifier::NumLock => ModMask::M2,
- Modifier::ScrollLock => ModMask::M5,
- })
- }
-}
-
-impl TryFrom<&str> for Modifier {
- type Error = anyhow::Error;
-
- fn try_from(val: &str) -> Result<Self> {
- match val {
- "C" => Ok(Self::Ctrl),
- "A" => Ok(Self::Alt),
- "S" => Ok(Self::Shift),
- "M" => Ok(Self::Super),
- "AltGr" => Ok(Self::Alt),
- "Num" => Ok(Self::NumLock),
- "Scroll" => Ok(Self::ScrollLock),
- _ => Err(anyhow!("unable to resolve \"{}\" to modifier", val)),
- }
- }
-}
-
-impl MouseShortcut {
- pub fn from_event(
- detail: u8,
- state: u16,
- ) -> Result<Self> {
- Ok(Self {
- button: Button::try_from(detail)?,
- modifiers: Modifier::iter()
- .filter(|&m| {
- m.was_held(state) && m != Modifier::NumLock && m != Modifier::ScrollLock
- })
- .collect(),
- })
- }
-
- pub fn mask(&self) -> u16 {
- self.modifiers
- .iter()
- .fold(0, |acc, &val| acc | u16::from(val))
- }
-
- pub fn button(&self) -> u8 {
- self.button.into()
- }
-}
-
-impl MouseEvent {
- pub fn from_press_event(
- event: &ButtonPressEvent,
- root: Window,
- ) -> Result<Self> {
- Ok(Self::new(
- MouseEventKind::Press,
- event.event,
- if event.child != x11rb::NONE {
- Some(event.child)
- } else {
- None
- },
- root,
- event.root_x,
- event.root_y,
- event.event_x,
- event.event_y,
- MouseShortcut::from_event(event.detail, event.state)?,
- ))
- }
-
- pub fn from_release_event(
- event: &ButtonReleaseEvent,
- root: Window,
- ) -> Result<Self> {
- Ok(Self::new(
- MouseEventKind::Release,
- event.event,
- if event.child != x11rb::NONE {
- Some(event.child)
- } else {
- None
- },
- root,
- event.root_x,
- event.root_y,
- event.event_x,
- event.event_y,
- MouseShortcut::from_event(event.detail, event.state)?,
- ))
- }
-
- pub fn from_motion_event(
- event: &MotionNotifyEvent,
- root: Window,
- ) -> Result<Self> {
- Ok(Self::new(
- MouseEventKind::Motion,
- event.event,
- if event.child != x11rb::NONE {
- Some(event.child)
- } else {
- None
- },
- root,
- event.root_x,
- event.root_y,
- event.event_x,
- event.event_y,
- MouseShortcut::from_event(1, event.state)?,
- ))
- }
-}
diff --git a/src/winsys/xdata/xconnection.rs b/src/winsys/xdata/xconnection.rs
@@ -15,11 +15,15 @@ use crate::geometry::Strut;
use crate::hints::Hints;
use crate::hints::SizeHints;
use crate::input::Button;
+use crate::input::Modifier;
use crate::input::Grip;
-use crate::input::KeyCode;
+use crate::input::Key;
+use crate::input::KeyEvent;
+use crate::input::MouseEventKind;
+use crate::input::MouseInputTarget;
+use crate::input::KeyInput;
use crate::input::MouseEvent;
-use crate::input::MouseEventKey;
-use crate::input::MouseShortcut;
+use crate::input::MouseInput;
use crate::screen::Screen;
use crate::window::IcccmWindowState;
use crate::window::Window;
@@ -28,7 +32,9 @@ use crate::window::WindowType;
use crate::Result;
use std::cell::Cell;
+use std::cell::RefCell;
use std::collections::HashMap;
+use std::collections::HashSet;
use std::convert::TryFrom;
use std::str::FromStr;
@@ -177,7 +183,8 @@ pub struct XConnection<'conn, Conn: connection::Connection> {
background_gc: xproto::Gcontext,
database: Option<Database>,
confined_to: Cell<Option<Window>>,
-
+ keys: RefCell<HashMap<u8, Key>>,
+ keycodes: RefCell<HashMap<Key, u8>>,
root_event_mask: EventMask,
window_event_mask: EventMask,
frame_event_mask: EventMask,
@@ -285,6 +292,9 @@ impl<'conn, Conn: connection::Connection> XConnection<'conn, Conn> {
);
}
+ let keys = RefCell::new(HashMap::new());
+ let keycodes = RefCell::new(HashMap::new());
+
let root_event_mask: EventMask = EventMask::PROPERTY_CHANGE
| EventMask::SUBSTRUCTURE_REDIRECT
| EventMask::STRUCTURE_NOTIFY
@@ -317,7 +327,8 @@ impl<'conn, Conn: connection::Connection> XConnection<'conn, Conn> {
background_gc,
database,
confined_to: Cell::new(None),
-
+ keys,
+ keycodes,
root_event_mask,
window_event_mask,
frame_event_mask,
@@ -493,6 +504,331 @@ impl<'conn, Conn: connection::Connection> XConnection<'conn, Conn> {
}
}
+ fn get_key(
+ &self,
+ keycode: u8,
+ ) -> Key {
+ if let Some(&key) = self.keys.borrow().get(&keycode) {
+ return key;
+ }
+
+ let key = match keycode {
+ 9 => Key::Escape,
+ 10 => Key::One,
+ 11 => Key::Two,
+ 12 => Key::Three,
+ 13 => Key::Four,
+ 14 => Key::Five,
+ 15 => Key::Six,
+ 16 => Key::Seven,
+ 17 => Key::Eight,
+ 18 => Key::Nine,
+ 19 => Key::Zero,
+ 20 => Key::Minus,
+ 21 => Key::Equal,
+ 22 => Key::Backspace,
+ 23 => Key::Tab,
+ 24 => Key::Q,
+ 25 => Key::W,
+ 26 => Key::E,
+ 27 => Key::R,
+ 28 => Key::T,
+ 29 => Key::Y,
+ 30 => Key::U,
+ 31 => Key::I,
+ 32 => Key::O,
+ 33 => Key::P,
+ 34 => Key::LeftBracket,
+ 35 => Key::RightBracket,
+ 36 => Key::Return,
+ 37 => Key::Control,
+ 38 => Key::A,
+ 39 => Key::S,
+ 40 => Key::D,
+ 41 => Key::F,
+ 42 => Key::G,
+ 43 => Key::H,
+ 44 => Key::J,
+ 45 => Key::K,
+ 46 => Key::L,
+ 47 => Key::SemiColon,
+ 48 => Key::Apostrophe,
+ 49 => Key::Tilde,
+ 50 => Key::Shift,
+ 51 => Key::BackSlash,
+ 52 => Key::Z,
+ 53 => Key::X,
+ 54 => Key::C,
+ 55 => Key::V,
+ 56 => Key::B,
+ 57 => Key::N,
+ 58 => Key::M,
+ 59 => Key::Comma,
+ 60 => Key::Period,
+ 61 => Key::Slash,
+ 62 => Key::RightShift,
+ 63 => Key::Multiply,
+ 64 => Key::Alt,
+ 65 => Key::Space,
+ 66 => Key::CapsLock,
+ 67 => Key::F1,
+ 68 => Key::F2,
+ 69 => Key::F3,
+ 70 => Key::F4,
+ 71 => Key::F5,
+ 72 => Key::F6,
+ 73 => Key::F7,
+ 74 => Key::F8,
+ 75 => Key::F9,
+ 76 => Key::F10,
+ 77 => Key::Numlock,
+ 78 => Key::ScrollLock,
+ 79 => Key::NumPad7,
+ 80 => Key::NumPad8,
+ 81 => Key::NumPad9,
+ 82 => Key::Subtract,
+ 83 => Key::NumPad4,
+ 84 => Key::NumPad5,
+ 85 => Key::NumPad6,
+ 86 => Key::Add,
+ 87 => Key::NumPad1,
+ 88 => Key::NumPad2,
+ 89 => Key::NumPad3,
+ 90 => Key::NumPad0,
+ 94 => Key::Less,
+ 95 => Key::F11,
+ 96 => Key::F12,
+ 105 => Key::RightContol,
+ 106 => Key::Divide,
+ 107 => Key::PrintScreen,
+ 108 => Key::RightAlt,
+ 110 => Key::Home,
+ 111 => Key::Up,
+ 112 => Key::PageUp,
+ 113 => Key::Left,
+ 114 => Key::Right,
+ 115 => Key::End,
+ 116 => Key::Down,
+ 117 => Key::PageDown,
+ 118 => Key::Insert,
+ 119 => Key::Delete,
+ 121 => Key::VolumeMute,
+ 122 => Key::VolumeDown,
+ 123 => Key::VolumeUp,
+ 127 => Key::Pause,
+ 128 => Key::LaunchAppA,
+ 129 => Key::Decimal,
+ 133 => Key::Super,
+ 134 => Key::RightSuper,
+ 135 => Key::Menu,
+ 146 => Key::Help,
+ 156 => Key::LaunchApp1,
+ 157 => Key::LaunchApp2,
+ 163 => Key::LaunchMail,
+ 164 => Key::BrowserFavorites,
+ 166 => Key::BrowserBack,
+ 167 => Key::BrowserForward,
+ 171 => Key::NextTrack,
+ 172 => Key::PlayPause,
+ 173 => Key::PreviousTrack,
+ 174 => Key::StopMedia,
+ 180 => Key::BrowserHome,
+ 182 => Key::BrowserStop,
+ 187 => Key::LeftParenthesis,
+ 188 => Key::RightParenthesis,
+ 192 => Key::LaunchApp5,
+ 193 => Key::LaunchApp6,
+ 194 => Key::LaunchApp7,
+ 195 => Key::LaunchApp8,
+ 196 => Key::LaunchApp9,
+ 210 => Key::LaunchApp3,
+ 211 => Key::LaunchApp4,
+ 212 => Key::LaunchAppB,
+ 225 => Key::BrowserSearch,
+ 234 => Key::SelectMedia,
+ _ => return Key::Any,
+ };
+
+ self.keys.borrow_mut().insert(keycode, key);
+ self.keycodes.borrow_mut().insert(key, keycode);
+
+ key
+ }
+
+ fn get_keycode(
+ &self,
+ key: Key,
+ ) -> u8 {
+ if let Some(&keycode) = self.keycodes.borrow().get(&key) {
+ return keycode;
+ }
+
+ let keycode = match key {
+ Key::Backspace => 22,
+ Key::Tab => 23,
+ Key::Return => 36,
+ Key::Shift => 50,
+ Key::Control => 37,
+ Key::Alt => 64,
+ Key::Super => 133,
+ Key::Menu => 135,
+ Key::Pause => 127,
+ Key::CapsLock => 66,
+ Key::Escape => 9,
+ Key::Space => 65,
+ Key::ExclamationMark => 10,
+ Key::QuotationMark => 48,
+ Key::QuestionMark => 61,
+ Key::NumberSign => 12,
+ Key::DollarSign => 13,
+ Key::PercentSign => 14,
+ Key::AtSign => 11,
+ Key::Ampersand => 16,
+ Key::Apostrophe => 48,
+ Key::LeftParenthesis => 187,
+ Key::RightParenthesis => 188,
+ Key::LeftBracket => 34,
+ Key::RightBracket => 35,
+ Key::LeftBrace => 34,
+ Key::RightBrace => 35,
+ Key::Underscore => 20,
+ Key::Grave => 49,
+ Key::Bar => 51,
+ Key::Tilde => 49,
+ Key::QuoteLeft => 49,
+ Key::Asterisk => 17,
+ Key::Plus => 21,
+ Key::Comma => 59,
+ Key::Minus => 20,
+ Key::Period => 60,
+ Key::Slash => 61,
+ Key::BackSlash => 51,
+ Key::Colon => 47,
+ Key::SemiColon => 47,
+ Key::Less => 94,
+ Key::Equal => 21,
+ Key::Greater => 60,
+ Key::PageUp => 112,
+ Key::PageDown => 117,
+ Key::End => 115,
+ Key::Home => 110,
+ Key::Left => 113,
+ Key::Up => 111,
+ Key::Right => 114,
+ Key::Down => 116,
+ Key::Print => 107,
+ Key::PrintScreen => 107,
+ Key::Insert => 118,
+ Key::Delete => 119,
+ Key::Help => 146,
+ Key::Zero => 19,
+ Key::One => 10,
+ Key::Two => 11,
+ Key::Three => 12,
+ Key::Four => 13,
+ Key::Five => 14,
+ Key::Six => 15,
+ Key::Seven => 16,
+ Key::Eight => 17,
+ Key::Nine => 18,
+ Key::A => 38,
+ Key::B => 56,
+ Key::C => 54,
+ Key::D => 40,
+ Key::E => 26,
+ Key::F => 41,
+ Key::G => 42,
+ Key::H => 43,
+ Key::I => 31,
+ Key::J => 44,
+ Key::K => 45,
+ Key::L => 46,
+ Key::M => 58,
+ Key::N => 57,
+ Key::O => 32,
+ Key::P => 33,
+ Key::Q => 24,
+ Key::R => 27,
+ Key::S => 39,
+ Key::T => 28,
+ Key::U => 30,
+ Key::V => 55,
+ Key::W => 25,
+ Key::X => 53,
+ Key::Y => 29,
+ Key::Z => 52,
+ Key::NumPad0 => 90,
+ Key::NumPad1 => 87,
+ Key::NumPad2 => 88,
+ Key::NumPad3 => 89,
+ Key::NumPad4 => 83,
+ Key::NumPad5 => 84,
+ Key::NumPad6 => 85,
+ Key::NumPad7 => 79,
+ Key::NumPad8 => 80,
+ Key::NumPad9 => 81,
+ Key::Multiply => 63,
+ Key::Add => 86,
+ Key::Subtract => 82,
+ Key::Decimal => 129,
+ Key::Divide => 106,
+ Key::F1 => 67,
+ Key::F2 => 68,
+ Key::F3 => 69,
+ Key::F4 => 70,
+ Key::F5 => 71,
+ Key::F6 => 72,
+ Key::F7 => 73,
+ Key::F8 => 74,
+ Key::F9 => 75,
+ Key::F10 => 76,
+ Key::F11 => 95,
+ Key::F12 => 96,
+ Key::Numlock => 77,
+ Key::ScrollLock => 78,
+ Key::LeftShift => 50,
+ Key::RightShift => 62,
+ Key::LeftControl => 37,
+ Key::RightContol => 105,
+ Key::LeftAlt => 64,
+ Key::RightAlt => 108,
+ Key::LeftSuper => 133,
+ Key::RightSuper => 134,
+ Key::BrowserBack => 166,
+ Key::BrowserForward => 167,
+ Key::BrowserStop => 182,
+ Key::BrowserSearch => 225,
+ Key::BrowserFavorites => 164,
+ Key::BrowserHome => 180,
+ Key::VolumeMute => 121,
+ Key::VolumeDown => 122,
+ Key::VolumeUp => 123,
+ Key::NextTrack => 171,
+ Key::PreviousTrack => 173,
+ Key::StopMedia => 174,
+ Key::PlayPause => 172,
+ Key::LaunchMail => 163,
+ Key::SelectMedia => 234,
+ Key::LaunchAppA => 128,
+ Key::LaunchAppB => 212,
+ Key::LaunchApp1 => 156,
+ Key::LaunchApp2 => 157,
+ Key::LaunchApp3 => 210,
+ Key::LaunchApp4 => 211,
+ Key::LaunchApp5 => 192,
+ Key::LaunchApp6 => 193,
+ Key::LaunchApp7 => 194,
+ Key::LaunchApp8 => 195,
+ Key::LaunchApp9 => 196,
+ _ => return 0,
+ };
+
+ self.keys.borrow_mut().insert(keycode, key);
+ self.keycodes.borrow_mut().insert(key, keycode);
+
+ keycode
+ }
+
fn set_window_state_atom(
&self,
window: Window,
@@ -549,8 +885,64 @@ impl<'conn, Conn: connection::Connection> XConnection<'conn, Conn> {
&self,
event: &xproto::ButtonPressEvent,
) -> Option<Event> {
+ let window = event.event;
+ let window = if window == self.screen.root || window == x11rb::NONE {
+ if event.child == x11rb::NONE {
+ None
+ } else {
+ Some(event.child)
+ }
+ } else {
+ Some(window)
+ };
+
Some(Event::Mouse {
- event: MouseEvent::from_press_event(&event, self.screen.root).ok()?,
+ event: MouseEvent {
+ kind: MouseEventKind::Press,
+ input: MouseInput {
+ target: MouseInputTarget::Global,
+ button: {
+ if let Ok(button) = Button::try_from(event.detail) {
+ button
+ } else {
+ return None;
+ }
+ },
+ modifiers: {
+ let mut modifiers = HashSet::new();
+
+ if event.state & u16::from(xproto::ModMask::CONTROL) > 0 {
+ modifiers.insert(Modifier::Ctrl);
+ }
+
+ if event.state & u16::from(xproto::ModMask::SHIFT) > 0 {
+ modifiers.insert(Modifier::Shift);
+ }
+
+ if event.state & u16::from(xproto::ModMask::M1) > 0 {
+ modifiers.insert(Modifier::Alt);
+ }
+
+ if event.state & u16::from(xproto::ModMask::M4) > 0 {
+ modifiers.insert(Modifier::Super);
+ }
+
+ modifiers
+ },
+ },
+ window: {
+ if window == Some(self.screen.root) {
+ None
+ } else {
+ window
+ }
+ },
+ root_rpos: Pos {
+ x: event.root_x as i32,
+ y: event.root_y as i32,
+ },
+ },
+ on_root: window == Some(self.screen.root),
})
}
@@ -559,8 +951,64 @@ impl<'conn, Conn: connection::Connection> XConnection<'conn, Conn> {
&self,
event: &xproto::ButtonReleaseEvent,
) -> Option<Event> {
+ let window = event.event;
+ let window = if window == self.screen.root || window == x11rb::NONE {
+ if event.child == x11rb::NONE {
+ None
+ } else {
+ Some(event.child)
+ }
+ } else {
+ None
+ };
+
Some(Event::Mouse {
- event: MouseEvent::from_release_event(&event, self.screen.root).ok()?,
+ event: MouseEvent {
+ kind: MouseEventKind::Release,
+ input: MouseInput {
+ target: MouseInputTarget::Global,
+ button: {
+ if let Ok(button) = Button::try_from(event.detail) {
+ button
+ } else {
+ return None;
+ }
+ },
+ modifiers: {
+ let mut modifiers = HashSet::new();
+
+ if event.state & u16::from(xproto::ModMask::CONTROL) > 0 {
+ modifiers.insert(Modifier::Ctrl);
+ }
+
+ if event.state & u16::from(xproto::ModMask::SHIFT) > 0 {
+ modifiers.insert(Modifier::Shift);
+ }
+
+ if event.state & u16::from(xproto::ModMask::M1) > 0 {
+ modifiers.insert(Modifier::Alt);
+ }
+
+ if event.state & u16::from(xproto::ModMask::M4) > 0 {
+ modifiers.insert(Modifier::Super);
+ }
+
+ modifiers
+ },
+ },
+ window: {
+ if window == Some(self.screen.root) {
+ None
+ } else {
+ window
+ }
+ },
+ root_rpos: Pos {
+ x: event.root_x as i32,
+ y: event.root_y as i32,
+ },
+ },
+ on_root: window == Some(self.screen.root),
})
}
@@ -569,8 +1017,58 @@ impl<'conn, Conn: connection::Connection> XConnection<'conn, Conn> {
&self,
event: &xproto::MotionNotifyEvent,
) -> Option<Event> {
+ let window = event.event;
+ let window = if window == self.screen.root || window == x11rb::NONE {
+ if event.child == x11rb::NONE {
+ None
+ } else {
+ Some(event.child)
+ }
+ } else {
+ None
+ };
+
Some(Event::Mouse {
- event: MouseEvent::from_motion_event(&event, self.screen.root).ok()?,
+ event: MouseEvent {
+ kind: MouseEventKind::Motion,
+ input: MouseInput {
+ target: MouseInputTarget::Global,
+ button: Button::Left,
+ modifiers: {
+ let mut modifiers = HashSet::new();
+
+ if event.state & u16::from(xproto::ModMask::CONTROL) > 0 {
+ modifiers.insert(Modifier::Ctrl);
+ }
+
+ if event.state & u16::from(xproto::ModMask::SHIFT) > 0 {
+ modifiers.insert(Modifier::Shift);
+ }
+
+ if event.state & u16::from(xproto::ModMask::M1) > 0 {
+ modifiers.insert(Modifier::Alt);
+ }
+
+ if event.state & u16::from(xproto::ModMask::M4) > 0 {
+ modifiers.insert(Modifier::Super);
+ }
+
+ modifiers
+ },
+ },
+ window: {
+ if window == Some(self.screen.root) {
+ None
+ } else {
+ window
+ }
+ },
+ root_rpos: Pos {
+ x: event.root_x as i32,
+ y: event.root_y as i32,
+ },
+ },
+ on_root: window == Some(self.screen.root),
})
}
@@ -580,7 +1078,41 @@ impl<'conn, Conn: connection::Connection> XConnection<'conn, Conn> {
event: &xproto::KeyPressEvent,
) -> Option<Event> {
Some(Event::Key {
- key_code: KeyCode::from_press_event(&event).without_mask(ModMask::M2),
+ event: KeyEvent {
+ input: KeyInput {
+ key: self.get_key(event.detail),
+ modifiers: {
+ let mut modifiers = HashSet::new();
+
+ if event.state & u16::from(xproto::ModMask::CONTROL) > 0 {
+ modifiers.insert(Modifier::Ctrl);
+ }
+
+ if event.state & u16::from(xproto::ModMask::SHIFT) > 0 {
+ modifiers.insert(Modifier::Shift);
+ }
+
+ if event.state & u16::from(xproto::ModMask::M1) > 0 {
+ modifiers.insert(Modifier::Alt);
+ }
+
+ if event.state & u16::from(xproto::ModMask::M4) > 0 {
+ modifiers.insert(Modifier::Super);
+ }
+
+ modifiers
+ },
+ },
+ window: {
+ let window = event.event;
+
+ if window == self.screen.root || window == x11rb::NONE {
+ Some(event.child)
+ } else {
+ None
+ }
+ },
+ }
})
}
@@ -1504,33 +2036,65 @@ impl<'conn, Conn: connection::Connection> Connection for XConnection<'conn, Conn
fn grab_bindings(
&self,
- key_codes: &[&KeyCode],
- mouse_bindings: &[&(MouseEventKey, MouseShortcut)],
+ key_inputs: &[&KeyInput],
+ mouse_inputs: &[&MouseInput],
) {
for &m in &[0, u16::from(ModMask::M2), u16::from(ModMask::M5)] {
- for k in key_codes {
- drop(self.conn.grab_key(
- false,
- self.screen.root,
- k.mask | m,
- k.code,
- xproto::GrabMode::ASYNC,
- xproto::GrabMode::ASYNC,
- ));
+ for key_input in key_inputs {
+ drop(
+ self.conn.grab_key(
+ false,
+ self.screen.root,
+ key_input
+ .modifiers
+ .iter()
+ .fold(0u16, |acc, &m| acc | {
+ u16::from(match m {
+ Modifier::Ctrl => xproto::ModMask::CONTROL,
+ Modifier::Shift => xproto::ModMask::SHIFT,
+ Modifier::Alt => xproto::ModMask::M1,
+ Modifier::Super => xproto::ModMask::M4,
+ Modifier::NumLock => xproto::ModMask::M2,
+ Modifier::ScrollLock => xproto::ModMask::M5,
+ _ => xproto::ModMask::ANY,
+ })
+ })
+ | u16::from(m),
+ self.get_keycode(key_input.key),
+ xproto::GrabMode::ASYNC,
+ xproto::GrabMode::ASYNC,
+ ),
+ );
}
- for (_, state) in mouse_bindings {
- drop(self.conn.grab_button(
- false,
- self.screen.root,
- u32::from(self.mouse_event_mask) as u16 | m,
- xproto::GrabMode::ASYNC,
- xproto::GrabMode::ASYNC,
- x11rb::NONE,
- x11rb::NONE,
- xproto::ButtonIndex::try_from(state.button()).unwrap(),
- state.mask() | m,
- ));
+ for mouse_input in mouse_inputs {
+ drop(
+ self.conn.grab_button(
+ false,
+ self.screen.root,
+ u32::from(self.mouse_event_mask) as u16,
+ xproto::GrabMode::ASYNC,
+ xproto::GrabMode::ASYNC,
+ x11rb::NONE,
+ x11rb::NONE,
+ xproto::ButtonIndex::try_from(mouse_input.button as u8).unwrap(),
+ mouse_input
+ .modifiers
+ .iter()
+ .fold(0u16, |acc, &m| acc | {
+ u16::from(match m {
+ Modifier::Ctrl => xproto::ModMask::CONTROL,
+ Modifier::Shift => xproto::ModMask::SHIFT,
+ Modifier::Alt => xproto::ModMask::M1,
+ Modifier::Super => xproto::ModMask::M4,
+ Modifier::NumLock => xproto::ModMask::M2,
+ Modifier::ScrollLock => xproto::ModMask::M5,
+ _ => xproto::ModMask::ANY,
+ })
+ })
+ | u16::from(m),
+ ),
+ );
}
}