diff options
| author | Maxime Coste <mawww@kakoune.org> | 2020-06-28 19:48:55 +1000 |
|---|---|---|
| committer | Maxime Coste <mawww@kakoune.org> | 2020-06-28 19:48:55 +1000 |
| commit | d3374e7e5f7af9f4fdf33200f91847b3cddf9e67 (patch) | |
| tree | 8a70ba5491447a5dfb7b565be242757ab470042f /src | |
| parent | fc3e5ea419aa79c7adf38a9252586d867b3eb19b (diff) | |
Refactor mouse press/release handling to support 3 buttons
Change button to be an additional parameter instead of having separate
events for left/right buttons.
Fixes #3471
Diffstat (limited to 'src')
| -rw-r--r-- | src/input_handler.cc | 51 | ||||
| -rw-r--r-- | src/json_ui.cc | 37 | ||||
| -rw-r--r-- | src/keys.cc | 33 | ||||
| -rw-r--r-- | src/keys.hh | 20 | ||||
| -rw-r--r-- | src/ncurses_ui.cc | 23 |
5 files changed, 96 insertions, 68 deletions
diff --git a/src/input_handler.cc b/src/input_handler.cc index 2773c482..f13c513e 100644 --- a/src/input_handler.cc +++ b/src/input_handler.cc @@ -92,35 +92,40 @@ struct MouseHandler Buffer& buffer = context.buffer(); BufferCoord cursor; auto& selections = context.selections(); - constexpr auto modifiers = Key::Modifiers::Control | Key::Modifiers::Alt | Key::Modifiers::Shift; + constexpr auto modifiers = Key::Modifiers::Control | Key::Modifiers::Alt | Key::Modifiers::Shift | Key::Modifiers::MouseButtonMask; switch ((key.modifiers & ~modifiers).value) { - case Key::Modifiers::MousePressRight: - m_dragging = false; - cursor = context.window().buffer_coord(key.coord()); - if (key.modifiers & Key::Modifiers::Control) - selections = {{selections.begin()->anchor(), cursor}}; - else - selections.main() = {selections.main().anchor(), cursor}; - selections.sort_and_merge_overlapping(); - return true; - - case Key::Modifiers::MousePressLeft: - m_dragging = true; - m_anchor = context.window().buffer_coord(key.coord()); - if (not (key.modifiers & Key::Modifiers::Control)) - context.selections_write_only() = { buffer, m_anchor}; - else + case Key::Modifiers::MousePress: + switch (key.mouse_button()) { - size_t main = selections.size(); - selections.push_back({m_anchor}); - selections.set_main_index(main); + case Key::MouseButton::Right: + m_dragging = false; + cursor = context.window().buffer_coord(key.coord()); + if (key.modifiers & Key::Modifiers::Control) + selections = {{selections.begin()->anchor(), cursor}}; + else + selections.main() = {selections.main().anchor(), cursor}; selections.sort_and_merge_overlapping(); + return true; + + case Key::MouseButton::Left: + m_dragging = true; + m_anchor = context.window().buffer_coord(key.coord()); + if (not (key.modifiers & Key::Modifiers::Control)) + context.selections_write_only() = { buffer, m_anchor}; + else + { + size_t main = selections.size(); + selections.push_back({m_anchor}); + selections.set_main_index(main); + selections.sort_and_merge_overlapping(); + } + return true; + + default: return true; } - return true; - case Key::Modifiers::MouseReleaseLeft: - case Key::Modifiers::MouseReleaseRight: + case Key::Modifiers::MouseRelease: if (not m_dragging) return true; m_dragging = false; diff --git a/src/json_ui.cc b/src/json_ui.cc index b4c6528c..007c8ab0 100644 --- a/src/json_ui.cc +++ b/src/json_ui.cc @@ -248,31 +248,30 @@ void JsonUI::eval_json(const Value& json) m_on_key(key); } } - else if (method == "mouse") + else if (method == "mouse_move") + { + if (params.size() != 2) + throw invalid_rpc_request("mouse coordinates not specified"); + + if (not params[0].is_a<int>() or not params[1].is_a<int>()) + throw invalid_rpc_request("mouse coordinates are not integers"); + + m_on_key({Key::Modifiers::MousePos, encode_coord({params[0].as<int>(), params[1].as<int>()})}); + } + else if (method == "mouse_press" or method == "mouse_release") { if (params.size() != 3) - throw invalid_rpc_request("mouse type/coordinates not specified"); + throw invalid_rpc_request("mouse button/coordinates not specified"); if (not params[0].is_a<String>()) - throw invalid_rpc_request("mouse type is not a string"); - else if (not params[1].is_a<int>() or - not params[2].is_a<int>()) + throw invalid_rpc_request("mouse button is not a string"); + if (not params[1].is_a<int>() or not params[2].is_a<int>()) throw invalid_rpc_request("mouse coordinates are not integers"); - const StringView type = params[0].as<String>(); - const Codepoint coord = encode_coord({params[1].as<int>(), params[2].as<int>()}); - if (type == "move") - m_on_key({Key::Modifiers::MousePos, coord}); - else if (type == "press_left") - m_on_key({Key::Modifiers::MousePressLeft, coord}); - else if (type == "press_right") - m_on_key({Key::Modifiers::MousePressRight, coord}); - else if (type == "release_left") - m_on_key({Key::Modifiers::MouseReleaseLeft, coord}); - else if (type == "release_right") - m_on_key({Key::Modifiers::MouseReleaseRight, coord}); - else - throw invalid_rpc_request(format("invalid mouse event type: {}", type)); + auto event = method == "mouse_press" ? Key::Modifiers::MousePress : Key::Modifiers::MouseRelease; + auto button = str_to_button(params[0].as<String>()); + + m_on_key({event | Key::to_modifier(button), encode_coord({params[1].as<int>(), params[2].as<int>()})}); } else if (method == "scroll") { diff --git a/src/keys.cc b/src/keys.cc index 90cb0310..29fa9ce1 100644 --- a/src/keys.cc +++ b/src/keys.cc @@ -157,21 +157,36 @@ KeyList parse_keys(StringView str) return result; } +StringView button_to_str(Key::MouseButton button) +{ + switch (button) + { + case Key::MouseButton::Left: return "left"; + case Key::MouseButton::Middle: return "middle"; + case Key::MouseButton::Right: return "right"; + default: kak_assert(false); throw logic_error{}; + } +} + +Key::MouseButton str_to_button(StringView str) +{ + if (str == "left") return Key::MouseButton::Left; + if (str == "middle") return Key::MouseButton::Middle; + if (str == "right") return Key::MouseButton::Right; + throw runtime_error(format("invalid mouse button name {}", str)); +} + String key_to_str(Key key) { const auto coord = key.coord() + DisplayCoord{1,1}; - switch (key.modifiers) + switch (Key::Modifiers(key.modifiers & ~Key::Modifiers::MouseButtonMask)) { case Key::Modifiers::MousePos: return format("<mouse:move:{}.{}>", coord.line, coord.column); - case Key::Modifiers::MousePressLeft: - return format("<mouse:press_left:{}.{}>", coord.line, coord.column); - case Key::Modifiers::MousePressRight: - return format("<mouse:press_right:{}.{}>", coord.line, coord.column); - case Key::Modifiers::MouseReleaseLeft: - return format("<mouse:release_left:{}.{}>", coord.line, coord.column); - case Key::Modifiers::MouseReleaseRight: - return format("<mouse:release_right:{}.{}>", coord.line, coord.column); + case Key::Modifiers::MousePress: + return format("<mouse:press:{}:{}.{}>", button_to_str(key.mouse_button()), coord.line, coord.column); + case Key::Modifiers::MouseRelease: + return format("<mouse:release:{}:{}.{}>", button_to_str(key.mouse_button()), coord.line, coord.column); case Key::Modifiers::Scroll: return format("<scroll:{}>", static_cast<int>(key.key)); case Key::Modifiers::Resize: diff --git a/src/keys.hh b/src/keys.hh index 84707faf..0f5fc0e7 100644 --- a/src/keys.hh +++ b/src/keys.hh @@ -14,6 +14,12 @@ namespace Kakoune struct Key { + enum class MouseButton + { + Left, + Middle, + Right + }; enum class Modifiers : int { None = 0, @@ -21,11 +27,11 @@ struct Key Alt = 1 << 1, Shift = 1 << 2, - MousePressLeft = 1 << 3, - MousePressRight = 1 << 4, - MouseReleaseLeft = 1 << 5, - MouseReleaseRight = 1 << 6, - MousePos = 1 << 7, + MousePress = 1 << 3, + MouseRelease = 1 << 4, + MousePos = 1 << 5, + MouseButtonMask= 0b11 << 6, + Scroll = 1 << 8, Resize = 1 << 9, MenuSelect = 1 << 10, @@ -82,6 +88,8 @@ struct Key constexpr bool operator<(Key other) const { return val() < other.val(); } constexpr DisplayCoord coord() const { return {(int)((key & 0xFFFF0000) >> 16), (int)(key & 0x0000FFFF)}; } + constexpr MouseButton mouse_button() { return MouseButton{((int)modifiers & (int)Modifiers::MouseButtonMask) >> 6}; } + static Modifiers to_modifier(MouseButton button) { return Key::Modifiers{((int)button << 6) & (int)Modifiers::MouseButtonMask}; } Optional<Codepoint> codepoint() const; }; @@ -95,6 +103,8 @@ class StringView; KeyList parse_keys(StringView str); String key_to_str(Key key); +StringView button_to_str(Key::MouseButton button); +Key::MouseButton str_to_button(StringView str); constexpr Key shift(Key key) { diff --git a/src/ncurses_ui.cc b/src/ncurses_ui.cc index 0f37abfd..f54a244a 100644 --- a/src/ncurses_ui.cc +++ b/src/ncurses_ui.cc @@ -19,6 +19,7 @@ #include <csignal> #include <sys/ioctl.h> #include <unistd.h> +#include <strings.h> constexpr char control(char c) { return c & 037; } @@ -669,19 +670,19 @@ Optional<Key> NCursesUI::get_next_key() return mod; }; - auto mouse_button = [this](Key::Modifiers mod, Codepoint coord, bool left, bool release) { - auto mask = left ? 0x1 : 0x2; + auto mouse_button = [this](Key::Modifiers mod, Key::MouseButton button, Codepoint coord, bool release) { + auto mask = 1 << (int)button; if (not release) { - mod |= (m_mouse_state & mask) ? Key::Modifiers::MousePos : (left ? Key::Modifiers::MousePressLeft : Key::Modifiers::MousePressRight); + mod |= (m_mouse_state & mask) ? Key::Modifiers::MousePos : Key::Modifiers::MousePress; m_mouse_state |= mask; } else { - mod |= left ? Key::Modifiers::MouseReleaseLeft : Key::Modifiers::MouseReleaseRight; + mod |= Key::Modifiers::MouseRelease; m_mouse_state &= ~mask; } - return Key{mod, coord}; + return Key{mod | Key::to_modifier(button), coord}; }; auto mouse_scroll = [this](Key::Modifiers mod, bool down) -> Key { @@ -752,17 +753,15 @@ Optional<Key> NCursesUI::get_next_key() const int y = (sgr ? params[2] : next_char() - 32) - 1; auto coord = encode_coord({y - content_line_offset(), x}); Key::Modifiers mod = parse_mask((b >> 2) & 0x7); - switch (b & 0x43) + switch (auto code = b & 0x43; code) { - case 0: return mouse_button(mod, coord, true, c == 'm'); - case 2: return mouse_button(mod, coord, false, c == 'm'); + case 0: case 1: case 2: + return mouse_button(mod, Key::MouseButton{code}, coord, c == 'm'); case 3: if (sgr) return {}; - if (m_mouse_state & 0x1) - return mouse_button(mod, coord, true, true); - else if (m_mouse_state & 0x2) - return mouse_button(mod, coord, false, true); + else if (int guess = ffs(m_mouse_state) - 1; 0 <= guess and guess < 3) + return mouse_button(mod, Key::MouseButton{guess}, coord, true); break; case 64: return mouse_scroll(mod, false); case 65: return mouse_scroll(mod, true); |
