From 09a0a9206af04d695d84ce65afb1310ad26edf89 Mon Sep 17 00:00:00 2001 From: elfmz Date: Sat, 14 Dec 2024 13:50:43 +0300 Subject: [PATCH 01/11] Update TTYBackend.cpp --- WinPort/src/Backend/TTY/TTYBackend.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/WinPort/src/Backend/TTY/TTYBackend.cpp b/WinPort/src/Backend/TTY/TTYBackend.cpp index f2e172e63..2117f3acb 100644 --- a/WinPort/src/Backend/TTY/TTYBackend.cpp +++ b/WinPort/src/Backend/TTY/TTYBackend.cpp @@ -369,6 +369,7 @@ void TTYBackend::WriterThread() { bool gone_background = false; try { + _focused = !_far2l_tty; // assume starting focused unless far2l_tty, this trick allows notification to work in best effort under old far2l that didnt support focus change notifications TTYOutput tty_out(_stdout, _far2l_tty, _norgb, _nodetect); DispatchPalette(tty_out); // DispatchTermResized(tty_out); @@ -959,7 +960,7 @@ void TTYBackend::OnConsoleExit() bool TTYBackend::OnConsoleIsActive() { - return false;//true; + return _focused; } void TTYBackend_OnTerminalDamaged(bool flush_input_queue) @@ -1082,6 +1083,16 @@ void TTYBackend::OnInspectKeyEvent(KEY_EVENT_RECORD &event) } } +void TTYBackend::OnFocusChange(bool focused) +{ + fprintf(stderr, "OnFocusChange: %u\n", (unsigned)!!focused); + _focused = focused; + INPUT_RECORD ir = {}; + ir.EventType = FOCUS_EVENT; + ir.Event.FocusEvent.bSetFocus = focused ? TRUE : FALSE; + g_winport_con_in->Enqueue(&ir, 1); +} + void TTYBackend::OnFar2lEvent(StackSerializer &stk_ser) { if (!_far2l_tty) { From bb650f009b7abd281a21b5bf379ba0da79fdea04 Mon Sep 17 00:00:00 2001 From: elfmz Date: Sat, 14 Dec 2024 13:50:55 +0300 Subject: [PATCH 02/11] Update TTYBackend.h --- WinPort/src/Backend/TTY/TTYBackend.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/WinPort/src/Backend/TTY/TTYBackend.h b/WinPort/src/Backend/TTY/TTYBackend.h index 77478b576..d4d6c46a1 100644 --- a/WinPort/src/Backend/TTY/TTYBackend.h +++ b/WinPort/src/Backend/TTY/TTYBackend.h @@ -66,6 +66,7 @@ class TTYBackend : IConsoleOutputBackend, ITTYInputSpecialSequenceHandler, IFar2 COORD _largest_window_size{}; std::atomic _largest_window_size_ready{false}; std::atomic _flush_input_queue{false}; + std::atomic _focused{true}; // assume starting focused struct BI : std::mutex { std::string flavor; } _backend_info; @@ -145,6 +146,7 @@ class TTYBackend : IConsoleOutputBackend, ITTYInputSpecialSequenceHandler, IFar2 // ITTYInputSpecialSequenceHandler virtual void OnUsingExtension(char extension); virtual void OnInspectKeyEvent(KEY_EVENT_RECORD &event); + virtual void OnFocusChange(bool focused); virtual void OnFar2lEvent(StackSerializer &stk_ser); virtual void OnFar2lReply(StackSerializer &stk_ser); virtual void OnInputBroken(); From 2b3c74eb3bc7c62dfc8a7d54a8e8d23fa433d727 Mon Sep 17 00:00:00 2001 From: elfmz Date: Sat, 14 Dec 2024 13:51:17 +0300 Subject: [PATCH 03/11] Update TTYInputSequenceParser.cpp --- WinPort/src/Backend/TTY/TTYInputSequenceParser.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/WinPort/src/Backend/TTY/TTYInputSequenceParser.cpp b/WinPort/src/Backend/TTY/TTYInputSequenceParser.cpp index 0aef72899..525f59d1a 100644 --- a/WinPort/src/Backend/TTY/TTYInputSequenceParser.cpp +++ b/WinPort/src/Backend/TTY/TTYInputSequenceParser.cpp @@ -314,6 +314,11 @@ size_t TTYInputSequenceParser::ParseEscapeSequence(const char *s, size_t l) fprintf(stderr, "\n"); */ + if (l > 1 && s[0] == '[' && (s[1] == 'I' || s[1] == 'O')) { // focus + _handler->OnFocusChange(s[1] == 'I'); + return 2; + } + if (l > 2 && s[0] == '[' && s[2] == 'n') { return 3; } From 8d44878b86adf98588c3137d9f72c1269d17a0dd Mon Sep 17 00:00:00 2001 From: elfmz Date: Sat, 14 Dec 2024 13:51:33 +0300 Subject: [PATCH 04/11] Update TTYInputSequenceParser.h --- WinPort/src/Backend/TTY/TTYInputSequenceParser.h | 1 + 1 file changed, 1 insertion(+) diff --git a/WinPort/src/Backend/TTY/TTYInputSequenceParser.h b/WinPort/src/Backend/TTY/TTYInputSequenceParser.h index 184390318..10bca76aa 100644 --- a/WinPort/src/Backend/TTY/TTYInputSequenceParser.h +++ b/WinPort/src/Backend/TTY/TTYInputSequenceParser.h @@ -67,6 +67,7 @@ struct ITTYInputSpecialSequenceHandler { virtual void OnUsingExtension(char extension) = 0; virtual void OnInspectKeyEvent(KEY_EVENT_RECORD &event) = 0; + virtual void OnFocusChange(bool focused) = 0; virtual void OnFar2lEvent(StackSerializer &stk_ser) = 0; virtual void OnFar2lReply(StackSerializer &stk_ser) = 0; virtual void OnInputBroken() = 0; From 771be637b4c2c8b6cb8e8fd5f2a68dbd2fc065ee Mon Sep 17 00:00:00 2001 From: elfmz Date: Sat, 14 Dec 2024 13:51:49 +0300 Subject: [PATCH 05/11] Update TTYOutput.cpp --- WinPort/src/Backend/TTY/TTYOutput.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/WinPort/src/Backend/TTY/TTYOutput.cpp b/WinPort/src/Backend/TTY/TTYOutput.cpp index 4ea0b0e7b..20ecf45ec 100644 --- a/WinPort/src/Backend/TTY/TTYOutput.cpp +++ b/WinPort/src/Backend/TTY/TTYOutput.cpp @@ -174,7 +174,8 @@ TTYOutput::TTYOutput(int out, bool far2l_tty, bool norgb, DWORD nodetect) } #endif - Format(ESC "7" ESC "[?47h" ESC "[?1049h" ESC "[?2004h"); + // enable mouse and focus notifications + Format(ESC "7" ESC "[?47h" ESC "[?1049h" ESC "[?2004h" ESC "[?1004h"); if ((_nodetect & NODETECT_W) == 0) { Format(ESC "[?9001h"); // win32-input-mode on @@ -185,6 +186,7 @@ TTYOutput::TTYOutput(int out, bool far2l_tty, bool norgb, DWORD nodetect) if ((_nodetect & NODETECT_K) == 0) { Format(ESC "[=15;1u"); // kovidgoyal's kitty mode on } + ChangeKeypad(true); ChangeMouse(true); @@ -215,7 +217,7 @@ TTYOutput::~TTYOutput() if ((_nodetect & NODETECT_K) == 0) { Format(ESC "[=0;1u" "\r"); // kovidgoyal's kitty mode off } - Format(ESC "[0m" ESC "[?1049l" ESC "[?47l" ESC "8" ESC "[?2004l" "\r\n"); + Format(ESC "[0m" ESC "[?1049l" ESC "[?47l" ESC "8" ESC "[?2004l" ESC "[?1004l" "\r\n"); if ((_nodetect & NODETECT_W) == 0) { Format(ESC "[?9001l"); // win32-input-mode off } From e51610f4eec7d7884faa9042dba1bfa4a69c2b73 Mon Sep 17 00:00:00 2001 From: elfmz Date: Sat, 14 Dec 2024 13:52:12 +0300 Subject: [PATCH 06/11] Update wxMain.cpp --- WinPort/src/Backend/WX/wxMain.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/WinPort/src/Backend/WX/wxMain.cpp b/WinPort/src/Backend/WX/wxMain.cpp index 62155402d..1ba88dbfe 100644 --- a/WinPort/src/Backend/WX/wxMain.cpp +++ b/WinPort/src/Backend/WX/wxMain.cpp @@ -2052,15 +2052,28 @@ void WinPortPanel::CheckPutText2CLip() void WinPortPanel::OnSetFocus( wxFocusEvent &event ) { //fprintf(stderr, "OnSetFocus\n"); + const bool was_focused = (_focused_ts != 0); const DWORD ts = WINPORT(GetTickCount)(); _focused_ts = ts ? ts : 1; ResetTimerIdling(); + if (!was_focused) { + INPUT_RECORD ir = {}; + ir.EventType = FOCUS_EVENT; + ir.Event.FocusEvent.bSetFocus = TRUE; + g_winport_con_in->Enqueue(&ir, 1); + } } void WinPortPanel::OnKillFocus( wxFocusEvent &event ) { fprintf(stderr, "OnKillFocus\n"); - _focused_ts = 0; + if (_focused_ts) { + _focused_ts = 0; + INPUT_RECORD ir = {}; + ir.EventType = FOCUS_EVENT; + ir.Event.FocusEvent.bSetFocus = FALSE; + g_winport_con_in->Enqueue(&ir, 1); + } ResetInputState(); } From 232a470b45a6c66a3390c78d2a27a0d50ad28630 Mon Sep 17 00:00:00 2001 From: elfmz Date: Sat, 14 Dec 2024 13:53:00 +0300 Subject: [PATCH 07/11] Update IVTShell.h --- far2l/src/vt/IVTShell.h | 1 + 1 file changed, 1 insertion(+) diff --git a/far2l/src/vt/IVTShell.h b/far2l/src/vt/IVTShell.h index c6446a1cf..6257a9e9b 100644 --- a/far2l/src/vt/IVTShell.h +++ b/far2l/src/vt/IVTShell.h @@ -15,6 +15,7 @@ struct IVTShell { virtual void OnMouseExpectation(MouseExpectation mex, bool enabled) = 0; virtual void OnBracketedPasteExpectation(bool enabled) = 0; + virtual void OnFocusChangeExpectation(bool enabled) = 0; virtual void OnWin32InputMode(bool enabled) = 0; virtual void SetKittyFlags(int flags) = 0; virtual int GetKittyFlags() = 0; From d462ce4840cb3fed1bef0bcbf3c3a2b5097a16d0 Mon Sep 17 00:00:00 2001 From: elfmz Date: Sat, 14 Dec 2024 13:53:20 +0300 Subject: [PATCH 08/11] Update vtansi.cpp --- far2l/src/vt/vtansi.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/far2l/src/vt/vtansi.cpp b/far2l/src/vt/vtansi.cpp index c04aa1ac1..3617ff2be 100644 --- a/far2l/src/vt/vtansi.cpp +++ b/far2l/src/vt/vtansi.cpp @@ -800,6 +800,9 @@ struct VTAnsiContext // alternative_screen_buffer.Toggle(suffix == 'h'); // break; + case 1004: + vt_shell->OnFocusChangeExpectation(suffix == 'h'); + break; case 2004: vt_shell->OnBracketedPasteExpectation(suffix == 'h'); break; From 4732c84984d420b0a519f0aad73894fce3978776 Mon Sep 17 00:00:00 2001 From: elfmz Date: Sat, 14 Dec 2024 13:53:45 +0300 Subject: [PATCH 09/11] Update vtshell.cpp --- far2l/src/vt/vtshell.cpp | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/far2l/src/vt/vtshell.cpp b/far2l/src/vt/vtshell.cpp index 35d7ba21c..7bc304334 100644 --- a/far2l/src/vt/vtshell.cpp +++ b/far2l/src/vt/vtshell.cpp @@ -40,8 +40,10 @@ #include "AnsiEsc.hpp" #include "TestPath.h" -#define BRACKETED_PASTE_SEQ_START "\x1b[200~" -#define BRACKETED_PASTE_SEQ_STOP "\x1b[201~" +#define BRACKETED_PASTE_SEQ_START "\x1b[200~" +#define BRACKETED_PASTE_SEQ_STOP "\x1b[201~" +#define FOCUS_CHANGED_SEQ_ACTIVE "\x1b[I" +#define FOCUS_CHANGED_SEQ_INACTIVE "\x1b[O" const char *VT_TranslateSpecialKey(const WORD key, bool ctrl, bool alt, bool shift, unsigned char keypad = 0, WCHAR uc = 0); std::string VT_TranslateKeyToKitty(const KEY_EVENT_RECORD &KeyEvent, int kitty_kb_flags); @@ -118,6 +120,7 @@ class VTShell : VTOutputReader::IProcessor, VTInputReader::IProcessor, IVTShell std::atomic _keypad{0}; std::atomic _bracketed_paste_expected{false}; std::atomic _win32_input_mode_expected{false}; + std::atomic _focus_change_expected{false}; std::atomic _kitty_kb_flags{0}; INPUT_RECORD _last_window_info_ir; std::unique_ptr _far2l_exts; @@ -456,6 +459,21 @@ class VTShell : VTOutputReader::IProcessor, VTInputReader::IProcessor, IVTShell } } + virtual void OnFocusChanged() // called from worker thread + { + if (_focus_change_expected) { + bool active = WINPORT(IsConsoleActive)() != FALSE; + const char *seq = active ? FOCUS_CHANGED_SEQ_ACTIVE : FOCUS_CHANGED_SEQ_INACTIVE; + if (!WriteTerm(seq, strlen(seq))) { + fprintf(stderr, "VT: OnFocusChanged - write error %d\n", errno); + } else { + fprintf(stderr, "VT: OnFocusChanged - %s\n", active ? "active" : "inactive"); + } + } else { + fprintf(stderr, "VT: OnFocusChanged - SKIPPED\n"); + } + } + void OnCtrlC(bool alt) { if (alt) { @@ -554,6 +572,14 @@ class VTShell : VTOutputReader::IProcessor, VTInputReader::IProcessor, IVTShell _bracketed_paste_expected = enabled; } + virtual void OnFocusChangeExpectation(bool enabled) + { + bool was_enabled = _focus_change_expected.exchange(enabled); + if (!was_enabled) { + OnFocusChanged(); + } + } + virtual void OnWin32InputMode(bool enabled) { _win32_input_mode_expected = enabled; From 1d7abbda50aed4f9ec4a74f49c7d26aa960c76ab Mon Sep 17 00:00:00 2001 From: elfmz Date: Sat, 14 Dec 2024 13:54:03 +0300 Subject: [PATCH 10/11] Update vtshell_ioreaders.cpp --- far2l/src/vt/vtshell_ioreaders.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/far2l/src/vt/vtshell_ioreaders.cpp b/far2l/src/vt/vtshell_ioreaders.cpp index 19c1e8a2a..fe01142e5 100644 --- a/far2l/src/vt/vtshell_ioreaders.cpp +++ b/far2l/src/vt/vtshell_ioreaders.cpp @@ -213,6 +213,9 @@ void *VTInputReader::ThreadProc() } else if (ir.EventType == KEY_EVENT) { _processor->OnInputKey(ir.Event.KeyEvent); + } else if (ir.EventType == FOCUS_EVENT) { + _processor->OnFocusChanged(); + } else if (ir.EventType == BRACKETED_PASTE_EVENT) { _processor->OnBracketedPaste(ir.Event.BracketedPaste.bStartPaste != FALSE); From d0f54bc080a2921b776aecfcff8307445d848794 Mon Sep 17 00:00:00 2001 From: elfmz Date: Sat, 14 Dec 2024 13:54:20 +0300 Subject: [PATCH 11/11] Update vtshell_ioreaders.h --- far2l/src/vt/vtshell_ioreaders.h | 1 + 1 file changed, 1 insertion(+) diff --git a/far2l/src/vt/vtshell_ioreaders.h b/far2l/src/vt/vtshell_ioreaders.h index 3735cac84..3855c9573 100644 --- a/far2l/src/vt/vtshell_ioreaders.h +++ b/far2l/src/vt/vtshell_ioreaders.h @@ -75,6 +75,7 @@ class VTInputReader : protected WithThread { virtual void OnInputMouse(const MOUSE_EVENT_RECORD &MouseEvent) = 0; virtual void OnInputKey(const KEY_EVENT_RECORD &KeyEvent) = 0; + virtual void OnFocusChanged() = 0; virtual void OnInputResized(const INPUT_RECORD &ir) = 0; virtual void OnInputInjected(const std::string &str) = 0; virtual void OnBracketedPaste(bool start) = 0;