diff --git a/src/input_handler.cc b/src/input_handler.cc index 08412a02..7b6339ff 100644 --- a/src/input_handler.cc +++ b/src/input_handler.cc @@ -49,6 +49,45 @@ namespace InputModes static constexpr std::chrono::milliseconds idle_timeout{50}; static constexpr std::chrono::milliseconds fs_check_timeout{500}; +struct MouseHandler +{ + bool handle_key(Key key, Context& context) + { + if (not context.has_window()) + return false; + + if (key.modifiers == Key::Modifiers::MousePress) + { + m_dragging = true; + m_anchor = context.window().buffer_coord(key.mouse_coord()); + context.selections() = SelectionList{ context.buffer(), m_anchor }; + return true; + } + if (key.modifiers == Key::Modifiers::MouseRelease) + { + if (not m_dragging) + return true; + m_dragging = false; + auto cursor = context.window().buffer_coord(key.mouse_coord()); + context.selections() = SelectionList{ context.buffer(), Selection{m_anchor, cursor} }; + return true; + } + if (key.modifiers == Key::Modifiers::MousePos) + { + if (not m_dragging) + return true; + auto cursor = context.window().buffer_coord(key.mouse_coord()); + context.selections() = SelectionList{ context.buffer(), Selection{m_anchor, cursor} }; + return true; + } + return false; + } + +private: + bool m_dragging = false; + ByteCoord m_anchor; +}; + class Normal : public InputMode { public: @@ -87,6 +126,9 @@ public: void on_key(Key key) override { + if (m_mouse_handler.handle_key(key, context())) + return; + if (m_waiting_for_reg) { if (key.modifiers == Key::Modifiers::None) @@ -139,6 +181,7 @@ public: } m_params = { 0, '"' }; } + context().hooks().run_hook("NormalKey", key_to_str(key), context()); m_idle_timer.set_next_date(Clock::now() + idle_timeout); } @@ -167,6 +210,7 @@ private: bool m_waiting_for_reg = false; Timer m_idle_timer; Timer m_fs_check_timer; + MouseHandler m_mouse_handler; }; template @@ -1109,7 +1153,8 @@ void InputHandler::on_next_key(KeymapMode keymap_mode, KeyCallback callback) static bool is_valid(Key key) { - return key != Key::Invalid and key.key <= 0x10FFFF; + return key != Key::Invalid and + ((key.modifiers & ~Key::Modifiers::ControlAlt) or key.key <= 0x10FFFF); } void InputHandler::handle_key(Key key) diff --git a/src/keys.hh b/src/keys.hh index c83e1361..54c6e175 100644 --- a/src/keys.hh +++ b/src/keys.hh @@ -5,6 +5,7 @@ #include "flags.hh" #include "hash.hh" #include "vector.hh" +#include "coord.hh" namespace Kakoune { @@ -16,7 +17,11 @@ struct Key None = 0, Control = 1 << 0, Alt = 1 << 1, - ControlAlt = Control | Alt + ControlAlt = Control | Alt, + + MousePress = 1 << 2, + MouseRelease = 1 << 3, + MousePos = 1 << 4, }; enum NamedKey : Codepoint { @@ -62,6 +67,8 @@ struct Key constexpr bool operator==(Key other) const { return val() == other.val(); } constexpr bool operator!=(Key other) const { return val() != other.val(); } constexpr bool operator<(Key other) const { return val() < other.val(); } + + constexpr CharCoord mouse_coord() const { return {(int)((key & 0xFFFF0000) >> 16), (int)(key & 0x0000FFFF)}; } }; template<> struct WithBitOps : std::true_type {}; @@ -78,6 +85,12 @@ constexpr Key alt(Codepoint key) { return { Key::Modifiers::Alt, key }; } constexpr Key ctrl(Codepoint key) { return { Key::Modifiers::Control, key }; } constexpr Key ctrlalt(Codepoint key) { return { Key::Modifiers::ControlAlt, key }; } +constexpr Codepoint encode_mouse_coord(CharCoord coord) { return (Codepoint)(((int)coord.line << 16) | ((int)coord.column & 0x0000FFFF)); } + +constexpr Key mouse_press(CharCoord pos) { return { Key::Modifiers::MousePress, encode_mouse_coord(pos) }; } +constexpr Key mouse_release(CharCoord pos) { return { Key::Modifiers::MouseRelease, encode_mouse_coord(pos) }; } +constexpr Key mouse_pos(CharCoord pos) { return { Key::Modifiers::MousePos, encode_mouse_coord(pos) }; } + inline size_t hash_value(const Key& key) { return hash_values(key.modifiers, key.key); } } diff --git a/src/ncurses_ui.cc b/src/ncurses_ui.cc index 13de9fd2..55dc3f75 100644 --- a/src/ncurses_ui.cc +++ b/src/ncurses_ui.cc @@ -260,6 +260,10 @@ NCursesUI::NCursesUI() signal(SIGWINCH, on_term_resize); signal(SIGINT, on_sigint); + mousemask(ALL_MOUSE_EVENTS | REPORT_MOUSE_POSITION, nullptr); + mouseinterval(0); + // force enable report mouse position + printf("\033[?1002h"); update_dimensions(); wrefresh(stdscr); @@ -267,6 +271,7 @@ NCursesUI::NCursesUI() NCursesUI::~NCursesUI() { + printf("\033[?1002l"); endwin(); signal(SIGWINCH, SIG_DFL); signal(SIGINT, SIG_DFL); @@ -442,6 +447,19 @@ Key NCursesUI::get_key() check_resize(); const int c = getch(); + + if (c == KEY_MOUSE) + { + MEVENT ev; + if (getmouse(&ev) == OK) + { + CharCoord pos{ ev.y, ev.x }; + if ((ev.bstate & BUTTON1_PRESSED) == BUTTON1_PRESSED) return mouse_press(pos); + if ((ev.bstate & BUTTON1_RELEASED) == BUTTON1_RELEASED) return mouse_release(pos); + else return mouse_pos(pos); + } + } + if (c > 0 and c < 27) { if (c == CTRL('l'))