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
This commit is contained in:
parent
fc3e5ea419
commit
d3374e7e5f
|
@ -59,11 +59,8 @@ The requests that the json ui can interpret on stdin are:
|
||||||
* keys(String key1, String key2...): keystrokes
|
* keys(String key1, String key2...): keystrokes
|
||||||
* resize(int rows, int columns): notify ui resize
|
* resize(int rows, int columns): notify ui resize
|
||||||
* scroll(int amount): scroll by given line amount
|
* scroll(int amount): scroll by given line amount
|
||||||
* mouse(String type, int line, int column): mouse event. line and column relate to
|
* mouse_move(int line, int column): line and column relate to the cursor position.
|
||||||
the cursor position. type can be:
|
* mouse_press(String button, int line, int column): line and column relate to
|
||||||
- 'move'
|
cursor position, button can be 'left', 'middle' or 'right'
|
||||||
- 'press_left'
|
* mouse_release(String button, int line, int column): same.
|
||||||
- 'press_right'
|
|
||||||
- 'release_left'
|
|
||||||
- 'release_right'
|
|
||||||
* menu_select(int index): explicit select of given menu entry
|
* menu_select(int index): explicit select of given menu entry
|
||||||
|
|
|
@ -92,10 +92,13 @@ struct MouseHandler
|
||||||
Buffer& buffer = context.buffer();
|
Buffer& buffer = context.buffer();
|
||||||
BufferCoord cursor;
|
BufferCoord cursor;
|
||||||
auto& selections = context.selections();
|
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)
|
switch ((key.modifiers & ~modifiers).value)
|
||||||
{
|
{
|
||||||
case Key::Modifiers::MousePressRight:
|
case Key::Modifiers::MousePress:
|
||||||
|
switch (key.mouse_button())
|
||||||
|
{
|
||||||
|
case Key::MouseButton::Right:
|
||||||
m_dragging = false;
|
m_dragging = false;
|
||||||
cursor = context.window().buffer_coord(key.coord());
|
cursor = context.window().buffer_coord(key.coord());
|
||||||
if (key.modifiers & Key::Modifiers::Control)
|
if (key.modifiers & Key::Modifiers::Control)
|
||||||
|
@ -105,7 +108,7 @@ struct MouseHandler
|
||||||
selections.sort_and_merge_overlapping();
|
selections.sort_and_merge_overlapping();
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case Key::Modifiers::MousePressLeft:
|
case Key::MouseButton::Left:
|
||||||
m_dragging = true;
|
m_dragging = true;
|
||||||
m_anchor = context.window().buffer_coord(key.coord());
|
m_anchor = context.window().buffer_coord(key.coord());
|
||||||
if (not (key.modifiers & Key::Modifiers::Control))
|
if (not (key.modifiers & Key::Modifiers::Control))
|
||||||
|
@ -119,8 +122,10 @@ struct MouseHandler
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case Key::Modifiers::MouseReleaseLeft:
|
default: return true;
|
||||||
case Key::Modifiers::MouseReleaseRight:
|
}
|
||||||
|
|
||||||
|
case Key::Modifiers::MouseRelease:
|
||||||
if (not m_dragging)
|
if (not m_dragging)
|
||||||
return true;
|
return true;
|
||||||
m_dragging = false;
|
m_dragging = false;
|
||||||
|
|
|
@ -248,31 +248,30 @@ void JsonUI::eval_json(const Value& json)
|
||||||
m_on_key(key);
|
m_on_key(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (method == "mouse")
|
else if (method == "mouse_move")
|
||||||
{
|
{
|
||||||
if (params.size() != 3)
|
if (params.size() != 2)
|
||||||
throw invalid_rpc_request("mouse type/coordinates not specified");
|
throw invalid_rpc_request("mouse coordinates not specified");
|
||||||
|
|
||||||
if (not params[0].is_a<String>())
|
if (not params[0].is_a<int>() or not params[1].is_a<int>())
|
||||||
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 coordinates are not integers");
|
throw invalid_rpc_request("mouse coordinates are not integers");
|
||||||
|
|
||||||
const StringView type = params[0].as<String>();
|
m_on_key({Key::Modifiers::MousePos, encode_coord({params[0].as<int>(), params[1].as<int>()})});
|
||||||
const Codepoint coord = encode_coord({params[1].as<int>(), params[2].as<int>()});
|
}
|
||||||
if (type == "move")
|
else if (method == "mouse_press" or method == "mouse_release")
|
||||||
m_on_key({Key::Modifiers::MousePos, coord});
|
{
|
||||||
else if (type == "press_left")
|
if (params.size() != 3)
|
||||||
m_on_key({Key::Modifiers::MousePressLeft, coord});
|
throw invalid_rpc_request("mouse button/coordinates not specified");
|
||||||
else if (type == "press_right")
|
|
||||||
m_on_key({Key::Modifiers::MousePressRight, coord});
|
if (not params[0].is_a<String>())
|
||||||
else if (type == "release_left")
|
throw invalid_rpc_request("mouse button is not a string");
|
||||||
m_on_key({Key::Modifiers::MouseReleaseLeft, coord});
|
if (not params[1].is_a<int>() or not params[2].is_a<int>())
|
||||||
else if (type == "release_right")
|
throw invalid_rpc_request("mouse coordinates are not integers");
|
||||||
m_on_key({Key::Modifiers::MouseReleaseRight, coord});
|
|
||||||
else
|
auto event = method == "mouse_press" ? Key::Modifiers::MousePress : Key::Modifiers::MouseRelease;
|
||||||
throw invalid_rpc_request(format("invalid mouse event type: {}", type));
|
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")
|
else if (method == "scroll")
|
||||||
{
|
{
|
||||||
|
|
33
src/keys.cc
33
src/keys.cc
|
@ -157,21 +157,36 @@ KeyList parse_keys(StringView str)
|
||||||
return result;
|
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)
|
String key_to_str(Key key)
|
||||||
{
|
{
|
||||||
const auto coord = key.coord() + DisplayCoord{1,1};
|
const auto coord = key.coord() + DisplayCoord{1,1};
|
||||||
switch (key.modifiers)
|
switch (Key::Modifiers(key.modifiers & ~Key::Modifiers::MouseButtonMask))
|
||||||
{
|
{
|
||||||
case Key::Modifiers::MousePos:
|
case Key::Modifiers::MousePos:
|
||||||
return format("<mouse:move:{}.{}>", coord.line, coord.column);
|
return format("<mouse:move:{}.{}>", coord.line, coord.column);
|
||||||
case Key::Modifiers::MousePressLeft:
|
case Key::Modifiers::MousePress:
|
||||||
return format("<mouse:press_left:{}.{}>", coord.line, coord.column);
|
return format("<mouse:press:{}:{}.{}>", button_to_str(key.mouse_button()), coord.line, coord.column);
|
||||||
case Key::Modifiers::MousePressRight:
|
case Key::Modifiers::MouseRelease:
|
||||||
return format("<mouse:press_right:{}.{}>", coord.line, coord.column);
|
return format("<mouse:release:{}:{}.{}>", button_to_str(key.mouse_button()), 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::Scroll:
|
case Key::Modifiers::Scroll:
|
||||||
return format("<scroll:{}>", static_cast<int>(key.key));
|
return format("<scroll:{}>", static_cast<int>(key.key));
|
||||||
case Key::Modifiers::Resize:
|
case Key::Modifiers::Resize:
|
||||||
|
|
20
src/keys.hh
20
src/keys.hh
|
@ -14,6 +14,12 @@ namespace Kakoune
|
||||||
|
|
||||||
struct Key
|
struct Key
|
||||||
{
|
{
|
||||||
|
enum class MouseButton
|
||||||
|
{
|
||||||
|
Left,
|
||||||
|
Middle,
|
||||||
|
Right
|
||||||
|
};
|
||||||
enum class Modifiers : int
|
enum class Modifiers : int
|
||||||
{
|
{
|
||||||
None = 0,
|
None = 0,
|
||||||
|
@ -21,11 +27,11 @@ struct Key
|
||||||
Alt = 1 << 1,
|
Alt = 1 << 1,
|
||||||
Shift = 1 << 2,
|
Shift = 1 << 2,
|
||||||
|
|
||||||
MousePressLeft = 1 << 3,
|
MousePress = 1 << 3,
|
||||||
MousePressRight = 1 << 4,
|
MouseRelease = 1 << 4,
|
||||||
MouseReleaseLeft = 1 << 5,
|
MousePos = 1 << 5,
|
||||||
MouseReleaseRight = 1 << 6,
|
MouseButtonMask= 0b11 << 6,
|
||||||
MousePos = 1 << 7,
|
|
||||||
Scroll = 1 << 8,
|
Scroll = 1 << 8,
|
||||||
Resize = 1 << 9,
|
Resize = 1 << 9,
|
||||||
MenuSelect = 1 << 10,
|
MenuSelect = 1 << 10,
|
||||||
|
@ -82,6 +88,8 @@ struct Key
|
||||||
constexpr bool operator<(Key other) const { return val() < other.val(); }
|
constexpr bool operator<(Key other) const { return val() < other.val(); }
|
||||||
|
|
||||||
constexpr DisplayCoord coord() const { return {(int)((key & 0xFFFF0000) >> 16), (int)(key & 0x0000FFFF)}; }
|
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;
|
Optional<Codepoint> codepoint() const;
|
||||||
};
|
};
|
||||||
|
@ -95,6 +103,8 @@ class StringView;
|
||||||
|
|
||||||
KeyList parse_keys(StringView str);
|
KeyList parse_keys(StringView str);
|
||||||
String key_to_str(Key key);
|
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)
|
constexpr Key shift(Key key)
|
||||||
{
|
{
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include <csignal>
|
#include <csignal>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <strings.h>
|
||||||
|
|
||||||
constexpr char control(char c) { return c & 037; }
|
constexpr char control(char c) { return c & 037; }
|
||||||
|
|
||||||
|
@ -669,19 +670,19 @@ Optional<Key> NCursesUI::get_next_key()
|
||||||
return mod;
|
return mod;
|
||||||
};
|
};
|
||||||
|
|
||||||
auto mouse_button = [this](Key::Modifiers mod, Codepoint coord, bool left, bool release) {
|
auto mouse_button = [this](Key::Modifiers mod, Key::MouseButton button, Codepoint coord, bool release) {
|
||||||
auto mask = left ? 0x1 : 0x2;
|
auto mask = 1 << (int)button;
|
||||||
if (not release)
|
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;
|
m_mouse_state |= mask;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mod |= left ? Key::Modifiers::MouseReleaseLeft : Key::Modifiers::MouseReleaseRight;
|
mod |= Key::Modifiers::MouseRelease;
|
||||||
m_mouse_state &= ~mask;
|
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 {
|
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;
|
const int y = (sgr ? params[2] : next_char() - 32) - 1;
|
||||||
auto coord = encode_coord({y - content_line_offset(), x});
|
auto coord = encode_coord({y - content_line_offset(), x});
|
||||||
Key::Modifiers mod = parse_mask((b >> 2) & 0x7);
|
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 0: case 1: case 2:
|
||||||
case 2: return mouse_button(mod, coord, false, c == 'm');
|
return mouse_button(mod, Key::MouseButton{code}, coord, c == 'm');
|
||||||
case 3:
|
case 3:
|
||||||
if (sgr)
|
if (sgr)
|
||||||
return {};
|
return {};
|
||||||
if (m_mouse_state & 0x1)
|
else if (int guess = ffs(m_mouse_state) - 1; 0 <= guess and guess < 3)
|
||||||
return mouse_button(mod, coord, true, true);
|
return mouse_button(mod, Key::MouseButton{guess}, coord, true);
|
||||||
else if (m_mouse_state & 0x2)
|
|
||||||
return mouse_button(mod, coord, false, true);
|
|
||||||
break;
|
break;
|
||||||
case 64: return mouse_scroll(mod, false);
|
case 64: return mouse_scroll(mod, false);
|
||||||
case 65: return mouse_scroll(mod, true);
|
case 65: return mouse_scroll(mod, true);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user