summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMaxime Coste <mawww@kakoune.org>2020-06-28 19:48:55 +1000
committerMaxime Coste <mawww@kakoune.org>2020-06-28 19:48:55 +1000
commitd3374e7e5f7af9f4fdf33200f91847b3cddf9e67 (patch)
tree8a70ba5491447a5dfb7b565be242757ab470042f /src
parentfc3e5ea419aa79c7adf38a9252586d867b3eb19b (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.cc51
-rw-r--r--src/json_ui.cc37
-rw-r--r--src/keys.cc33
-rw-r--r--src/keys.hh20
-rw-r--r--src/ncurses_ui.cc23
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);