kranewl

A wlroots-based dynamic Wayland compositor, written in C++, configurable with Lua
git clone git://git.deurzen.net/kranewl
Log | Files | Refs | LICENSE

commit 6fcb966919047d15a925410c67f1c2caa27cd878
parent 3e7e073d1ade79e2ae79ea49d7402c78cd49989e
Author: deurzen <max@deurzen.net>
Date:   Sat,  4 Jun 2022 01:06:51 +0200

implements key binding key repeat handling

Diffstat:
Minclude/kranewl/input/bindings.hh | 9---------
Minclude/kranewl/input/cursor.hh | 5+++++
Minclude/kranewl/input/key-bindings.hh | 917++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------
Minclude/kranewl/input/keyboard.hh | 27+++++++++++++++++++++------
Msrc/kranewl/input/keyboard.cc | 120+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------
Msrc/kranewl/input/seat.cc | 1+
6 files changed, 847 insertions(+), 232 deletions(-)

diff --git a/include/kranewl/input/bindings.hh b/include/kranewl/input/bindings.hh @@ -4,21 +4,12 @@ #include <kranewl/input/cursor.hh> #include <cstdint> -#include <functional> #include <optional> class Model; typedef struct View* View_ptr; typedef - std::function<void(Model&)> - KeyboardAction; - -typedef - std::function<bool(Model&, View_ptr)> - CursorAction; - -typedef std::unordered_map<KeyboardInput, KeyboardAction> KeyBindings; diff --git a/include/kranewl/input/cursor.hh b/include/kranewl/input/cursor.hh @@ -10,6 +10,7 @@ extern "C" { } #include <cstdint> +#include <functional> #include <unordered_set> struct CursorInput { @@ -43,6 +44,10 @@ typedef class Seat* Seat_ptr; typedef struct View* View_ptr; typedef struct Node* Node_ptr; +typedef + std::function<bool(Model&, View_ptr)> + CursorAction; + typedef struct Cursor { enum class Mode { Passthrough, diff --git a/include/kranewl/input/key-bindings.hh b/include/kranewl/input/key-bindings.hh @@ -23,597 +23,1116 @@ namespace Bindings { static const KeyBindings key_bindings = { { { XKB_KEY_Q, MODKEY | WLR_MODIFIER_CTRL | WLR_MODIFIER_SHIFT }, - CALL(exit()) + { + .action = CALL(exit()), + .repeatable = false + } }, // view state modifiers { { XKB_KEY_c, MODKEY }, - CALL(kill_focus()) + { + .action = CALL(kill_focus()), + .repeatable = false + } }, { { XKB_KEY_space, MODKEY | WLR_MODIFIER_SHIFT }, - CALL(set_floating_focus(Toggle::Reverse)) + { + .action = CALL(set_floating_focus(Toggle::Reverse)), + .repeatable = false + } }, { { XKB_KEY_f, MODKEY }, - CALL(set_fullscreen_focus(Toggle::Reverse)) + { + .action = CALL(set_fullscreen_focus(Toggle::Reverse)), + .repeatable = false + } }, { { XKB_KEY_x, MODKEY }, - CALL(set_sticky_focus(Toggle::Reverse)) + { + .action = CALL(set_sticky_focus(Toggle::Reverse)), + .repeatable = false + } }, { { XKB_KEY_f, MODKEY | SECKEY | WLR_MODIFIER_CTRL }, - CALL(set_contained_focus(Toggle::Reverse)) + { + .action = CALL(set_contained_focus(Toggle::Reverse)), + .repeatable = false + } }, { { XKB_KEY_i, MODKEY | SECKEY | WLR_MODIFIER_CTRL }, - CALL(set_invincible_focus(Toggle::Reverse)) + { + .action = CALL(set_invincible_focus(Toggle::Reverse)), + .repeatable = false + } }, { { XKB_KEY_y, MODKEY }, - CALL(set_iconify_focus(Toggle::Reverse)) + { + .action = CALL(set_iconify_focus(Toggle::Reverse)), + .repeatable = false + } }, { { XKB_KEY_u, MODKEY }, - CALL(pop_deiconify()) + { + .action = CALL(pop_deiconify()), + .repeatable = false + } }, { { XKB_KEY_u, MODKEY | SECKEY }, - CALL(deiconify_all()) + { + .action = CALL(deiconify_all()), + .repeatable = false + } }, // view arrangers { { XKB_KEY_space, MODKEY | WLR_MODIFIER_CTRL }, - CALL(center_focus()) + { + .action = CALL(center_focus()), + .repeatable = false + } }, { { XKB_KEY_h, MODKEY | WLR_MODIFIER_CTRL }, - [](Model& model) { + { + .action = [](Model& model) { View_ptr focus = model.focused_view(); if (focus && model.is_free(focus)) - model.nudge_focus(Edge::Left, 15); + model.nudge_focus(Edge::Left, 50); else model.shuffle_main(Direction::Backward); - } + }, + .repeatable = true + } }, { { XKB_KEY_j, MODKEY | WLR_MODIFIER_CTRL }, - [](Model& model) { + { + .action = [](Model& model) { View_ptr focus = model.focused_view(); if (focus && model.is_free(focus)) - model.nudge_focus(Edge::Bottom, 15); + model.nudge_focus(Edge::Bottom, 50); else model.shuffle_stack(Direction::Forward); - } + }, + .repeatable = true + } }, { { XKB_KEY_k, MODKEY | WLR_MODIFIER_CTRL }, - [](Model& model) { + { + .action = [](Model& model) { View_ptr focus = model.focused_view(); if (focus && model.is_free(focus)) - model.nudge_focus(Edge::Top, 15); + model.nudge_focus(Edge::Top, 50); else model.shuffle_stack(Direction::Backward); - } + }, + .repeatable = true + } }, { { XKB_KEY_l, MODKEY | WLR_MODIFIER_CTRL }, - [](Model& model) { + { + .action = [](Model& model) { View_ptr focus = model.focused_view(); if (focus && model.is_free(focus)) - model.nudge_focus(Edge::Right, 15); + model.nudge_focus(Edge::Right, 50); else model.shuffle_main(Direction::Forward); - } + }, + .repeatable = true + } }, { { XKB_KEY_H, MODKEY | WLR_MODIFIER_CTRL | WLR_MODIFIER_SHIFT }, - CALL(stretch_focus(Edge::Left, 15)) + { + .action = CALL(stretch_focus(Edge::Left, 50)), + .repeatable = true + } }, { { XKB_KEY_J, MODKEY | WLR_MODIFIER_CTRL | WLR_MODIFIER_SHIFT }, - CALL(stretch_focus(Edge::Bottom, 15)) + { + .action = CALL(stretch_focus(Edge::Bottom, 50)), + .repeatable = true + } }, { { XKB_KEY_K, MODKEY | WLR_MODIFIER_CTRL | WLR_MODIFIER_SHIFT }, - CALL(stretch_focus(Edge::Top, 15)) + { + .action = CALL(stretch_focus(Edge::Top, 50)), + .repeatable = true + } }, { { XKB_KEY_L, MODKEY | WLR_MODIFIER_CTRL | WLR_MODIFIER_SHIFT }, - CALL(stretch_focus(Edge::Right, 15)) + { + .action = CALL(stretch_focus(Edge::Right, 50)), + .repeatable = true + } }, { { XKB_KEY_Y, MODKEY | WLR_MODIFIER_CTRL | WLR_MODIFIER_SHIFT }, - CALL(stretch_focus(Edge::Left, -15)) + { + .action = CALL(stretch_focus(Edge::Left, -50)), + .repeatable = true + } }, { { XKB_KEY_U, MODKEY | WLR_MODIFIER_CTRL | WLR_MODIFIER_SHIFT }, - CALL(stretch_focus(Edge::Bottom, -15)) + { + .action = CALL(stretch_focus(Edge::Bottom, -50)), + .repeatable = true + } }, { { XKB_KEY_I, MODKEY | WLR_MODIFIER_CTRL | WLR_MODIFIER_SHIFT }, - CALL(stretch_focus(Edge::Top, -15)) + { + .action = CALL(stretch_focus(Edge::Top, -50)), + .repeatable = true + } }, { { XKB_KEY_O, MODKEY | WLR_MODIFIER_CTRL | WLR_MODIFIER_SHIFT }, - CALL(stretch_focus(Edge::Right, -15)) -}, -{ { XKB_KEY_leftarrow, MODKEY | WLR_MODIFIER_CTRL }, - CALL(snap_focus(WLR_EDGE_LEFT)) -}, -{ { XKB_KEY_downarrow, MODKEY | WLR_MODIFIER_CTRL }, - CALL(snap_focus(WLR_EDGE_BOTTOM)) -}, -{ { XKB_KEY_uparrow, MODKEY | WLR_MODIFIER_CTRL }, - CALL(snap_focus(WLR_EDGE_TOP)) -}, -{ { XKB_KEY_rightarrow, MODKEY | WLR_MODIFIER_CTRL }, - CALL(snap_focus(WLR_EDGE_RIGHT)) + { + .action = CALL(stretch_focus(Edge::Right, -50)), + .repeatable = true + } +}, +{ { XKB_KEY_Left, MODKEY | WLR_MODIFIER_CTRL }, + { + .action = CALL(snap_focus(WLR_EDGE_LEFT)), + .repeatable = false + } +}, +{ { XKB_KEY_Down, MODKEY | WLR_MODIFIER_CTRL }, + { + .action = CALL(snap_focus(WLR_EDGE_BOTTOM)), + .repeatable = false + } +}, +{ { XKB_KEY_Up, MODKEY | WLR_MODIFIER_CTRL }, + { + .action = CALL(snap_focus(WLR_EDGE_TOP)), + .repeatable = false + } +}, +{ { XKB_KEY_Right, MODKEY | WLR_MODIFIER_CTRL }, + { + .action = CALL(snap_focus(WLR_EDGE_RIGHT)), + .repeatable = false + } }, { { XKB_KEY_j, MODKEY }, - CALL(cycle_focus(Direction::Forward)) + { + .action = CALL(cycle_focus(Direction::Forward)), + .repeatable = true + } }, { { XKB_KEY_k, MODKEY }, - CALL(cycle_focus(Direction::Backward)) + { + .action = CALL(cycle_focus(Direction::Backward)), + .repeatable = true + } }, { { XKB_KEY_J, MODKEY | WLR_MODIFIER_SHIFT }, - CALL(drag_focus(Direction::Forward)) + { + .action = CALL(drag_focus(Direction::Forward)), + .repeatable = true + } }, { { XKB_KEY_K, MODKEY | WLR_MODIFIER_SHIFT }, - CALL(drag_focus(Direction::Backward)) + { + .action = CALL(drag_focus(Direction::Backward)), + .repeatable = true + } }, { { XKB_KEY_r, MODKEY }, - CALL(reverse_views()) + { + .action = CALL(reverse_views()), + .repeatable = false + } }, { { XKB_KEY_colon, MODKEY | WLR_MODIFIER_SHIFT }, - CALL(rotate_views(Direction::Forward)) + { + .action = CALL(rotate_views(Direction::Forward)), + .repeatable = true + } }, { { XKB_KEY_less, MODKEY | WLR_MODIFIER_SHIFT }, - CALL(rotate_views(Direction::Backward)) + { + .action = CALL(rotate_views(Direction::Backward)), + .repeatable = true + } }, // workspace behavior modifiers { { XKB_KEY_M, MODKEY | WLR_MODIFIER_SHIFT }, - CALL(set_focus_follows_cursor(Toggle::Reverse, model.mp_workspace)) + { + .action = CALL(set_focus_follows_cursor(Toggle::Reverse, model.mp_workspace)), + .repeatable = false + } }, { { XKB_KEY_M, MODKEY | WLR_MODIFIER_CTRL | WLR_MODIFIER_SHIFT }, - CALL(set_focus_follows_cursor(Toggle::Reverse, model.mp_context)) + { + .action = CALL(set_focus_follows_cursor(Toggle::Reverse, model.mp_context)), + .repeatable = false + } }, // workspace layout modifiers { { XKB_KEY_F, MODKEY | WLR_MODIFIER_SHIFT }, - CALL(set_layout(LayoutHandler::LayoutKind::Float)) + { + .action = CALL(set_layout(LayoutHandler::LayoutKind::Float)), + .repeatable = false + } }, { { XKB_KEY_L, MODKEY | WLR_MODIFIER_SHIFT }, - CALL(set_layout(LayoutHandler::LayoutKind::FramelessFloat)) + { + .action = CALL(set_layout(LayoutHandler::LayoutKind::FramelessFloat)), + .repeatable = false + } }, { { XKB_KEY_z, MODKEY }, - CALL(set_layout(LayoutHandler::LayoutKind::SingleFloat)) + { + .action = CALL(set_layout(LayoutHandler::LayoutKind::SingleFloat)), + .repeatable = false + } }, { { XKB_KEY_Z, MODKEY | WLR_MODIFIER_SHIFT }, - CALL(set_layout(LayoutHandler::LayoutKind::FramelessSingleFloat)) + { + .action = CALL(set_layout(LayoutHandler::LayoutKind::FramelessSingleFloat)), + .repeatable = false + } }, { { XKB_KEY_m, MODKEY }, - CALL(set_layout(LayoutHandler::LayoutKind::Monocle)) + { + .action = CALL(set_layout(LayoutHandler::LayoutKind::Monocle)), + .repeatable = false + } }, { { XKB_KEY_d, MODKEY | WLR_MODIFIER_CTRL }, - CALL(set_layout(LayoutHandler::LayoutKind::MainDeck)) + { + .action = CALL(set_layout(LayoutHandler::LayoutKind::MainDeck)), + .repeatable = false + } }, { { XKB_KEY_D, MODKEY | WLR_MODIFIER_SHIFT }, - CALL(set_layout(LayoutHandler::LayoutKind::StackDeck)) + { + .action = CALL(set_layout(LayoutHandler::LayoutKind::StackDeck)), + .repeatable = false + } }, { { XKB_KEY_D, MODKEY | WLR_MODIFIER_CTRL | WLR_MODIFIER_SHIFT }, - CALL(set_layout(LayoutHandler::LayoutKind::DoubleDeck)) + { + .action = CALL(set_layout(LayoutHandler::LayoutKind::DoubleDeck)), + .repeatable = false + } }, { { XKB_KEY_g, MODKEY }, - CALL(set_layout(LayoutHandler::LayoutKind::Center)) + { + .action = CALL(set_layout(LayoutHandler::LayoutKind::Center)), + .repeatable = false + } }, { { XKB_KEY_t, MODKEY }, - CALL(set_layout(LayoutHandler::LayoutKind::DoubleStack)) + { + .action = CALL(set_layout(LayoutHandler::LayoutKind::DoubleStack)), + .repeatable = false + } }, { { XKB_KEY_T, MODKEY | WLR_MODIFIER_SHIFT }, - CALL(set_layout(LayoutHandler::LayoutKind::CompactDoubleStack)) + { + .action = CALL(set_layout(LayoutHandler::LayoutKind::CompactDoubleStack)), + .repeatable = false + } }, { { XKB_KEY_P, MODKEY | WLR_MODIFIER_CTRL | WLR_MODIFIER_SHIFT }, - CALL(set_layout(LayoutHandler::LayoutKind::Paper)) + { + .action = CALL(set_layout(LayoutHandler::LayoutKind::Paper)), + .repeatable = false + } }, { { XKB_KEY_P, MODKEY | SECKEY | WLR_MODIFIER_CTRL | WLR_MODIFIER_SHIFT }, - CALL(set_layout(LayoutHandler::LayoutKind::CompactPaper)) + { + .action = CALL(set_layout(LayoutHandler::LayoutKind::CompactPaper)), + .repeatable = false + } }, { { XKB_KEY_Y, MODKEY | WLR_MODIFIER_SHIFT }, - CALL(set_layout(LayoutHandler::LayoutKind::HorizontalStack)) + { + .action = CALL(set_layout(LayoutHandler::LayoutKind::HorizontalStack)), + .repeatable = false + } }, { { XKB_KEY_y, MODKEY | WLR_MODIFIER_CTRL }, - CALL(set_layout(LayoutHandler::LayoutKind::CompactHorizontalStack)) + { + .action = CALL(set_layout(LayoutHandler::LayoutKind::CompactHorizontalStack)), + .repeatable = false + } }, { { XKB_KEY_V, MODKEY | WLR_MODIFIER_SHIFT }, - CALL(set_layout(LayoutHandler::LayoutKind::VerticalStack)) + { + .action = CALL(set_layout(LayoutHandler::LayoutKind::VerticalStack)), + .repeatable = false + } }, { { XKB_KEY_v, MODKEY | WLR_MODIFIER_CTRL }, - CALL(set_layout(LayoutHandler::LayoutKind::CompactVerticalStack)) + { + .action = CALL(set_layout(LayoutHandler::LayoutKind::CompactVerticalStack)), + .repeatable = false + } }, { { XKB_KEY_F, MODKEY | WLR_MODIFIER_CTRL | WLR_MODIFIER_SHIFT }, - CALL(set_layout_retain_region(LayoutHandler::LayoutKind::Float)) + { + .action = CALL(set_layout_retain_region(LayoutHandler::LayoutKind::Float)), + .repeatable = false + } }, { { XKB_KEY_space, MODKEY }, - CALL(toggle_layout()) + { + .action = CALL(toggle_layout()), + .repeatable = false + } }, { { XKB_KEY_Return, MODKEY }, - CALL_EXTERNAL(alacritty) + { + .action = CALL_EXTERNAL(alacritty), + .repeatable = false + } }, // workspace layout storage and retrieval { { XKB_KEY_F1, MODKEY | WLR_MODIFIER_SHIFT }, - CALL(save_layout(0)) + { + .action = CALL(save_layout(0)), + .repeatable = false + } }, { { XKB_KEY_F2, MODKEY | WLR_MODIFIER_SHIFT }, - CALL(save_layout(1)) + { + .action = CALL(save_layout(1)), + .repeatable = false + } }, { { XKB_KEY_F3, MODKEY | WLR_MODIFIER_SHIFT }, - CALL(save_layout(2)) + { + .action = CALL(save_layout(2)), + .repeatable = false + } }, { { XKB_KEY_F4, MODKEY | WLR_MODIFIER_SHIFT }, - CALL(save_layout(3)) + { + .action = CALL(save_layout(3)), + .repeatable = false + } }, { { XKB_KEY_F5, MODKEY | WLR_MODIFIER_SHIFT }, - CALL(save_layout(4)) + { + .action = CALL(save_layout(4)), + .repeatable = false + } }, { { XKB_KEY_F6, MODKEY | WLR_MODIFIER_SHIFT }, - CALL(save_layout(5)) + { + .action = CALL(save_layout(5)), + .repeatable = false + } }, { { XKB_KEY_F7, MODKEY | WLR_MODIFIER_SHIFT }, - CALL(save_layout(6)) + { + .action = CALL(save_layout(6)), + .repeatable = false + } }, { { XKB_KEY_F8, MODKEY | WLR_MODIFIER_SHIFT }, - CALL(save_layout(7)) + { + .action = CALL(save_layout(7)), + .repeatable = false + } }, { { XKB_KEY_F9, MODKEY | WLR_MODIFIER_SHIFT }, - CALL(save_layout(8)) + { + .action = CALL(save_layout(8)), + .repeatable = false + } }, { { XKB_KEY_F10, MODKEY | WLR_MODIFIER_SHIFT }, - CALL(save_layout(9)) + { + .action = CALL(save_layout(9)), + .repeatable = false + } }, { { XKB_KEY_F11, MODKEY | WLR_MODIFIER_SHIFT }, - CALL(save_layout(10)) + { + .action = CALL(save_layout(10)), + .repeatable = false + } }, { { XKB_KEY_F12, MODKEY | WLR_MODIFIER_SHIFT }, - CALL(save_layout(11)) + { + .action = CALL(save_layout(11)), + .repeatable = false + } }, { { XKB_KEY_F1, MODKEY }, - CALL(load_layout(0)) + { + .action = CALL(load_layout(0)), + .repeatable = false + } }, { { XKB_KEY_F2, MODKEY }, - CALL(load_layout(1)) + { + .action = CALL(load_layout(1)), + .repeatable = false + } }, { { XKB_KEY_F3, MODKEY }, - CALL(load_layout(2)) + { + .action = CALL(load_layout(2)), + .repeatable = false + } }, { { XKB_KEY_F4, MODKEY }, - CALL(load_layout(3)) + { + .action = CALL(load_layout(3)), + .repeatable = false + } }, { { XKB_KEY_F5, MODKEY }, - CALL(load_layout(4)) + { + .action = CALL(load_layout(4)), + .repeatable = false + } }, { { XKB_KEY_F6, MODKEY }, - CALL(load_layout(5)) + { + .action = CALL(load_layout(5)), + .repeatable = false + } }, { { XKB_KEY_F7, MODKEY }, - CALL(load_layout(6)) + { + .action = CALL(load_layout(6)), + .repeatable = false + } }, { { XKB_KEY_F8, MODKEY }, - CALL(load_layout(7)) + { + .action = CALL(load_layout(7)), + .repeatable = false + } }, { { XKB_KEY_F9, MODKEY }, - CALL(load_layout(8)) + { + .action = CALL(load_layout(8)), + .repeatable = false + } }, { { XKB_KEY_F10, MODKEY }, - CALL(load_layout(9)) + { + .action = CALL(load_layout(9)), + .repeatable = false + } }, { { XKB_KEY_F11, MODKEY }, - CALL(load_layout(10)) + { + .action = CALL(load_layout(10)), + .repeatable = false + } }, { { XKB_KEY_F12, MODKEY }, - CALL(load_layout(11)) + { + .action = CALL(load_layout(11)), + .repeatable = false + } }, // workspace layout data modifiers { { XKB_KEY_equal, MODKEY }, - CALL(change_gap_size(2)) + { + .action = CALL(change_gap_size(2)), + .repeatable = true + } }, { { XKB_KEY_minus, MODKEY }, - CALL(change_gap_size(-2)) + { + .action = CALL(change_gap_size(-2)), + .repeatable = true + } }, { { XKB_KEY_plus, MODKEY | WLR_MODIFIER_SHIFT }, - CALL(reset_gap_size()) + { + .action = CALL(reset_gap_size()), + .repeatable = true + } }, { { XKB_KEY_i, MODKEY }, - CALL(change_main_count(1)) + { + .action = CALL(change_main_count(1)), + .repeatable = true + } }, { { XKB_KEY_d, MODKEY }, - CALL(change_main_count(-1)) + { + .action = CALL(change_main_count(-1)), + .repeatable = true + } }, { { XKB_KEY_l, MODKEY }, - CALL(change_main_factor(.05f)) + { + .action = CALL(change_main_factor(.05f)), + .repeatable = true + } }, { { XKB_KEY_h, MODKEY }, - CALL(change_main_factor(-.05f)) + { + .action = CALL(change_main_factor(-.05f)), + .repeatable = true + } }, { { XKB_KEY_Page_Up, MODKEY | WLR_MODIFIER_SHIFT }, - CALL(change_margin(5)) + { + .action = CALL(change_margin(5)), + .repeatable = true + } }, { { XKB_KEY_Page_Down, MODKEY | WLR_MODIFIER_SHIFT }, - CALL(change_margin(-5)) + { + .action = CALL(change_margin(-5)), + .repeatable = true + } }, { { XKB_KEY_Left, MODKEY | WLR_MODIFIER_SHIFT }, - CALL(change_margin(Edge::Left, 5)) + { + .action = CALL(change_margin(Edge::Left, 5)), + .repeatable = true + } }, { { XKB_KEY_Left, MODKEY | WLR_MODIFIER_CTRL | WLR_MODIFIER_SHIFT }, - CALL(change_margin(Edge::Left, -5)) + { + .action = CALL(change_margin(Edge::Left, -5)), + .repeatable = true + } }, { { XKB_KEY_Up, MODKEY | WLR_MODIFIER_SHIFT }, - CALL(change_margin(Edge::Top, 5)) + { + .action = CALL(change_margin(Edge::Top, 5)), + .repeatable = true + } }, { { XKB_KEY_Up, MODKEY | WLR_MODIFIER_CTRL | WLR_MODIFIER_SHIFT }, - CALL(change_margin(Edge::Top, -5)) + { + .action = CALL(change_margin(Edge::Top, -5)), + .repeatable = true + } }, { { XKB_KEY_Right, MODKEY | WLR_MODIFIER_SHIFT }, - CALL(change_margin(Edge::Right, 5)) + { + .action = CALL(change_margin(Edge::Right, 5)), + .repeatable = true + } }, { { XKB_KEY_Right, MODKEY | WLR_MODIFIER_CTRL | WLR_MODIFIER_SHIFT }, - CALL(change_margin(Edge::Right, -5)) + { + .action = CALL(change_margin(Edge::Right, -5)), + .repeatable = true + } }, { { XKB_KEY_Down, MODKEY | WLR_MODIFIER_SHIFT }, - CALL(change_margin(Edge::Bottom, 5)) + { + .action = CALL(change_margin(Edge::Bottom, 5)), + .repeatable = true + } }, { { XKB_KEY_Down, MODKEY | WLR_MODIFIER_CTRL | WLR_MODIFIER_SHIFT }, - CALL(change_margin(Edge::Bottom, -5)) + { + .action = CALL(change_margin(Edge::Bottom, -5)), + .repeatable = true + } }, { { XKB_KEY_less, MODKEY | WLR_MODIFIER_CTRL | WLR_MODIFIER_SHIFT }, - CALL(cycle_layout_data(Direction::Backward)) + { + .action = CALL(cycle_layout_data(Direction::Backward)), + .repeatable = false + } }, { { XKB_KEY_greater, MODKEY | WLR_MODIFIER_CTRL | WLR_MODIFIER_SHIFT }, - CALL(cycle_layout_data(Direction::Forward)) + { + .action = CALL(cycle_layout_data(Direction::Forward)), + .repeatable = false + } }, { { XKB_KEY_question, MODKEY | WLR_MODIFIER_CTRL | WLR_MODIFIER_SHIFT }, - CALL(toggle_layout_data()) + { + .action = CALL(toggle_layout_data()), + .repeatable = false + } }, { { XKB_KEY_Delete, MODKEY | WLR_MODIFIER_CTRL | WLR_MODIFIER_SHIFT }, - CALL(copy_data_from_prev_layout()) + { + .action = CALL(copy_data_from_prev_layout()), + .repeatable = false + } }, { { XKB_KEY_plus, MODKEY | WLR_MODIFIER_CTRL | WLR_MODIFIER_SHIFT }, - CALL(reset_margin()) + { + .action = CALL(reset_margin()), + .repeatable = false + } }, { { XKB_KEY_plus, MODKEY | SECKEY | WLR_MODIFIER_CTRL | WLR_MODIFIER_SHIFT }, - CALL(reset_layout_data()) + { + .action = CALL(reset_layout_data()), + .repeatable = false + } }, // workspace activators { { XKB_KEY_Escape, MODKEY }, - CALL(toggle_workspace_current_context()) + { + .action = CALL(toggle_workspace_current_context()), + .repeatable = false + } }, { { XKB_KEY_bracketright, MODKEY }, - CALL(activate_next_workspace_current_context(Direction::Forward)) + { + .action = CALL(activate_next_workspace_current_context(Direction::Forward)), + .repeatable = false + } }, { { XKB_KEY_bracketleft, MODKEY }, - CALL(activate_next_workspace_current_context(Direction::Backward)) + { + .action = CALL(activate_next_workspace_current_context(Direction::Backward)), + .repeatable = false + } }, { { XKB_KEY_1, MODKEY }, - CALL(activate_workspace_current_context(Index{0})) + { + .action = CALL(activate_workspace_current_context(Index{0})), + .repeatable = false + } }, { { XKB_KEY_2, MODKEY }, - CALL(activate_workspace_current_context(1)) + { + .action = CALL(activate_workspace_current_context(1)), + .repeatable = false + } }, { { XKB_KEY_3, MODKEY }, - CALL(activate_workspace_current_context(2)) + { + .action = CALL(activate_workspace_current_context(2)), + .repeatable = false + } }, { { XKB_KEY_4, MODKEY }, - CALL(activate_workspace_current_context(3)) + { + .action = CALL(activate_workspace_current_context(3)), + .repeatable = false + } }, { { XKB_KEY_5, MODKEY }, - CALL(activate_workspace_current_context(4)) + { + .action = CALL(activate_workspace_current_context(4)), + .repeatable = false + } }, { { XKB_KEY_6, MODKEY }, - CALL(activate_workspace_current_context(5)) + { + .action = CALL(activate_workspace_current_context(5)), + .repeatable = false + } }, { { XKB_KEY_7, MODKEY }, - CALL(activate_workspace_current_context(6)) + { + .action = CALL(activate_workspace_current_context(6)), + .repeatable = false + } }, { { XKB_KEY_8, MODKEY }, - CALL(activate_workspace_current_context(7)) + { + .action = CALL(activate_workspace_current_context(7)), + .repeatable = false + } }, { { XKB_KEY_9, MODKEY }, - CALL(activate_workspace_current_context(8)) + { + .action = CALL(activate_workspace_current_context(8)), + .repeatable = false + } }, { { XKB_KEY_0, MODKEY }, - CALL(activate_workspace_current_context(9)) + { + .action = CALL(activate_workspace_current_context(9)), + .repeatable = false + } }, // workspace view movers { { XKB_KEY_braceright, MODKEY | WLR_MODIFIER_SHIFT }, - CALL(move_focus_to_next_workspace(Direction::Forward)) + { + .action = CALL(move_focus_to_next_workspace(Direction::Forward)), + .repeatable = false + } }, { { XKB_KEY_braceleft, MODKEY | WLR_MODIFIER_SHIFT }, - CALL(move_focus_to_next_workspace(Direction::Backward)) + { + .action = CALL(move_focus_to_next_workspace(Direction::Backward)), + .repeatable = false + } }, { { XKB_KEY_exclam, MODKEY | WLR_MODIFIER_SHIFT }, - CALL(move_focus_to_workspace(0)) + { + .action = CALL(move_focus_to_workspace(0)), + .repeatable = false + } }, { { XKB_KEY_at, MODKEY | WLR_MODIFIER_SHIFT }, - CALL(move_focus_to_workspace(1)) + { + .action = CALL(move_focus_to_workspace(1)), + .repeatable = false + } }, { { XKB_KEY_numbersign, MODKEY | WLR_MODIFIER_SHIFT }, - CALL(move_focus_to_workspace(2)) + { + .action = CALL(move_focus_to_workspace(2)), + .repeatable = false + } }, { { XKB_KEY_dollar, MODKEY | WLR_MODIFIER_SHIFT }, - CALL(move_focus_to_workspace(3)) + { + .action = CALL(move_focus_to_workspace(3)), + .repeatable = false + } }, { { XKB_KEY_percent, MODKEY | WLR_MODIFIER_SHIFT }, - CALL(move_focus_to_workspace(4)) + { + .action = CALL(move_focus_to_workspace(4)), + .repeatable = false + } }, { { XKB_KEY_asciicircum, MODKEY | WLR_MODIFIER_SHIFT }, - CALL(move_focus_to_workspace(5)) + { + .action = CALL(move_focus_to_workspace(5)), + .repeatable = false + } }, { { XKB_KEY_ampersand, MODKEY | WLR_MODIFIER_SHIFT }, - CALL(move_focus_to_workspace(6)) + { + .action = CALL(move_focus_to_workspace(6)), + .repeatable = false + } }, { { XKB_KEY_asterisk, MODKEY | WLR_MODIFIER_SHIFT }, - CALL(move_focus_to_workspace(7)) + { + .action = CALL(move_focus_to_workspace(7)), + .repeatable = false + } }, { { XKB_KEY_parenleft, MODKEY | WLR_MODIFIER_SHIFT }, - CALL(move_focus_to_workspace(8)) + { + .action = CALL(move_focus_to_workspace(8)), + .repeatable = false + } }, { { XKB_KEY_parenright, MODKEY | WLR_MODIFIER_SHIFT }, - CALL(move_focus_to_workspace(9)) + { + .action = CALL(move_focus_to_workspace(9)), + .repeatable = false + } }, // context activators { { XKB_KEY_Escape, MODKEY | WLR_MODIFIER_CTRL }, - CALL(toggle_context()) + { + .action = CALL(toggle_context()), + .repeatable = false + } }, { { XKB_KEY_bracketright, MODKEY | WLR_MODIFIER_CTRL }, - CALL(activate_next_context(Direction::Forward)) + { + .action = CALL(activate_next_context(Direction::Forward)), + .repeatable = false + } }, { { XKB_KEY_bracketleft, MODKEY | WLR_MODIFIER_CTRL }, - CALL(activate_next_context(Direction::Backward)) + { + .action = CALL(activate_next_context(Direction::Backward)), + .repeatable = false + } }, { { XKB_KEY_1, MODKEY | WLR_MODIFIER_CTRL }, - CALL(activate_context(Index{0})) + { + .action = CALL(activate_context(Index{0})), + .repeatable = false + } }, { { XKB_KEY_2, MODKEY | WLR_MODIFIER_CTRL }, - CALL(activate_context(1)) + { + .action = CALL(activate_context(1)), + .repeatable = false + } }, { { XKB_KEY_3, MODKEY | WLR_MODIFIER_CTRL }, - CALL(activate_context(2)) + { + .action = CALL(activate_context(2)), + .repeatable = false + } }, { { XKB_KEY_4, MODKEY | WLR_MODIFIER_CTRL }, - CALL(activate_context(3)) + { + .action = CALL(activate_context(3)), + .repeatable = false + } }, { { XKB_KEY_5, MODKEY | WLR_MODIFIER_CTRL }, - CALL(activate_context(4)) + { + .action = CALL(activate_context(4)), + .repeatable = false + } }, { { XKB_KEY_6, MODKEY | WLR_MODIFIER_CTRL }, - CALL(activate_context(5)) + { + .action = CALL(activate_context(5)), + .repeatable = false + } }, { { XKB_KEY_7, MODKEY | WLR_MODIFIER_CTRL }, - CALL(activate_context(6)) + { + .action = CALL(activate_context(6)), + .repeatable = false + } }, { { XKB_KEY_8, MODKEY | WLR_MODIFIER_CTRL }, - CALL(activate_context(7)) + { + .action = CALL(activate_context(7)), + .repeatable = false + } }, { { XKB_KEY_9, MODKEY | WLR_MODIFIER_CTRL }, - CALL(activate_context(8)) + { + .action = CALL(activate_context(8)), + .repeatable = false + } }, { { XKB_KEY_0, MODKEY | WLR_MODIFIER_CTRL }, - CALL(activate_context(9)) + { + .action = CALL(activate_context(9)), + .repeatable = false + } }, // view jump criteria { { XKB_KEY_b, MODKEY }, - CALL(jump_view({ + { + .action = CALL(jump_view({ SearchSelector::SelectionCriterium::ByAppIdEquals, - "qutebrowser" - })) + "firefox" + })), + .repeatable = false + } }, { { XKB_KEY_B, MODKEY | WLR_MODIFIER_SHIFT }, - CALL(jump_view({ + { + .action = CALL(jump_view({ SearchSelector::SelectionCriterium::ByAppIdEquals, - "firefox" - })) + "qutebrowser" + })), + .repeatable = false + } }, { { XKB_KEY_b, MODKEY | WLR_MODIFIER_CTRL }, - CALL(jump_view({ + { + .action = CALL(jump_view({ SearchSelector::SelectionCriterium::ByAppIdContains, "chromium" - })) + })), + .repeatable = false + } }, { { XKB_KEY_space, MODKEY | SECKEY }, - CALL(jump_view({ + { + .action = CALL(jump_view({ SearchSelector::SelectionCriterium::ByAppIdEquals, "spotify" - })) + })), + .repeatable = false + } }, { { XKB_KEY_e, MODKEY }, - CALL(jump_view({ + { + .action = CALL(jump_view({ SearchSelector::SelectionCriterium::ByTitleContains, "[vim]" - })) + })), + .repeatable = false + } }, { { XKB_KEY_comma, MODKEY }, - CALL(jump_view({ + { + .action = CALL(jump_view({ model.mp_workspace->index(), Workspace::ViewSelector::SelectionCriterium::AtFirst - })) + })), + .repeatable = false + } }, { { XKB_KEY_period, MODKEY }, - CALL(jump_view({ + { + .action = CALL(jump_view({ model.mp_workspace->index(), Workspace::ViewSelector::SelectionCriterium::AtMain - })) + })), + .repeatable = false + } }, { { XKB_KEY_slash, MODKEY }, - CALL(jump_view({ + { + .action = CALL(jump_view({ model.mp_workspace->index(), Workspace::ViewSelector::SelectionCriterium::AtLast - })) + })), + .repeatable = false + } }, // external commands { { XKB_KEY_XF86AudioPlay, {} }, - CALL_EXTERNAL(playerctl play-pause) + { + .action = CALL_EXTERNAL(playerctl play-pause), + .repeatable = false + } }, { { XKB_KEY_p, MODKEY | SECKEY }, - CALL_EXTERNAL(playerctl play-pause) + { + .action = CALL_EXTERNAL(playerctl play-pause), + .repeatable = false + } }, { { XKB_KEY_XF86AudioPrev, {} }, - CALL_EXTERNAL(playerctl previous) + { + .action = CALL_EXTERNAL(playerctl previous), + .repeatable = false + } }, { { XKB_KEY_k, MODKEY | SECKEY }, - CALL_EXTERNAL(playerctl previous) + { + .action = CALL_EXTERNAL(playerctl previous), + .repeatable = false + } }, { { XKB_KEY_XF86AudioNext, {} }, - CALL_EXTERNAL(playerctl next) + { + .action = CALL_EXTERNAL(playerctl next), + .repeatable = false + } }, { { XKB_KEY_j, MODKEY | SECKEY }, - CALL_EXTERNAL(playerctl next) + { + .action = CALL_EXTERNAL(playerctl next), + .repeatable = false + } }, { { XKB_KEY_XF86AudioStop, {} }, - CALL_EXTERNAL(playerctl stop) + { + .action = CALL_EXTERNAL(playerctl stop), + .repeatable = false + } }, { { XKB_KEY_BackSpace, MODKEY | SECKEY }, - CALL_EXTERNAL(playerctl stop) + { + .action = CALL_EXTERNAL(playerctl stop), + .repeatable = false + } }, { { XKB_KEY_XF86AudioMute, {} }, - CALL_EXTERNAL(amixer -D pulse sset Master toggle) + { + .action = CALL_EXTERNAL(amixer -D pulse sset Master toggle), + .repeatable = false + } }, { { XKB_KEY_XF86AudioLowerVolume, {} }, - CALL_EXTERNAL(amixer -D pulse sset Master 5%-) + { + .action = CALL_EXTERNAL(amixer -D pulse sset Master 5%-), + .repeatable = true + } }, { { XKB_KEY_XF86AudioRaiseVolume, {} }, - CALL_EXTERNAL(amixer -D pulse sset Master 5%+) + { + .action = CALL_EXTERNAL(amixer -D pulse sset Master 5%+), + .repeatable = true + } }, { { XKB_KEY_XF86AudioMute, WLR_MODIFIER_SHIFT }, - CALL_EXTERNAL(amixer -D pulse sset Capture toggle) + { + .action = CALL_EXTERNAL(amixer -D pulse sset Capture toggle), + .repeatable = false + } }, { { XKB_KEY_XF86AudioMicMute, {} }, - CALL_EXTERNAL(amixer -D pulse sset Capture toggle) + { + .action = CALL_EXTERNAL(amixer -D pulse sset Capture toggle), + .repeatable = false + } }, { { XKB_KEY_space, WLR_MODIFIER_CTRL }, - CALL_EXTERNAL(dunstctl close) + { + .action = CALL_EXTERNAL(dunstctl close), + .repeatable = false + } }, { { XKB_KEY_space, WLR_MODIFIER_CTRL | WLR_MODIFIER_SHIFT }, - CALL_EXTERNAL(dunstctl close-all) + { + .action = CALL_EXTERNAL(dunstctl close-all), + .repeatable = false + } }, { { XKB_KEY_less, WLR_MODIFIER_CTRL | WLR_MODIFIER_SHIFT }, - CALL_EXTERNAL(dunstctl history-pop) + { + .action = CALL_EXTERNAL(dunstctl history-pop), + .repeatable = false + } }, { { XKB_KEY_Return, MODKEY }, - CALL_EXTERNAL(alacritty) + { + .action = CALL_EXTERNAL(alacritty), + .repeatable = false + } }, { { XKB_KEY_semicolon, MODKEY }, - CALL_EXTERNAL(nemo) + { + .action = CALL_EXTERNAL(nemo), + .repeatable = false + } }, { { XKB_KEY_p, MODKEY }, - CALL_EXTERNAL(rofi -show run) + { + .action = CALL_EXTERNAL(rofi -show run), + .repeatable = false + } }, { { XKB_KEY_q, MODKEY }, - CALL_EXTERNAL(qutebrowser) + { + .action = CALL_EXTERNAL(qutebrowser), + .repeatable = false + } }, { { XKB_KEY_Q, MODKEY | WLR_MODIFIER_SHIFT }, - CALL_EXTERNAL(firefox) + { + .action = CALL_EXTERNAL(firefox), + .repeatable = false + } }, { { XKB_KEY_q, MODKEY | WLR_MODIFIER_CTRL }, - CALL_EXTERNAL(chromium) + { + .action = CALL_EXTERNAL(chromium), + .repeatable = false + } }, { { XKB_KEY_apostrophe, MODKEY }, - CALL_EXTERNAL(blueberry) + { + .action = CALL_EXTERNAL(blueberry), + .repeatable = false + } }, { { XKB_KEY_Return, MODKEY | WLR_MODIFIER_SHIFT }, - CALL_EXTERNAL(alacritty --class "kranewl:cf,Alacritty") + { + .action = CALL_EXTERNAL(alacritty --class "kranewl:cf,Alacritty"), + .repeatable = false + } }, }; diff --git a/include/kranewl/input/keyboard.hh b/include/kranewl/input/keyboard.hh @@ -6,11 +6,19 @@ extern "C" { } #include <cstdint> +#include <functional> +#include <optional> #include <unordered_set> struct KeyboardInput { - xkb_keysym_t keysym; - uint32_t modifiers; + xkb_keysym_t keysym; + uint32_t modifiers; +}; + +class Model; +struct KeyboardAction { + std::function<void(Model&)> action; + bool repeatable; }; typedef class Server* Server_ptr; @@ -20,18 +28,25 @@ typedef struct Keyboard { Keyboard(Server_ptr, Seat_ptr, struct wlr_input_device*); ~Keyboard(); - static void handle_destroy(struct wl_listener*, void*); static void handle_modifiers(struct wl_listener*, void*); static void handle_key(struct wl_listener*, void*); + static int handle_key_repeat(void*); + static void handle_destroy(struct wl_listener*, void*); Server_ptr mp_server; - Seat_ptr mp_seat; + Seat_ptr mp_seat; - struct wlr_input_device* mp_device; + struct wlr_input_device* mp_device; + + uint32_t m_repeat_rate; + uint32_t m_repeat_delay; + + struct wl_event_source* mp_key_repeat_source; + std::optional<std::function<void(Model&)>> m_repeat_action; - struct wl_listener ml_destroy; struct wl_listener ml_modifiers; struct wl_listener ml_key; + struct wl_listener ml_destroy; }* Keyboard_ptr; diff --git a/src/kranewl/input/keyboard.cc b/src/kranewl/input/keyboard.cc @@ -7,6 +7,7 @@ #include <kranewl/util.hh> extern "C" { +#include <wayland-server-core.h> #include <wlr/types/wlr_idle.h> #include <wlr/types/wlr_input_device.h> #include <wlr/types/wlr_input_inhibitor.h> @@ -18,10 +19,16 @@ Keyboard::Keyboard(Server_ptr server, Seat_ptr seat, struct wlr_input_device* de : mp_server(server), mp_seat(seat), mp_device(device), - ml_destroy({ .notify = handle_destroy }), ml_modifiers({ .notify = handle_modifiers }), - ml_key({ .notify = handle_key }) + ml_key({ .notify = handle_key }), + ml_destroy({ .notify = handle_destroy }) { + mp_key_repeat_source = wl_event_loop_add_timer( + server->mp_event_loop, + handle_key_repeat, + this + ); + wl_signal_add(&mp_device->keyboard->events.modifiers, &ml_modifiers); wl_signal_add(&mp_device->keyboard->events.key, &ml_key); wl_signal_add(&mp_device->events.destroy, &ml_destroy); @@ -31,13 +38,6 @@ Keyboard::~Keyboard() {} void -Keyboard::handle_destroy(struct wl_listener*, void*) -{ - TRACE(); - -} - -void Keyboard::handle_modifiers(struct wl_listener* listener, void*) { TRACE(); @@ -52,7 +52,13 @@ Keyboard::handle_modifiers(struct wl_listener* listener, void*) ); } -static inline bool +static inline void +perform_action(Model_ptr model, std::function<void(Model&)> action) +{ + action(*model); +} + +static inline std::optional<KeyboardAction> process_key_binding(Model_ptr model, KeyboardInput input) { TRACE(); @@ -60,11 +66,22 @@ process_key_binding(Model_ptr model, KeyboardInput input) auto binding = Util::const_retrieve(model->key_bindings(), input); if (binding) { - (*binding)(*model); - return true; + perform_action(model, binding->action); + return binding; } - return false; + return std::nullopt; +} + +static inline void +disarm_key_repeat_timer(Keyboard_ptr keyboard) +{ + if (!keyboard) + return; + + keyboard->m_repeat_action = std::nullopt; + if (wl_event_source_timer_update(keyboard->mp_key_repeat_source, 0) < 0) + spdlog::error("Could not disarm key repeat timer"); } void @@ -94,7 +111,9 @@ Keyboard::handle_key(struct wl_listener* listener, void* data) ); bool key_press_handled = false; - if (event->state == WL_KEYBOARD_KEY_STATE_PRESSED) { + switch (event->state) { + case WL_KEYBOARD_KEY_STATE_PRESSED: + { for (int i = 0; i < symcount; ++i) if (keysyms[i] >= XKB_KEY_XF86Switch_VT_1 && keysyms[i] <= XKB_KEY_XF86Switch_VT_12) @@ -111,16 +130,37 @@ Keyboard::handle_key(struct wl_listener* listener, void* data) return; } - if (!seat->mp_input_inhibit_manager->active_inhibitor) { - for (int i = 0; i < symcount; ++i) - key_press_handled |= process_key_binding( + if (!seat->mp_input_inhibit_manager->active_inhibitor) + for (int i = 0; i < symcount; ++i) { + std::optional<KeyboardAction> binding = process_key_binding( seat->mp_model, KeyboardInput{ keysyms[i], modifiers & ~WLR_MODIFIER_CAPS } ); - } + + if (binding && binding->repeatable + && keyboard->mp_device->keyboard->repeat_info.delay > 0) + { + keyboard->m_repeat_action = binding->action; + if (wl_event_source_timer_update(keyboard->mp_key_repeat_source, + keyboard->mp_device->keyboard->repeat_info.delay) < 0) + { + spdlog::error("Could not set up key repeat timer"); + } + } else if (keyboard->m_repeat_action) + disarm_key_repeat_timer(keyboard); + + key_press_handled |= binding != std::nullopt; + } + + break; + } + case WL_KEYBOARD_KEY_STATE_RELEASED: + disarm_key_repeat_timer(keyboard); + break; + default: break; } if (!key_press_handled) { @@ -133,3 +173,47 @@ Keyboard::handle_key(struct wl_listener* listener, void* data) ); } } + +int +Keyboard::handle_key_repeat(void* data) +{ + Keyboard_ptr keyboard = reinterpret_cast<Keyboard_ptr>(data); + struct wlr_keyboard* wlr_device + = keyboard->mp_device->keyboard; + + if (keyboard->m_repeat_action) { + if (wlr_device->repeat_info.rate > 0) + if (wl_event_source_timer_update(keyboard->mp_key_repeat_source, + 1000 / wlr_device->repeat_info.rate) < 0) + { + spdlog::error("Could not update key repeat timer"); + } + + perform_action( + keyboard->mp_seat->mp_model, + *keyboard->m_repeat_action + ); + } + + return 0; +} + +void +Keyboard::handle_destroy(struct wl_listener* listener, void*) +{ + TRACE(); + + Keyboard_ptr keyboard = wl_container_of(listener, keyboard, ml_destroy); + Seat_ptr seat = keyboard->mp_seat; + + if (wlr_seat_get_keyboard(seat->mp_wlr_seat) == keyboard->mp_device->keyboard) + keyboard->mp_device->keyboard = nullptr; + + wl_list_remove(&keyboard->ml_key.link); + wl_list_remove(&keyboard->ml_modifiers.link); + + disarm_key_repeat_timer(keyboard); + wl_event_source_remove(keyboard->mp_key_repeat_source); + + seat->unregister_keyboard(keyboard); +} diff --git a/src/kranewl/input/seat.cc b/src/kranewl/input/seat.cc @@ -88,6 +88,7 @@ void Seat::unregister_keyboard(Keyboard_ptr keyboard) { Util::erase_remove(m_keyboards, keyboard); + delete keyboard; } void