Skip to content

Commit

Permalink
Merge pull request elfmz#2567 from elfmz/tty-focus
Browse files Browse the repository at this point in the history
TTY/VT: focus change notifications  (touch elfmz#2563)
  • Loading branch information
elfmz authored Dec 14, 2024
2 parents 5cf7786 + d0f54bc commit 510d930
Show file tree
Hide file tree
Showing 11 changed files with 74 additions and 6 deletions.
13 changes: 12 additions & 1 deletion WinPort/src/Backend/TTY/TTYBackend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -959,7 +960,7 @@ void TTYBackend::OnConsoleExit()

bool TTYBackend::OnConsoleIsActive()
{
return false;//true;
return _focused;
}

void TTYBackend_OnTerminalDamaged(bool flush_input_queue)
Expand Down Expand Up @@ -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) {
Expand Down
2 changes: 2 additions & 0 deletions WinPort/src/Backend/TTY/TTYBackend.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ class TTYBackend : IConsoleOutputBackend, ITTYInputSpecialSequenceHandler, IFar2
COORD _largest_window_size{};
std::atomic<bool> _largest_window_size_ready{false};
std::atomic<bool> _flush_input_queue{false};
std::atomic<bool> _focused{true}; // assume starting focused

struct BI : std::mutex { std::string flavor; } _backend_info;

Expand Down Expand Up @@ -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();
Expand Down
5 changes: 5 additions & 0 deletions WinPort/src/Backend/TTY/TTYInputSequenceParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
1 change: 1 addition & 0 deletions WinPort/src/Backend/TTY/TTYInputSequenceParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
6 changes: 4 additions & 2 deletions WinPort/src/Backend/TTY/TTYOutput.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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);

Expand Down Expand Up @@ -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
}
Expand Down
15 changes: 14 additions & 1 deletion WinPort/src/Backend/WX/wxMain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}

Expand Down
1 change: 1 addition & 0 deletions far2l/src/vt/IVTShell.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
3 changes: 3 additions & 0 deletions far2l/src/vt/vtansi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
30 changes: 28 additions & 2 deletions far2l/src/vt/vtshell.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -118,6 +120,7 @@ class VTShell : VTOutputReader::IProcessor, VTInputReader::IProcessor, IVTShell
std::atomic<unsigned char> _keypad{0};
std::atomic<bool> _bracketed_paste_expected{false};
std::atomic<bool> _win32_input_mode_expected{false};
std::atomic<bool> _focus_change_expected{false};
std::atomic<int> _kitty_kb_flags{0};
INPUT_RECORD _last_window_info_ir;
std::unique_ptr<VTFar2lExtensios> _far2l_exts;
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
Expand Down
3 changes: 3 additions & 0 deletions far2l/src/vt/vtshell_ioreaders.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
1 change: 1 addition & 0 deletions far2l/src/vt/vtshell_ioreaders.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit 510d930

Please sign in to comment.