Skip to content

Commit

Permalink
VT: add mouse support (fix #1427)
Browse files Browse the repository at this point in the history
  • Loading branch information
elfmz committed Nov 27, 2022
1 parent 5dd8c1e commit ed2c198
Show file tree
Hide file tree
Showing 10 changed files with 163 additions and 28 deletions.
5 changes: 4 additions & 1 deletion WinPort/src/Backend/TTY/TTYInputSequenceParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions far2l/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
16 changes: 8 additions & 8 deletions far2l/bootstrap/scripts/farlang.templ.m4
Original file line number Diff line number Diff line change
Expand Up @@ -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+Вниз"
Expand Down
24 changes: 24 additions & 0 deletions far2l/src/vt/IVTShell.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#pragma once
#include <string>

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;
};
2 changes: 1 addition & 1 deletion far2l/src/vt/VTFar2lExtensios.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#include <StackSerializer.h>
#include <string>
#include <set>
#include "vtansi.h"
#include "IVTShell.h"

class VTFar2lExtensios
{
Expand Down
9 changes: 9 additions & 0 deletions far2l/src/vt/vtansi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
11 changes: 1 addition & 10 deletions far2l/src/vt/vtansi.h
Original file line number Diff line number Diff line change
@@ -1,15 +1,6 @@
#pragma once
#include <string>

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
{
Expand Down
33 changes: 25 additions & 8 deletions far2l/src/vt/vtshell.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 <termios.h>
Expand Down Expand Up @@ -80,7 +81,8 @@ class VTShell : VTOutputReader::IProcessor, VTInputReader::IProcessor, IVTShell
std::atomic<bool> _bracketed_paste_expected{false};
INPUT_RECORD _last_window_info_ir;
std::unique_ptr<VTFar2lExtensios> _far2l_exts;
std::mutex _far2l_exts_mutex, _write_term_mutex;
std::unique_ptr<VTMouse> _mouse;
std::mutex _read_state_mutex, _write_term_mutex;

std::string _start_marker, _exit_marker;
unsigned int _exit_code;
Expand Down Expand Up @@ -325,9 +327,12 @@ class VTShell : VTOutputReader::IProcessor, VTInputReader::IProcessor, IVTShell
{
//fprintf(stderr, "OnInputMouse: %x\n", MouseEvent.dwEventFlags);
{
std::lock_guard<std::mutex> lock(_far2l_exts_mutex);
std::lock_guard<std::mutex> lock(_read_state_mutex);
if (_far2l_exts && _far2l_exts->OnInputMouse(MouseEvent))
return;

if (_mouse && _mouse->OnInputMouse(MouseEvent))
return;
}

if (MouseEvent.dwEventFlags & MOUSE_WHEELED) {
Expand Down Expand Up @@ -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<std::mutex> lock(_far2l_exts_mutex);
std::lock_guard<std::mutex> lock(_read_state_mutex);
if (_far2l_exts && _far2l_exts->OnInputKey(KeyEvent))
return;
}
Expand Down Expand Up @@ -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<std::mutex> 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;
Expand All @@ -478,20 +494,20 @@ class VTShell : VTOutputReader::IProcessor, VTInputReader::IProcessor, IVTShell
std::string reply;
switch (str[5]) {
case '1': {
std::lock_guard<std::mutex> lock(_far2l_exts_mutex);
std::lock_guard<std::mutex> lock(_read_state_mutex);
if (!_far2l_exts)
_far2l_exts.reset(new VTFar2lExtensios(this));

reply = "\x1b_far2lok\x07";
} break;

case '0': {
std::lock_guard<std::mutex> lock(_far2l_exts_mutex);
std::lock_guard<std::mutex> lock(_read_state_mutex);
_far2l_exts.reset();
} break;

case ':': {
std::lock_guard<std::mutex> lock(_far2l_exts_mutex);
std::lock_guard<std::mutex> lock(_read_state_mutex);
if (str[6] && _far2l_exts) {
VTAnsiSuspend vta_suspend(_vta);
StackSerializer stk_ser;
Expand Down Expand Up @@ -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<std::mutex> lock(_far2l_exts_mutex); // stop input readout
std::lock_guard<std::mutex> lock(_read_state_mutex); // stop input readout
SavedScreen saved_scr;
ScrBuf.FillBuf();
auto choice = Message(MSG_KEEPBACKGROUND, 3,
Expand Down Expand Up @@ -859,8 +875,9 @@ class VTShell : VTOutputReader::IProcessor, VTInputReader::IProcessor, IVTShell
_bracketed_paste_expected = false;
DeliverPendingWindowInfo();

std::lock_guard<std::mutex> lock(_far2l_exts_mutex);
std::lock_guard<std::mutex> lock(_read_state_mutex);
_far2l_exts.reset();
_mouse.reset();
return _exit_code;
}

Expand Down
77 changes: 77 additions & 0 deletions far2l/src/vt/vtshell_mouse.cpp
Original file line number Diff line number Diff line change
@@ -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;
}
13 changes: 13 additions & 0 deletions far2l/src/vt/vtshell_mouse.h
Original file line number Diff line number Diff line change
@@ -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);
};

0 comments on commit ed2c198

Please sign in to comment.