mirror of
https://github.com/mawww/kakoune.git
synced 2024-12-24 20:13:00 +03:00
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
|
||||
* resize(int rows, int columns): notify ui resize
|
||||
* scroll(int amount): scroll by given line amount
|
||||
* mouse(String type, int line, int column): mouse event. line and column relate to
|
||||
the cursor position. type can be:
|
||||
- 'move'
|
||||
- 'press_left'
|
||||
- 'press_right'
|
||||
- 'release_left'
|
||||
- 'release_right'
|
||||
* mouse_move(int line, int column): line and column relate to the cursor position.
|
||||
* mouse_press(String button, int line, int column): line and column relate to
|
||||
cursor position, button can be 'left', 'middle' or 'right'
|
||||
* mouse_release(String button, int line, int column): same.
|
||||
* menu_select(int index): explicit select of given menu entry
|
||||
|
@ -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;
|
||||
return true;
|
||||
|
||||
case Key::Modifiers::MouseReleaseLeft:
|
||||
case Key::Modifiers::MouseReleaseRight:
|
||||
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;
|
||||
}
|
||||
|
||||
case Key::Modifiers::MouseRelease:
|
||||
if (not m_dragging)
|
||||
return true;
|
||||
m_dragging = false;
|
||||
|
@ -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() != 3)
|
||||
throw invalid_rpc_request("mouse type/coordinates not specified");
|
||||
if (params.size() != 2)
|
||||
throw invalid_rpc_request("mouse 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>())
|
||||
if (not params[0].is_a<int>() or not params[1].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));
|
||||
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 button/coordinates not specified");
|
||||
|
||||
if (not params[0].is_a<String>())
|
||||
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");
|
||||
|
||||
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")
|
||||
{
|
||||
|
33
src/keys.cc
33
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:
|
||||
|
20
src/keys.hh
20
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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user