Repository navigation
Expand file tree
/
Copy pathPrintKittyKB.java
More file actions
172 lines (146 loc) · 6.42 KB
/
Copy pathPrintKittyKB.java
File metadata and controls
172 lines (146 loc) · 6.42 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
///usr/bin/env jbang "$0" "$@" ; exit $?
//DEPS org.codejive.miniterm:miniterm${miniterm.ffm:}:${miniterm.version:0.2.0}
//DEPS org.codejive.miniterm:ansiparser:${miniterm.version:0.2.0}
//DEPS org.codejive.miniterm:termcap:${miniterm.version:0.2.0}
package examples;
import java.io.IOException;
import org.codejive.miniterm.Terminal;
import org.codejive.miniterm.ansiparser.AnsiReader;
import org.codejive.miniterm.termcap.TermCaps;
import org.codejive.miniterm.termcap.TermProber;
public class PrintKittyKB {
// ANSI helpers
private static final String CSI = "\033[";
public static void main(String[] args) {
try (Terminal terminal = Terminal.create()) {
terminal.enableRawMode();
// Detect terminal capabilities
TermCaps caps = TermProber.probe(terminal, () -> terminal.read(500));
System.out.println("Terminal capabilities:");
System.out.println(" Kitty keyboard support: " + caps.kittyKeyboard());
System.out.println();
if (!caps.kittyKeyboard()) {
System.out.println("Warning: Terminal does not report Kitty keyboard support.");
System.out.println("Attempting to enable anyway (some terminals support it without reporting).");
System.out.println();
}
// Query terminal for Kitty keyboard protocol support
System.out.println("Querying terminal for Kitty keyboard protocol...");
TermCaps.queryKittyKeyboard(terminal);
// Try to read the response
AnsiReader reader = new AnsiReader(() -> terminal.read(500));
String response = reader.read();
if (response != null && TermCaps.isKittyKeyboardResponse(response)) {
System.out.println("Terminal responded: " + escape(response));
System.out.println("Kitty keyboard protocol is supported!");
} else {
System.out.println("No response received (timeout or not supported).");
}
System.out.println();
// Enable Kitty keyboard protocol with flags:
// 1 = Disambiguate escape codes
// 2 = Report event types (press, release, repeat)
// 4 = Report alternate keys
// Combined: 7 = Full enhancement
int flags = 7;
System.out.println("Enabling Kitty keyboard protocol with flags: " + flags);
System.out.println(" 1 = Disambiguate escape codes");
System.out.println(" 2 = Report event types (press, release, repeat)");
System.out.println(" 4 = Report alternate keys");
System.out.println();
TermCaps.pushKittyKeyboard(terminal, flags);
System.out.println();
System.out.println("Press keys to see enhanced keyboard events.");
System.out.println("Try: letters (plain text), Ctrl+Shift+A, Alt+Shift+B, arrow keys.");
System.out.println("(Press Ctrl+C to exit)");
System.out.println();
System.out.println(String.format("%-40s | %-30s | %s", "Raw", "Hex", "Type"));
System.out.println(String.format("%-40s-+-%-30s-+-%s",
"-".repeat(40), "-".repeat(30), "-".repeat(30)));
try {
String token;
while ((token = reader.read()) != null) {
if (token.isEmpty()) continue;
// Check for Ctrl+C (raw byte 3 or Kitty protocol CSI 99;5u)
if (!token.startsWith("\033") && token.length() == 1 && token.charAt(0) == 3) {
break;
}
// Check for Kitty-encoded Ctrl+C: CSI 99;5u (ESC[99;5u)
if ((CSI + "99;5u").equals(token)) {
break;
}
// Print the event details on a single line
String type = analyzeToken(token);
System.out.println(String.format("%-40s | %-30s | %s",
escape(token), toHex(token), type));
}
} finally {
// Restore original keyboard protocol
TermCaps.popKittyKeyboard(terminal);
}
} catch (IOException e) {
e.printStackTrace();
}
}
private static String analyzeToken(String token) {
if (token == null || token.isEmpty()) {
return "Empty";
}
// Check for Kitty keyboard protocol sequences
// Format: CSI <unicode-key-code> : <alternate-key-codes> ; <modifiers> : <event-type> ; <text> u
if (token.startsWith(CSI) && token.endsWith("u")) {
return "Kitty keyboard protocol sequence";
}
// Check for standard CSI sequences
if (token.startsWith(CSI)) {
return "CSI sequence (standard)";
}
// Check for escape sequences
if (token.startsWith("\033")) {
return "Escape sequence";
}
// Check for control characters
if (token.length() == 1) {
char c = token.charAt(0);
if (c < 32) {
return "Control character (Ctrl+" + (char) (c + 64) + ")";
}
if (c == 127) {
return "DEL character";
}
return "Printable character: '" + c + "'";
}
// Multi-byte sequence
return "Multi-byte sequence";
}
private static String escape(String s) {
if (s == null) return "null";
StringBuilder sb = new StringBuilder();
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c == '\033') {
sb.append("ESC");
} else if (c == '\n') {
sb.append("\\n");
} else if (c == '\r') {
sb.append("\\r");
} else if (c == '\t') {
sb.append("\\t");
} else if (c < 32 || c == 127) {
sb.append("\\x").append(String.format("%02x", (int) c));
} else {
sb.append(c);
}
}
return sb.toString();
}
private static String toHex(String s) {
if (s == null) return "null";
StringBuilder sb = new StringBuilder();
for (int i = 0; i < s.length(); i++) {
if (i > 0) sb.append(" ");
sb.append(String.format("%02x", (int) s.charAt(i)));
}
return sb.toString();
}
}