diff options
author | Robin Haberkorn <robin.haberkorn@googlemail.com> | 2025-02-02 13:17:51 +0300 |
---|---|---|
committer | Robin Haberkorn <robin.haberkorn@googlemail.com> | 2025-02-16 02:20:39 +0300 |
commit | b87c56799ab6f6d651e1dc6c712a625545a4ad5f (patch) | |
tree | 726a36ede8cf7a9d310c4299f5fadef6398dcda0 /src/interface-curses | |
parent | 6c500d60eb7df65b0c71e9b0e0955ff581fc3f5a (diff) | |
download | sciteco-b87c56799ab6f6d651e1dc6c712a625545a4ad5f.tar.gz |
implemented mouse support via special ^KMOUSE and <EJ> with negative keys
* You need to set 0,64ED to enable mouse processing in Curses.
It is always enabled in Gtk as it should never make the experience worse.
sample.teco_ini enables mouse support, since this should be the new default.
`sciteco --no-profile` won't have it enabled, though.
* On curses, it requires the ncurses mouse protocol version 2, which will
also be supported by PDCurses.
* Similar to the Curses API, a special key macro ^KMOUSE is inserted if any of the supported
mouse events has been detected.
* You can then use -EJ to get the type of mouse event, which can be used
with a computed goto in the command-line editing macro.
Alternatively, this could have been solved with separate ^KMOUSE:PRESSED,
^KMOUSE:RELEASED etc. pseudo-key macros.
* The default ^KMOUSE implementation in fnkeys.tes supports the following:
* Left click: Edit command line to jump to position.
* Ctrl+left click: Jump to beginning of line.
* Right click: Insert position or position range (when dragging).
* Double right click: insert range for word under cursor
* Ctrl+right click: Insert beginning of line
* Scroll wheel: scrolls (faster with shift)
* Ctrl+scroll wheel: zoom (GTK-only)
* Currently, there is no visual feedback when "selecting" ranges
via right-click+drag.
This would be tricky to do and most terminal emulators do not appear
to support continuous mouse updates.
Diffstat (limited to 'src/interface-curses')
-rw-r--r-- | src/interface-curses/interface.c | 102 |
1 files changed, 102 insertions, 0 deletions
diff --git a/src/interface-curses/interface.c b/src/interface-curses/interface.c index c8daab9..fe2b1bb 100644 --- a/src/interface-curses/interface.c +++ b/src/interface-curses/interface.c @@ -53,6 +53,7 @@ * Some macros in term.h interfere with our code. */ #undef lines +#undef buttons #endif #include <Scintilla.h> @@ -688,6 +689,15 @@ teco_interface_init_interactive(GError **error) #endif /* + * Disables click-detection. + * If we'd want to discern PRESSED and CLICKED events, + * we'd have to emulate the same feature on GTK. + */ +#if NCURSES_MOUSE_VERSION >= 2 + mouseinterval(0); +#endif + + /* * We always have a CTRL handler on Windows, but doing it * here again, ensures that we have a higher precedence * than the one installed by PDCurses. @@ -1584,9 +1594,92 @@ teco_interface_refresh(void) doupdate(); } +#if NCURSES_MOUSE_VERSION >= 2 + +#define BUTTON_NUM(X) \ + (BUTTON##X##_PRESSED | BUTTON##X##_RELEASED | \ + BUTTON##X##_CLICKED | BUTTON##X##_DOUBLE_CLICKED | BUTTON##X##_TRIPLE_CLICKED) +#define BUTTON_EVENT(X) \ + (BUTTON1_##X | BUTTON2_##X | BUTTON3_##X | BUTTON4_##X | BUTTON5_##X) + +static gboolean +teco_interface_getmouse(void) +{ + MEVENT event; + WINDOW *current = teco_view_get_window(teco_interface_current_view); + + /* + * Return mouse coordinates relative to the view. + * They will be in characters, but that's what SCI_POSITIONFROMPOINT + * expects on Scinterm anyway. + */ + if (getmouse(&event) != OK || + !wmouse_trafo(current, &event.y, &event.x, FALSE)) + /* no event inside of current view */ + return FALSE; + + /* + * NOTE: There will only be one of the button bits + * set in bstate, so we don't loose information translating + * them to enums. + * + * At least on ncurses, we don't always get a RELEASED event. + * It instead sends only REPORT_MOUSE_POSITION, + * so make sure not to overwrite teco_mouse.button in this case. + */ + if (event.bstate & BUTTON_NUM(4)) + /* scroll up - there will be no RELEASED event */ + teco_mouse.type = TECO_MOUSE_SCROLLUP; + else if (event.bstate & BUTTON_NUM(5)) + /* scroll down - there will be no RELEASED event */ + teco_mouse.type = TECO_MOUSE_SCROLLDOWN; + else if (event.bstate & BUTTON_EVENT(RELEASED)) + teco_mouse.type = TECO_MOUSE_RELEASED; + else if (event.bstate & BUTTON_EVENT(PRESSED)) + teco_mouse.type = TECO_MOUSE_PRESSED; + else + /* can also be REPORT_MOUSE_POSITION */ + teco_mouse.type = TECO_MOUSE_RELEASED; + + teco_mouse.x = event.x; + teco_mouse.y = event.y; + + if (event.bstate & BUTTON_NUM(1)) + teco_mouse.button = 1; + else if (event.bstate & BUTTON_NUM(2)) + teco_mouse.button = 2; + else if (event.bstate & BUTTON_NUM(3)) + teco_mouse.button = 3; + else if (!(event.bstate & REPORT_MOUSE_POSITION)) + teco_mouse.button = -1; + + teco_mouse.mods = 0; + if (event.bstate & BUTTON_SHIFT) + teco_mouse.mods |= TECO_MOUSE_SHIFT; + if (event.bstate & BUTTON_CTRL) + teco_mouse.mods |= TECO_MOUSE_CTRL; + if (event.bstate & BUTTON_ALT) + teco_mouse.mods |= TECO_MOUSE_ALT; + + return TRUE; +} + +#endif /* NCURSES_MOUSE_VERSION >= 2 */ + static gint teco_interface_blocking_getch(void) { +#if NCURSES_MOUSE_VERSION >= 2 + /* + * FIXME: REPORT_MOUSE_POSITION is necessary at least on + * ncurses, so that BUTTONX_RELEASED events are reported. + * It does NOT report every cursor movement, though. + * What does PDCurses do? + */ + mousemask(teco_ed & TECO_ED_MOUSEKEY + ? ALL_MOUSE_EVENTS | REPORT_MOUSE_POSITION : 0, NULL); +#endif + /* no special <CTRL/C> handling */ raw(); nodelay(teco_interface.input_pad, FALSE); @@ -1697,6 +1790,15 @@ teco_interface_event_loop_iter(void) #undef FNS #undef FN +#if NCURSES_MOUSE_VERSION >= 2 + case KEY_MOUSE: + /* ANY of the mouse events */ + if (teco_interface_getmouse() && + !teco_cmdline_keymacro("MOUSE", -1, error)) + return; + break; +#endif + /* * Control keys and keys with printable representation */ |