Make scrolling speed configurable

The UI now can send a 'Scroll' key, whose value is the scrolling
amount encoded as a signed integer. This replaces the MouseWheelUp
and MouseWheelDown keys.

The NCursesUI now has a ncurses_wheel_scroll_amount ui_option that
controls that amount, it can be negative to swap scrolling direction.

Fixes #3045
This commit is contained in:
Maxime Coste 2019-08-19 22:16:39 +10:00
parent f1047181cb
commit 2359df0f17
7 changed files with 68 additions and 82 deletions

View File

@ -92,8 +92,7 @@ struct MouseHandler
Buffer& buffer = context.buffer(); Buffer& buffer = context.buffer();
BufferCoord cursor; BufferCoord cursor;
auto& selections = context.selections(); auto& selections = context.selections();
const auto key_modifier = (Key::Modifiers)(key.modifiers & Key::Modifiers::MouseEvent); switch (key.modifiers)
switch (key_modifier)
{ {
case Key::Modifiers::MousePressRight: case Key::Modifiers::MousePressRight:
m_dragging = false; m_dragging = false;
@ -137,14 +136,9 @@ struct MouseHandler
selections.sort_and_merge_overlapping(); selections.sort_and_merge_overlapping();
return true; return true;
case Key::Modifiers::MouseWheelDown: case Key::Modifiers::Scroll:
m_dragging = false; m_dragging = false;
scroll_window(context, 3); scroll_window(context, static_cast<int32_t>(key.key));
return true;
case Key::Modifiers::MouseWheelUp:
m_dragging = false;
scroll_window(context, -3);
return true; return true;
default: return false; default: return false;
@ -232,16 +226,6 @@ public:
kak_assert(m_state != State::PopOnEnabled); kak_assert(m_state != State::PopOnEnabled);
ScopedSetBool set_in_on_key{m_in_on_key}; ScopedSetBool set_in_on_key{m_in_on_key};
// Hack to parse keys sent by terminals using the 8th bit to mark the
// meta key. In normal mode, give priority to a potential alt-key than
// the accentuated character.
if (not (key.modifiers & Key::Modifiers::MouseEvent) and
key.key >= 127 and key.key < 256)
{
key.modifiers |= Key::Modifiers::Alt;
key.key &= 0x7f;
}
bool do_restore_hooks = false; bool do_restore_hooks = false;
auto restore_hooks = on_scope_end([&, this]{ auto restore_hooks = on_scope_end([&, this]{
if (m_hooks_disabled and enabled() and do_restore_hooks) if (m_hooks_disabled and enabled() and do_restore_hooks)
@ -253,8 +237,6 @@ public:
const bool transient = context().flags() & Context::Flags::Draft; const bool transient = context().flags() & Context::Flags::Draft;
auto cp = key.codepoint();
if (m_mouse_handler.handle_key(key, context())) if (m_mouse_handler.handle_key(key, context()))
{ {
context().print_status({}); context().print_status({});
@ -264,7 +246,7 @@ public:
if (not transient) if (not transient)
m_idle_timer.set_next_date(Clock::now() + get_idle_timeout(context())); m_idle_timer.set_next_date(Clock::now() + get_idle_timeout(context()));
} }
else if (cp and isdigit(*cp)) else if (auto cp = key.codepoint(); cp and isdigit(*cp))
{ {
long long new_val = (long long)m_params.count * 10 + *cp - '0'; long long new_val = (long long)m_params.count * 10 + *cp - '0';
if (new_val > std::numeric_limits<int>::max()) if (new_val > std::numeric_limits<int>::max())
@ -310,6 +292,15 @@ public:
if (context().has_client()) if (context().has_client())
context().client().info_hide(); context().client().info_hide();
// Hack to parse keys sent by terminals using the 8th bit to mark the
// meta key. In normal mode, give priority to a potential alt-key than
// the accentuated character.
if (key.key >= 127 and key.key < 256)
{
key.modifiers |= Key::Modifiers::Alt;
key.key &= 0x7f;
}
do_restore_hooks = true; do_restore_hooks = true;
if (auto command = get_normal_command(key)) if (auto command = get_normal_command(key))
{ {

View File

@ -430,13 +430,18 @@ void JsonUI::eval_json(const Value& json)
m_on_key({Key::Modifiers::MouseReleaseLeft, coord}); m_on_key({Key::Modifiers::MouseReleaseLeft, coord});
else if (type == "release_right") else if (type == "release_right")
m_on_key({Key::Modifiers::MouseReleaseRight, coord}); m_on_key({Key::Modifiers::MouseReleaseRight, coord});
else if (type == "wheel_up")
m_on_key({Key::Modifiers::MouseWheelUp, coord});
else if (type == "wheel_down")
m_on_key({Key::Modifiers::MouseWheelDown, coord});
else else
throw invalid_rpc_request(format("invalid mouse event type: {}", type)); throw invalid_rpc_request(format("invalid mouse event type: {}", type));
} }
else if (method == "scroll")
{
if (params.size() != 1)
throw invalid_rpc_request("scroll needs an amount");
else if (not params[0].is_a<int>())
throw invalid_rpc_request("scroll amount is not an integer");
m_on_key({Key::Modifiers::Scroll, (Codepoint)params[0].as<int>()});
}
else if (method == "menu_select") else if (method == "menu_select")
{ {
if (params.size() != 1) if (params.size() != 1)

View File

@ -146,10 +146,8 @@ KeyList parse_keys(StringView str)
String key_to_str(Key key) String key_to_str(Key key)
{ {
if (auto mouse_event = (key.modifiers & Key::Modifiers::MouseEvent))
{
const auto coord = key.coord() + DisplayCoord{1,1}; const auto coord = key.coord() + DisplayCoord{1,1};
switch ((Key::Modifiers)mouse_event) switch (key.modifiers)
{ {
case Key::Modifiers::MousePos: case Key::Modifiers::MousePos:
return format("<mouse:move:{}.{}>", coord.line, coord.column); return format("<mouse:move:{}.{}>", coord.line, coord.column);
@ -161,17 +159,11 @@ String key_to_str(Key key)
return format("<mouse:release_left:{}.{}>", coord.line, coord.column); return format("<mouse:release_left:{}.{}>", coord.line, coord.column);
case Key::Modifiers::MouseReleaseRight: case Key::Modifiers::MouseReleaseRight:
return format("<mouse:release_right:{}.{}>", coord.line, coord.column); return format("<mouse:release_right:{}.{}>", coord.line, coord.column);
case Key::Modifiers::MouseWheelDown: case Key::Modifiers::Scroll:
return "<mouse:wheel_down>"; return format("<scroll:{}>", static_cast<int>(key.key));
case Key::Modifiers::MouseWheelUp: case Key::Modifiers::Resize:
return "<mouse:wheel_up>"; return format("<resize:{}.{}>", coord.line, coord.column);
default: kak_assert(false); default: break;
}
}
else if (key.modifiers == Key::Modifiers::Resize)
{
auto size = key.coord() + DisplayCoord{1,1};
return format("<resize:{}.{}>", size.line, size.column);
} }
bool named = false; bool named = false;

View File

@ -26,14 +26,9 @@ struct Key
MouseReleaseLeft = 1 << 5, MouseReleaseLeft = 1 << 5,
MouseReleaseRight = 1 << 6, MouseReleaseRight = 1 << 6,
MousePos = 1 << 7, MousePos = 1 << 7,
MouseWheelDown = 1 << 8, Scroll = 1 << 8,
MouseWheelUp = 1 << 9, Resize = 1 << 9,
MouseEvent = MousePressLeft | MousePressRight | MenuSelect = 1 << 10,
MouseReleaseLeft | MouseReleaseRight |
MousePos | MouseWheelDown | MouseWheelUp,
Resize = 1 << 10,
MenuSelect = 1 << 11,
}; };
enum NamedKey : Codepoint enum NamedKey : Codepoint
{ {

View File

@ -437,6 +437,7 @@ void register_options()
" ncurses_change_colors bool\n" " ncurses_change_colors bool\n"
" ncurses_wheel_up_button int\n" " ncurses_wheel_up_button int\n"
" ncurses_wheel_down_button int\n" " ncurses_wheel_down_button int\n"
" ncurses_wheel_scroll_amount int\n"
" ncurses_shift_function_key int\n" " ncurses_shift_function_key int\n"
" ncurses_builtin_key_parser bool\n", " ncurses_builtin_key_parser bool\n",
UserInterface::Options{}); UserInterface::Options{});

View File

@ -556,31 +556,28 @@ Optional<Key> NCursesUI::get_next_key()
MEVENT ev; MEVENT ev;
if (getmouse(&ev) == OK) if (getmouse(&ev) == OK)
{ {
auto get_modifiers = [this](mmask_t mask) { const auto mask = ev.bstate;
Key::Modifiers res{}; auto coord = encode_coord({ ev.y - content_line_offset(), ev.x });
Key::Modifiers mod{};
if (mask & BUTTON_CTRL) if (mask & BUTTON_CTRL)
res |= Key::Modifiers::Control; mod |= Key::Modifiers::Control;
if (mask & BUTTON_ALT) if (mask & BUTTON_ALT)
res |= Key::Modifiers::Alt; mod |= Key::Modifiers::Alt;
if (BUTTON_PRESS(mask, 1)) if (BUTTON_PRESS(mask, 1))
return res | Key::Modifiers::MousePressLeft; return Key{mod | Key::Modifiers::MousePressLeft, coord};
if (BUTTON_PRESS(mask, 3)) if (BUTTON_PRESS(mask, 3))
return res | Key::Modifiers::MousePressRight; return Key{mod | Key::Modifiers::MousePressRight, coord};
if (BUTTON_RELEASE(mask, 1)) if (BUTTON_RELEASE(mask, 1))
return res | Key::Modifiers::MouseReleaseLeft; return Key{mod | Key::Modifiers::MouseReleaseLeft, coord};
if (BUTTON_RELEASE(mask, 3)) if (BUTTON_RELEASE(mask, 3))
return res | Key::Modifiers::MouseReleaseRight; return Key{mod | Key::Modifiers::MouseReleaseRight, coord};
if (BUTTON_PRESS(mask, m_wheel_down_button)) if (BUTTON_PRESS(mask, m_wheel_down_button))
return res | Key::Modifiers::MouseWheelDown; return Key{mod | Key::Modifiers::Scroll, static_cast<Codepoint>(m_wheel_scroll_amount)};
if (BUTTON_PRESS(mask, m_wheel_up_button)) if (BUTTON_PRESS(mask, m_wheel_up_button))
return res | Key::Modifiers::MouseWheelUp; return Key{mod | Key::Modifiers::Scroll, static_cast<Codepoint>(-m_wheel_scroll_amount)};
return res | Key::Modifiers::MousePos; return Key{mod | Key::Modifiers::MousePos, coord};
};
return Key{ get_modifiers(ev.bstate),
encode_coord({ ev.y - content_line_offset(), ev.x }) };
} }
} }
@ -1278,6 +1275,10 @@ void NCursesUI::set_ui_options(const Options& options)
auto wheel_down_it = options.find("ncurses_wheel_down_button"_sv); auto wheel_down_it = options.find("ncurses_wheel_down_button"_sv);
m_wheel_down_button = wheel_down_it != options.end() ? m_wheel_down_button = wheel_down_it != options.end() ?
str_to_int_ifp(wheel_down_it->value).value_or(5) : 5; str_to_int_ifp(wheel_down_it->value).value_or(5) : 5;
auto wheel_scroll_amount_it = options.find("ncurses_wheel_scroll_amount"_sv);
m_wheel_scroll_amount = wheel_scroll_amount_it != options.end() ?
str_to_int_ifp(wheel_scroll_amount_it->value).value_or(3) : 3;
} }
{ {

View File

@ -140,6 +140,7 @@ private:
bool m_mouse_enabled = false; bool m_mouse_enabled = false;
int m_wheel_up_button = 4; int m_wheel_up_button = 4;
int m_wheel_down_button = 5; int m_wheel_down_button = 5;
int m_wheel_scroll_amount = 3;
static constexpr int default_shift_function_key = 12; static constexpr int default_shift_function_key = 12;
int m_shift_function_key = default_shift_function_key; int m_shift_function_key = default_shift_function_key;