Skip to content

Commit 6e5a7b4

Browse files
committed
Add support for Kitty keyboard protocol and XTerm PC-style function keys
1 parent 525623c commit 6e5a7b4

File tree

3 files changed

+429
-181
lines changed

3 files changed

+429
-181
lines changed

include/tvision/internal/terminal.h

Lines changed: 47 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@ struct MouseState
1414

1515
class GetChBuf
1616
{
17-
enum { maxSize = 31 };
17+
enum { maxSize = 63 };
1818

19-
int keys[maxSize];
2019
uint size {0};
20+
int keys[maxSize];
2121

2222
protected:
2323

@@ -26,20 +26,20 @@ class GetChBuf
2626

2727
public:
2828

29-
int get();
29+
int get(bool keepErr);
3030
int last(size_t i);
3131
void unget();
3232
void reject();
3333
int getNum();
3434

3535
};
3636

37-
inline int GetChBuf::get()
37+
inline int GetChBuf::get(bool keepErr=false)
3838
{
3939
if (size < maxSize)
4040
{
4141
int k = do_getch();
42-
if (k != -1)
42+
if (keepErr || k != -1)
4343
keys[size++] = k;
4444
return k;
4545
}
@@ -55,21 +55,22 @@ inline int GetChBuf::last(size_t i=0)
5555

5656
inline void GetChBuf::unget()
5757
{
58-
if (size)
59-
do_ungetch(keys[--size]);
58+
int k;
59+
if (size && (k = keys[--size]) != -1)
60+
do_ungetch(k);
6061
}
6162

6263
inline void GetChBuf::reject()
6364
{
6465
while (size)
65-
do_ungetch(keys[--size]);
66+
unget();
6667
}
6768

6869
inline int GetChBuf::getNum()
6970
{
7071
int num = 0, digits = 0;
7172
int k;
72-
while ((k = get()) != -1 && '0' <= k && k <= '9')
73+
while ((k = get(true)) != -1 && '0' <= k && k <= '9')
7374
{
7475
num = 10 * num + (k - '0');
7576
++digits;
@@ -79,22 +80,57 @@ inline int GetChBuf::getNum()
7980

8081
enum ParseResult { Rejected = 0, Accepted, Ignored };
8182

83+
struct CSIData
84+
{
85+
// Represents the data stored in a CSI escape sequence:
86+
// \x1B [ val[0] sep[0] val[1] sep[1]
87+
88+
// CSIs can be longer, but this is the largest we need for now.
89+
enum { maxLength = 2 };
90+
91+
uint val[maxLength];
92+
uint sep[maxLength];
93+
uint length;
94+
95+
bool readFrom(GetChBuf &buf)
96+
{
97+
length = 0;
98+
for (uint i = 0; i < maxLength; ++i)
99+
{
100+
int k;
101+
if (val[i] = uint(k = buf.getNum()), k == -1) return false;
102+
if (sep[i] = uint(k = buf.last()), k == -1) return false;
103+
if (sep[i] != ';')
104+
return (length = i + 1), true;
105+
}
106+
return false;
107+
}
108+
109+
uint terminator() const
110+
{
111+
return length ? sep[length - 1] : 0;
112+
}
113+
};
114+
82115
namespace TermIO
83116
{
84117

85118
void mouseOn();
86119
void mouseOff();
120+
void kittyKeysOn();
121+
void kittyKeysOff();
87122

88123
ParseResult parseEscapeSeq(GetChBuf&, TEvent&, MouseState&);
89124
ParseResult parseX10Mouse(GetChBuf&, TEvent&, MouseState&);
90125
ParseResult parseSGRMouse(GetChBuf&, TEvent&, MouseState&);
126+
ParseResult parseCSIKey(const CSIData &csi, TEvent&);
91127
ParseResult parseFKeyA(GetChBuf&, TEvent&);
92128
ParseResult parseFKeyB(GetChBuf&, TEvent&);
93129
ParseResult parseArrowKeyA(GetChBuf&, TEvent&);
94-
ParseResult parseHomeEndA(GetChBuf&, TEvent&);
130+
ParseResult parseFixTermKey(const CSIData &csi, TEvent&);
95131

96132
bool acceptMouseEvent(TEvent &ev, MouseState &oldm, const MouseState &newm);
97-
void setAltModifier(TEvent &ev);
133+
void setAltModifier(KeyDownEvent &keyDown);
98134

99135
#ifdef _TV_UNIX
100136
namespace Unix

source/platform/ncursinp.cpp

Lines changed: 36 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,19 @@ static const const_unordered_map<ushort, KeyDownEvent> fromCursesKeyCode = {
146146
{ KEY_F0 + 34, {{kbCtrlF10}, kbCtrlShift}},
147147
{ KEY_F0 + 35, {{kbCtrlF11}, kbCtrlShift}},
148148
{ KEY_F0 + 36, {{kbCtrlF12}, kbCtrlShift}},
149-
// Ctrl+Shift+F(n) supported by ncurses but not Turbo Vision
149+
// Ctrl+Shift+F1-12
150+
{ KEY_F0 + 37, {{kbCtrlF1}, kbShift | kbCtrlShift}},
151+
{ KEY_F0 + 38, {{kbCtrlF2}, kbShift | kbCtrlShift}},
152+
{ KEY_F0 + 39, {{kbCtrlF3}, kbShift | kbCtrlShift}},
153+
{ KEY_F0 + 40, {{kbCtrlF4}, kbShift | kbCtrlShift}},
154+
{ KEY_F0 + 41, {{kbCtrlF5}, kbShift | kbCtrlShift}},
155+
{ KEY_F0 + 42, {{kbCtrlF6}, kbShift | kbCtrlShift}},
156+
{ KEY_F0 + 43, {{kbCtrlF7}, kbShift | kbCtrlShift}},
157+
{ KEY_F0 + 44, {{kbCtrlF8}, kbShift | kbCtrlShift}},
158+
{ KEY_F0 + 45, {{kbCtrlF9}, kbShift | kbCtrlShift}},
159+
{ KEY_F0 + 46, {{kbCtrlF10}, kbShift | kbCtrlShift}},
160+
{ KEY_F0 + 47, {{kbCtrlF11}, kbShift | kbCtrlShift}},
161+
{ KEY_F0 + 48, {{kbCtrlF12}, kbShift | kbCtrlShift}},
150162
// Alt+F1-F12
151163
{ KEY_F0 + 49, {{kbAltF1}, kbAltShift} },
152164
{ KEY_F0 + 50, {{kbAltF2}, kbAltShift} },
@@ -176,16 +188,16 @@ static const auto fromCursesHighKey =
176188
{ "kRIT3", {{kbAltRight}, kbAltShift}},
177189
{ "kUP3", {{kbAltUp}, kbAltShift}},
178190
{ "kDN3", {{kbAltDown}, kbAltShift}},
179-
{ "kDC4", {{kbShiftDel}, kbShift | kbAltShift}},
180-
{ "kEND4", {{kbEnd}, kbShift | kbAltShift}},
181-
{ "kHOM4", {{kbHome}, kbShift | kbAltShift}},
182-
{ "kIC4", {{kbShiftIns}, kbShift | kbAltShift}},
183-
{ "kLFT4", {{kbLeft}, kbShift | kbAltShift}},
184-
{ "kNXT4", {{kbPgDn}, kbShift | kbAltShift}},
185-
{ "kPRV4", {{kbPgUp}, kbShift | kbAltShift}},
186-
{ "kRIT4", {{kbRight}, kbShift | kbAltShift}},
187-
{ "kUP4", {{kbUp}, kbShift | kbAltShift}},
188-
{ "kDN4", {{kbDown}, kbShift | kbAltShift}},
191+
{ "kDC4", {{kbAltDel}, kbShift | kbAltShift}},
192+
{ "kEND4", {{kbAltEnd}, kbShift | kbAltShift}},
193+
{ "kHOM4", {{kbAltHome}, kbShift | kbAltShift}},
194+
{ "kIC4", {{kbAltIns}, kbShift | kbAltShift}},
195+
{ "kLFT4", {{kbAltLeft}, kbShift | kbAltShift}},
196+
{ "kNXT4", {{kbAltPgDn}, kbShift | kbAltShift}},
197+
{ "kPRV4", {{kbAltPgUp}, kbShift | kbAltShift}},
198+
{ "kRIT4", {{kbAltRight}, kbShift | kbAltShift}},
199+
{ "kUP4", {{kbAltUp}, kbShift | kbAltShift}},
200+
{ "kDN4", {{kbAltDown}, kbShift | kbAltShift}},
189201
{ "kDC5", {{kbCtrlDel}, kbCtrlShift}},
190202
{ "kEND5", {{kbCtrlEnd}, kbCtrlShift}},
191203
{ "kHOM5", {{kbCtrlHome}, kbCtrlShift}},
@@ -206,16 +218,16 @@ static const auto fromCursesHighKey =
206218
{ "kRIT6", {{kbCtrlRight}, kbCtrlShift | kbShift}},
207219
{ "kUP6", {{kbCtrlUp}, kbCtrlShift | kbShift}},
208220
{ "kDN6", {{kbCtrlDown}, kbCtrlShift | kbShift}},
209-
{ "kDC7", {{kbDel}, kbCtrlShift | kbAltShift}}, // Please do not attempt this one
210-
{ "kEND7", {{kbEnd}, kbCtrlShift | kbAltShift}},
211-
{ "kHOM7", {{kbHome}, kbCtrlShift | kbAltShift}},
212-
{ "kIC7", {{kbIns}, kbCtrlShift | kbAltShift}},
213-
{ "kLFT7", {{kbLeft}, kbCtrlShift | kbAltShift}},
214-
{ "kNXT7", {{kbPgDn}, kbCtrlShift | kbAltShift}},
215-
{ "kPRV7", {{kbPgUp}, kbCtrlShift | kbAltShift}},
216-
{ "kRIT7", {{kbRight}, kbCtrlShift | kbAltShift}},
217-
{ "kUP7", {{kbUp}, kbCtrlShift | kbAltShift}},
218-
{ "kDN7", {{kbDown}, kbCtrlShift | kbAltShift}},
221+
{ "kDC7", {{kbAltDel}, kbCtrlShift | kbAltShift}}, // Please do not attempt this one
222+
{ "kEND7", {{kbAltEnd}, kbCtrlShift | kbAltShift}},
223+
{ "kHOM7", {{kbAltHome}, kbCtrlShift | kbAltShift}},
224+
{ "kIC7", {{kbAltIns}, kbCtrlShift | kbAltShift}},
225+
{ "kLFT7", {{kbAltLeft}, kbCtrlShift | kbAltShift}},
226+
{ "kNXT7", {{kbAltPgDn}, kbCtrlShift | kbAltShift}},
227+
{ "kPRV7", {{kbAltPgUp}, kbCtrlShift | kbAltShift}},
228+
{ "kRIT7", {{kbAltRight}, kbCtrlShift | kbAltShift}},
229+
{ "kUP7", {{kbAltUp}, kbCtrlShift | kbAltShift}},
230+
{ "kDN7", {{kbAltDown}, kbCtrlShift | kbAltShift}},
219231
{ "kpADD", {{'+'}, 0, {'+'}, 1}},
220232
{ "kpSUB", {{'-'}, 0, {'-'}, 1}},
221233
{ "kpMUL", {{'*'}, 0, {'*'}, 1}},
@@ -244,6 +256,7 @@ NcursesInput::NcursesInput(bool mouse) :
244256
* special key sequences, I believe. */
245257
set_escdelay(getEnv<int>("TVISION_ESCDELAY", 10));
246258

259+
TermIO::kittyKeysOn();
247260
if (mouseEnabled)
248261
{
249262
mstate.where = {-1, -1};
@@ -261,6 +274,7 @@ NcursesInput::~NcursesInput()
261274
{
262275
if (mouseEnabled)
263276
TermIO::mouseOff();
277+
TermIO::kittyKeysOff();
264278
}
265279

266280
int NcursesInput::getButtonCount()
@@ -348,7 +362,7 @@ bool NcursesInput::getEvent(TEvent &ev)
348362
parsePrintableChar(ev, keys, num_keys);
349363

350364
if (Alt)
351-
TermIO::setAltModifier(ev);
365+
TermIO::setAltModifier(ev.keyDown);
352366

353367
return ev.keyDown.keyCode != kbNoKey || ev.keyDown.textLength;
354368
}

0 commit comments

Comments
 (0)