diff --git a/WinPort/src/Backend/TTY/TTYInputSequenceParser.cpp b/WinPort/src/Backend/TTY/TTYInputSequenceParser.cpp index f11f95ac0..33c085d86 100644 --- a/WinPort/src/Backend/TTY/TTYInputSequenceParser.cpp +++ b/WinPort/src/Backend/TTY/TTYInputSequenceParser.cpp @@ -521,7 +521,10 @@ void TTYInputSequenceParser::ParseMouse(char action, char col, char raw) _mouse.middle = true; break; - case '^': // right press + case '2': // right+middle press + ir.Event.MouseEvent.dwControlKeyState|= LEFT_CTRL_PRESSED; + + case '"': // right press if (now - _mouse.right_ts <= 500) { ir.Event.MouseEvent.dwEventFlags|= DOUBLE_CLICK; _mouse.right_ts = 0; diff --git a/far2l/CMakeLists.txt b/far2l/CMakeLists.txt index d60fe5708..1a345cfc7 100644 --- a/far2l/CMakeLists.txt +++ b/far2l/CMakeLists.txt @@ -131,6 +131,7 @@ src/vt/vtshell_translation.cpp src/vt/vtshell_compose.cpp src/vt/vtshell_leader.cpp src/vt/vtshell_ioreaders.cpp +src/vt/vtshell_mouse.cpp src/vt/vtlog.cpp src/vt/vtcompletor.cpp src/vt/VTFar2lExtensios.cpp diff --git a/far2l/bootstrap/scripts/farlang.templ.m4 b/far2l/bootstrap/scripts/farlang.templ.m4 index 5cdd78202..994c46050 100644 --- a/far2l/bootstrap/scripts/farlang.templ.m4 +++ b/far2l/bootstrap/scripts/farlang.templ.m4 @@ -5407,14 +5407,14 @@ upd:" Ctrl+Alt+Z - detach far2l application to background releasing terminal. " VTStartTipPendCmdMouse l: -" MouseScrollUp - автозавершающийся просмотр лога терминала. " -" MouseScrollUp - pause and open autoclosing viewer with console log. " -upd:" MouseScrollUp - pause and open autoclosing viewer with console log. " -upd:" MouseScrollUp - pause and open autoclosing viewer with console log. " -upd:" MouseScrollUp - pause and open autoclosing viewer with console log. " -upd:" MouseScrollUp - pause and open autoclosing viewer with console log. " -upd:" MouseScrollUp - pause and open autoclosing viewer with console log. " -" MouseScrollUp - перегляд лога терміналу, що завершується автоматично. " +" Ctrl+Shift+MouseScrollUp - автозавершающийся просмотр лога терминала. " +" Ctrl+Shift+MouseScrollUp - pause and open autoclosing viewer with console log. " +upd:" Ctrl+Shift+MouseScrollUp - pause and open autoclosing viewer with console log. " +upd:" Ctrl+Shift+MouseScrollUp - pause and open autoclosing viewer with console log. " +upd:" Ctrl+Shift+MouseScrollUp - pause and open autoclosing viewer with console log. " +upd:" Ctrl+Shift+MouseScrollUp - pause and open autoclosing viewer with console log. " +upd:" Ctrl+Shift+MouseScrollUp - pause and open autoclosing viewer with console log. " +" Ctrl+Shift+MouseScrollUp - перегляд лога терміналу, що завершується автоматично. " BookmarkBottom "Редактирование: Del,Ins,F4,Shift+Вверх,Shift+Вниз" diff --git a/far2l/src/vt/IVTShell.h b/far2l/src/vt/IVTShell.h new file mode 100644 index 000000000..c20163203 --- /dev/null +++ b/far2l/src/vt/IVTShell.h @@ -0,0 +1,24 @@ +#pragma once +#include + +enum MouseExpectation +{ + MEX_NONE = 0, + MEX_X10_MOUSE = 9, + MEX_VT200_MOUSE = 1000, + MEX_VT200_HIGHLIGHT_MOUSE = 1001, + MEX_BTN_EVENT_MOUSE = 1002, + MEX_ANY_EVENT_MOUSE = 1003 +}; + + +struct IVTShell +{ + virtual void OnMouseExpectation(MouseExpectation mex) = 0; + virtual void OnBracketedPasteExpectation(bool enabled) = 0; + virtual void OnApplicationProtocolCommand(const char *str) = 0; + virtual bool OnOSCommand(int id, std::string &str) = 0; + virtual void InjectInput(const char *str) = 0; + virtual void OnKeypadChange(unsigned char keypad) = 0; + virtual void OnTerminalResized() = 0; +}; diff --git a/far2l/src/vt/VTFar2lExtensios.h b/far2l/src/vt/VTFar2lExtensios.h index e46e6560e..0d85e58be 100644 --- a/far2l/src/vt/VTFar2lExtensios.h +++ b/far2l/src/vt/VTFar2lExtensios.h @@ -4,7 +4,7 @@ #include #include #include -#include "vtansi.h" +#include "IVTShell.h" class VTFar2lExtensios { diff --git a/far2l/src/vt/vtansi.cpp b/far2l/src/vt/vtansi.cpp index 41a12c179..f64f5fd2b 100644 --- a/far2l/src/vt/vtansi.cpp +++ b/far2l/src/vt/vtansi.cpp @@ -668,6 +668,15 @@ void InterpretEscSeq( void ) if (prefix2 == '?' && (suffix == 'h' || suffix == 'l')) { for (i = 0; i < es_argc; ++i) { switch (es_argv[i]) { + case MEX_X10_MOUSE: + case MEX_VT200_MOUSE: + case MEX_VT200_HIGHLIGHT_MOUSE: + case MEX_BTN_EVENT_MOUSE: + case MEX_ANY_EVENT_MOUSE: + if (g_vt_shell) + g_vt_shell->OnMouseExpectation( (suffix == 'h') ? (MouseExpectation)es_argv[i] : MEX_NONE ); + break; + // case 47: case 1047: // g_alternative_screen_buffer.Toggle(suffix == 'h'); // break; diff --git a/far2l/src/vt/vtansi.h b/far2l/src/vt/vtansi.h index 9679cd1f7..0a814ddec 100644 --- a/far2l/src/vt/vtansi.h +++ b/far2l/src/vt/vtansi.h @@ -1,15 +1,6 @@ #pragma once #include - -struct IVTShell -{ - virtual void OnBracketedPasteExpectation(bool enabled) = 0; - virtual void OnApplicationProtocolCommand(const char *str) = 0; - virtual bool OnOSCommand(int id, std::string &str) = 0; - virtual void InjectInput(const char *str) = 0; - virtual void OnKeypadChange(unsigned char keypad) = 0; - virtual void OnTerminalResized() = 0; -}; +#include "IVTShell.h" class VTAnsi { diff --git a/far2l/src/vt/vtshell.cpp b/far2l/src/vt/vtshell.cpp index 8a2531e56..be88225d5 100644 --- a/far2l/src/vt/vtshell.cpp +++ b/far2l/src/vt/vtshell.cpp @@ -30,6 +30,7 @@ #include "InterThreadCall.hpp" #include "vtshell_compose.h" #include "vtshell_ioreaders.h" +#include "vtshell_mouse.h" #include "../WinPort/src/SavedScreen.h" #define __USE_BSD #include @@ -80,7 +81,8 @@ class VTShell : VTOutputReader::IProcessor, VTInputReader::IProcessor, IVTShell std::atomic _bracketed_paste_expected{false}; INPUT_RECORD _last_window_info_ir; std::unique_ptr _far2l_exts; - std::mutex _far2l_exts_mutex, _write_term_mutex; + std::unique_ptr _mouse; + std::mutex _read_state_mutex, _write_term_mutex; std::string _start_marker, _exit_marker; unsigned int _exit_code; @@ -325,9 +327,12 @@ class VTShell : VTOutputReader::IProcessor, VTInputReader::IProcessor, IVTShell { //fprintf(stderr, "OnInputMouse: %x\n", MouseEvent.dwEventFlags); { - std::lock_guard lock(_far2l_exts_mutex); + std::lock_guard lock(_read_state_mutex); if (_far2l_exts && _far2l_exts->OnInputMouse(MouseEvent)) return; + + if (_mouse && _mouse->OnInputMouse(MouseEvent)) + return; } if (MouseEvent.dwEventFlags & MOUSE_WHEELED) { @@ -375,7 +380,7 @@ class VTShell : VTOutputReader::IProcessor, VTInputReader::IProcessor, IVTShell virtual void OnInputKey(const KEY_EVENT_RECORD &KeyEvent) //called from worker thread { { - std::lock_guard lock(_far2l_exts_mutex); + std::lock_guard lock(_read_state_mutex); if (_far2l_exts && _far2l_exts->OnInputKey(KeyEvent)) return; } @@ -467,6 +472,17 @@ class VTShell : VTOutputReader::IProcessor, VTInputReader::IProcessor, IVTShell _keypad = keypad; } + virtual void OnMouseExpectation(MouseExpectation mex) + { + fprintf(stderr, "VT::OnMouseExpectation: %u\n", mex); + + std::lock_guard lock(_read_state_mutex); + _mouse.reset(); + if (mex != MEX_NONE) { + _mouse.reset(new VTMouse(this, mex)); + } + } + virtual void OnBracketedPasteExpectation(bool enabled) { _bracketed_paste_expected = enabled; @@ -478,7 +494,7 @@ class VTShell : VTOutputReader::IProcessor, VTInputReader::IProcessor, IVTShell std::string reply; switch (str[5]) { case '1': { - std::lock_guard lock(_far2l_exts_mutex); + std::lock_guard lock(_read_state_mutex); if (!_far2l_exts) _far2l_exts.reset(new VTFar2lExtensios(this)); @@ -486,12 +502,12 @@ class VTShell : VTOutputReader::IProcessor, VTInputReader::IProcessor, IVTShell } break; case '0': { - std::lock_guard lock(_far2l_exts_mutex); + std::lock_guard lock(_read_state_mutex); _far2l_exts.reset(); } break; case ':': { - std::lock_guard lock(_far2l_exts_mutex); + std::lock_guard lock(_read_state_mutex); if (str[6] && _far2l_exts) { VTAnsiSuspend vta_suspend(_vta); StackSerializer stk_ser; @@ -561,7 +577,7 @@ class VTShell : VTOutputReader::IProcessor, VTInputReader::IProcessor, IVTShell if (!_allow_osc_clipset) { { VTAnsiSuspend vta_suspend(_vta); // preserve console state - std::lock_guard lock(_far2l_exts_mutex); // stop input readout + std::lock_guard lock(_read_state_mutex); // stop input readout SavedScreen saved_scr; ScrBuf.FillBuf(); auto choice = Message(MSG_KEEPBACKGROUND, 3, @@ -859,8 +875,9 @@ class VTShell : VTOutputReader::IProcessor, VTInputReader::IProcessor, IVTShell _bracketed_paste_expected = false; DeliverPendingWindowInfo(); - std::lock_guard lock(_far2l_exts_mutex); + std::lock_guard lock(_read_state_mutex); _far2l_exts.reset(); + _mouse.reset(); return _exit_code; } diff --git a/far2l/src/vt/vtshell_mouse.cpp b/far2l/src/vt/vtshell_mouse.cpp new file mode 100644 index 000000000..19c7d36df --- /dev/null +++ b/far2l/src/vt/vtshell_mouse.cpp @@ -0,0 +1,77 @@ +#include "headers.hpp" +#include "vtshell_mouse.h" + +#define BUTTONS_PRESS_MASK (FROM_LEFT_1ST_BUTTON_PRESSED | FROM_LEFT_2ND_BUTTON_PRESSED | RIGHTMOST_BUTTON_PRESSED) + +VTMouse::VTMouse(IVTShell *vtshell, MouseExpectation mex) + : _vtshell(vtshell), _mex(mex) +{ +} + +static constexpr char sClickMatrix[4][4] { // [Button] [Mods: none, ctrl, alt, ctrl+alt] + {'#', '3', '+', ';'}, // B_NONE (button released) + {' ', '0', '(', '8'}, // B_LEFT + {'!', '1', ')', '9'}, // B_MID + {'"', '2', '*', ':'}, // B_RIGHT +}; + +static constexpr char sMoveMatrix[4][4] { // [Button] [Mods: none, ctrl, alt, ctrl+alt] + {'C', 'S', 'K', '['}, // B_NONE (no button pressed) + {'@', 'P', 'H', 'X'}, // B_LEFT + {'A', 'Q', 'I', 'Y'}, // B_MID + {'B', 'R', 'J', 'Z'}, // B_RIGHT +}; + +static constexpr char sWheelMatrix[2][2] { // [Direction] [Mods: none, ctrl] + {'`', 'p'}, // UP + {'a', 'q'}, // DOWN +}; + +bool VTMouse::OnInputMouse(const MOUSE_EVENT_RECORD &MouseEvent) +{ + if (MouseEvent.dwControlKeyState & SHIFT_PRESSED) { + return false; // shift combinations reserved by VT + } + + if (MouseEvent.dwEventFlags & MOUSE_MOVED) { + if (_mex < MEX_VT200_HIGHLIGHT_MOUSE) + return true; + + if (_mex == MEX_VT200_HIGHLIGHT_MOUSE) { + if ( (MouseEvent.dwButtonState & BUTTONS_PRESS_MASK) == 0) + return true; + } + } + if (_mex == MEX_X10_MOUSE) { + if ( (MouseEvent.dwButtonState & BUTTONS_PRESS_MASK) == 0) + return true; + } + + unsigned int imod = 0, ibut = 0; + + if (MouseEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) imod|= 1; + if (MouseEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) imod|= 2; + + if (MouseEvent.dwButtonState & FROM_LEFT_1ST_BUTTON_PRESSED) ibut = 1; + else if (MouseEvent.dwButtonState & FROM_LEFT_2ND_BUTTON_PRESSED) ibut = 2; + else if (MouseEvent.dwButtonState & RIGHTMOST_BUTTON_PRESSED) ibut = 3; + + char seq[] = {0x1b, '[', 'M', 0 /* action */, + char('!' + std::min(MouseEvent.dwMousePosition.X, SHORT(0x7f - '!'))), + char('!' + std::min(MouseEvent.dwMousePosition.Y, SHORT(0x7f - '!'))), + 0}; + + if (MouseEvent.dwEventFlags & MOUSE_WHEELED) { + seq[3] = sWheelMatrix[ (MouseEvent.dwButtonState & 0x00010000) ? 0 : 1 ][ (imod & 1) ? 1 : 0 ]; + + } else if (MouseEvent.dwEventFlags & MOUSE_MOVED) { + seq[3] = sMoveMatrix[ibut][imod]; + + } else { + seq[3] = sClickMatrix[ibut][imod]; + } + fprintf(stderr, "MouseSeq: '%s'\n", &seq[1]); + + _vtshell->InjectInput(seq); + return true; +} diff --git a/far2l/src/vt/vtshell_mouse.h b/far2l/src/vt/vtshell_mouse.h new file mode 100644 index 000000000..34e3fb6b2 --- /dev/null +++ b/far2l/src/vt/vtshell_mouse.h @@ -0,0 +1,13 @@ +#pragma once +#include "IVTShell.h" + +class VTMouse +{ + IVTShell *_vtshell; + MouseExpectation _mex; + bool _last_btn_state{}; + +public: + VTMouse(IVTShell *vtshell, MouseExpectation mex); + bool OnInputMouse(const MOUSE_EVENT_RECORD &MouseEvent); +};