blob: 01dc978315606f9e8977138dfd450765272ab168 (
plain) (
blame)
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
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
|
# Primitives for keyboard control.
# Require Linux and a modern terminal.
== code
enable-keyboard-immediate-mode:
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
50/push-eax
51/push-ecx
52/push-edx
53/push-ebx
56/push-esi
57/push-edi
#
(_maybe-open-terminal)
# var terminal-info/esi: (addr termios)
# termios is a type from the Linux kernel. We don't care how large it is.
81 5/subop/subtract %esp 0x100/imm32
89/<- %esi 4/r32/esp
# ioctl(*Terminal-file-descriptor, TCGETS, terminal-info)
89/<- %edx 6/r32/esi
b9/copy-to-ecx 0x5401/imm32/TCGETS
8b/-> *Terminal-file-descriptor 3/r32/ebx
e8/call syscall_ioctl/disp32
# terminal-info->c_iflags &= Keyboard-immediate-mode-iflags
#? (write-buffered Stderr "iflags before: ")
#? (write-int32-hex-buffered Stderr *esi)
#? (write-buffered Stderr Newline)
#? (flush Stderr)
8b/-> *esi 0/r32/eax # Termios-c_iflag
23/and *Keyboard-immediate-mode-iflags 0/r32/eax
89/<- *esi 0/r32/eax # Termios-c_iflag
#? (write-buffered Stderr "iflags after: ")
#? (write-int32-hex-buffered Stderr *esi)
#? (write-buffered Stderr Newline)
#? (flush Stderr)
# terminal-info->c_lflags &= Keyboard-immediate-mode-lflags
#? (write-buffered Stderr "lflags before: ")
#? (write-int32-hex-buffered Stderr *(esi+0xc))
#? (write-buffered Stderr Newline)
#? (flush Stderr)
8b/-> *(esi+0xc) 0/r32/eax # Termios-c_lflag
23/and *Keyboard-immediate-mode-lflags 0/r32/eax
89/<- *(esi+0xc) 0/r32/eax # Termios-c_lflag
#? (write-buffered Stderr "lflags after: ")
#? (write-int32-hex-buffered Stderr *(esi+0xc))
#? (write-buffered Stderr Newline)
#? (flush Stderr)
# ioctl(*Terminal-file-descriptor, TCSETS, terminal-info)
89/<- %edx 6/r32/esi
b9/copy-to-ecx 0x5402/imm32/TCSETS
8b/-> *Terminal-file-descriptor 3/r32/ebx
e8/call syscall_ioctl/disp32
$enable-keyboard-immediate-mode:end:
# . reclaim locals
81 0/subop/add %esp 0x100/imm32
# . restore registers
5f/pop-to-edi
5e/pop-to-esi
5b/pop-to-ebx
5a/pop-to-edx
59/pop-to-ecx
58/pop-to-eax
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
enable-keyboard-type-mode:
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
50/push-eax
51/push-ecx
52/push-edx
53/push-ebx
56/push-esi
57/push-edi
#
(_maybe-open-terminal)
# var terminal-info/esi: (addr termios)
# termios is a type from the Linux kernel. We don't care how large it is.
81 5/subop/subtract %esp 0x100/imm32
89/<- %esi 4/r32/esp
# ioctl(*Terminal-file-descriptor, TCGETS, terminal-info)
89/<- %edx 6/r32/esi
b9/copy-to-ecx 0x5401/imm32/TCGETS
8b/-> *Terminal-file-descriptor 3/r32/ebx
e8/call syscall_ioctl/disp32
# terminal-info->c_iflags |= Keyboard-type-mode-iflags
8b/-> *esi 0/r32/eax # Termios-c_iflag
0b/or *Keyboard-type-mode-iflags 0/r32/eax
89/<- *esi 0/r32/eax # Termios-c_iflag
# terminal-info->c_lflags |= Keyboard-type-mode-lflags
8b/-> *(esi+0xc) 0/r32/eax # Termios-c_lflag
0b/or *Keyboard-type-mode-lflags 0/r32/eax
89/<- *(esi+0xc) 0/r32/eax # Termios-c_lflag
# ioctl(*Terminal-file-descriptor, TCSETS, terminal-info)
89/<- %edx 6/r32/esi
b9/copy-to-ecx 0x5402/imm32/TCSETS
8b/-> *Terminal-file-descriptor 3/r32/ebx
e8/call syscall_ioctl/disp32
$enable-keyboard-type-mode:end:
# . reclaim locals
81 0/subop/add %esp 0x100/imm32
# . restore registers
5f/pop-to-edi
5e/pop-to-esi
5b/pop-to-ebx
5a/pop-to-edx
59/pop-to-ecx
58/pop-to-eax
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
# read keys or escapes up to 4 bytes
#
# fun fact: terminal escapes and graphemes in utf-8 don't conflict!
# - in graphemes all but the first/lowest byte will have a 1 in the MSB (be
# greater than 0x7f)
# - in escapes every byte will have a 0 in the MSB
# the two categories overlap only when the first/lowest byte is 0x1b or 'esc'
#
# Only use this in immediate mode; in type (typewriter) mode 4 bytes may get
# parts of multiple keys.
read-key-from-real-keyboard: # -> result/eax: grapheme
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
51/push-ecx
# var buf/ecx: (stream byte 4)
68/push 0/imm32/data
68/push 4/imm32/size
68/push 0/imm32/read
68/push 0/imm32/write
89/<- %ecx 4/r32/esp
#
(read 0 %ecx) # => eax
8b/-> *(ecx+0xc) 0/r32/eax
$read-key-from-real-keyboard:end:
# . reclaim locals
81 0/subop/add %esp 0x10/imm32
# . restore registers
59/pop-to-ecx
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
# use this in type mode
read-line-from-real-keyboard: # in: (addr stream byte)
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
50/push-eax
#
(read 0 *(ebp+8)) # => eax
$read-line-from-real-keyboard:end:
# . restore registers
58/pop-to-eax
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
== data
# iflags: octal hex
# IGNBRK 0000001 0x0001
# BRKINT 0000002 0x0002
# IGNPAR 0000004 0x0004
# PARMRK 0000010 0x0008
# INPCK 0000020 0x0010
# ISTRIP 0000040 0x0020
# INLCR 0000100 0x0040
# IGNCR 0000200 0x0080
# ICRNL 0000400 0x0100
# IUCLC 0001000 0x0200
# IXON 0002000 0x0400
# IXANY 0004000 0x0800
# IXOFF 0010000 0x1000
# IMAXBEL 0020000 0x2000
# IUTF8 0040000 0x4000
# lflags:
# ISIG 0000001 0x0001
# ICANON 0000002 0x0002
# ECHO 0000010 0x0008
# ECHOE 0000020 0x0010
# ECHOK 0000040 0x0020
# ECHONL 0000100 0x0040
# NOFLSH 0000200 0x0080
# TOSTOP 0000400 0x0100
# IEXTEN 0100000 0x8000
# recipe for raw mode according to the termios.3 manpage on Linux:
# termios_p->c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
# termios_p->c_oflag &= ~OPOST;
# termios_p->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
# termios_p->c_cflag &= ~(CSIZE | PARENB);
# termios_p->c_cflag |= CS8;
Keyboard-immediate-mode-iflags: # (addr tcflag_t)
#? 0xfffffa14 # ~IGNBRK & ~BRKINT & ~PARMRK & ~ISTRIP & ~INLCR & ~IGNCR & ~ICRNL & ~IXON
0xffffffff/imm32
Keyboard-immediate-mode-lflags: # (addr tcflag_t)
#? 0xffff7fb4/imm32 # ~ICANON & ~ISIG & ~IEXTEN & ~ECHO & ~ECHONL
0xffffffb5/imm32 # ~ICANON & ~ECHO & ~ECHONL
Keyboard-type-mode-iflags: # (addr tcflag_t)
0x00000000/imm32 # ~Keyboard-immediate-mode-iflags
Keyboard-type-mode-lflags: # (addr tcflag_t)
0x0000004a/imm32 # ~Keyboard-immediate-mode-lflags
|