AquilaOS documentation
How it works, and its code
Loading...
Searching...
No Matches
keyboard.c
Go to the documentation of this file.
1
15
16#include <core/system.h>
17#include <core/string.h>
18#include <dev/vt.h>
19#include <sys/reboot.h>
20#include <aquila/keyboard.h>
21
22/* scancodes (set 1) */
23#define SC_ESC 0x01
24#define SC_BS 0x0E
25#define SC_TAB 0x0F
26#define SC_ENTER 0x1C
27#define SC_CTRL 0x1D
28#define SC_LSHIFT 0x2A
29#define SC_RSHIFT 0x36
30#define SC_KP_MUL 0x37
31#define SC_ALT 0x38
32#define SC_CAPS 0x3A
33#define SC_F1 0x3B
34#define SC_F10 0x44
35#define SC_NUM 0x45
36#define SC_KP7 0x47
37#define SC_KP_DEL 0x53
38#define SC_F11 0x57
39#define SC_F12 0x58
40
41/* the characters of the keys, by scancode: without Shift, then with it */
42static const char keys[128] = {
43 [0x02] = '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=',
44 [0x10] = 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']',
45 [0x1E] = 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`',
46 [0x2B] = '\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/',
47 [0x39] = ' ',
48 [0x56] = '<',
49};
50
51static const char shifted[128] = {
52 [0x02] = '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+',
53 [0x10] = 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}',
54 [0x1E] = 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', '~',
55 [0x2B] = '|', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?',
56 [0x39] = ' ',
57 [0x56] = '>',
58};
59
60/* what the function keys send, F1 to F12 */
61static const char *fkeys[12] = {
62 "\033[[A", "\033[[B", "\033[[C", "\033[[D", "\033[[E", "\033[17~",
63 "\033[18~", "\033[19~", "\033[20~", "\033[21~", "\033[23~", "\033[24~",
64};
65
66/* what the keypad's keys, 7 to ., send without Num Lock: those of the
67 * editing block (one letter: a cursor key). NULL for - and +, which are
68 * the same either way. */
69static const char *keypad_keys[13] = {
70 "\033[1~", "A", "\033[5~", NULL, "D", "\033[G", "C", NULL,
71 "\033[4~", "B", "\033[6~", "\033[2~", "\033[3~",
72};
73
74static const char keypad_digits[] = "789-456+1230.";
75
76/* the Linux key codes of the keys with an E0 prefix, by scancode; the
77 * other keys' key codes are their scancodes */
78static const uint8_t e0_keycodes[128] = {
79 [0x1C] = 96, /* keypad Enter */
80 [0x1D] = 97, /* right Ctrl */
81 [0x35] = 98, /* keypad / */
82 [0x37] = 99, /* Print Screen */
83 [0x38] = 100, /* right Alt */
84 [0x47] = 102, /* Home */
85 [0x48] = 103, /* Up */
86 [0x49] = 104, /* Page Up */
87 [0x4B] = 105, /* Left */
88 [0x4D] = 106, /* Right */
89 [0x4F] = 107, /* End */
90 [0x50] = 108, /* Down */
91 [0x51] = 109, /* Page Down */
92 [0x52] = 110, /* Insert */
93 [0x53] = 111, /* Delete */
94 [0x5B] = 125, /* left Windows */
95 [0x5C] = 126, /* right Windows */
96 [0x5D] = 127, /* Menu */
97};
98
99#define KEY_PAUSE 119
100
101static int shift, ctrl, alt, caps, num;
102
103/* whether an E0 prefix came for the next scancode, and how many bytes
104 * of the Pause key's sequence (E1 ...) are left to skip */
105static int extended, skip;
106
108static void send(const char *s)
109{
110 vt_input(s, strlen(s));
111}
112
114static void send_byte(int c)
115{
116 char b = c;
117 vt_input(&b, 1);
118}
119
130int vt_keymap(int table, int keycode)
131{
132 int shifted_table = table & (1 << KG_SHIFT);
133
134 if (table & ~((1 << KG_SHIFT) | (1 << KG_ALTGR)))
135 return K_HOLE;
136
137 switch (keycode) {
138 case SC_ESC: return K(KT_LATIN, 0x1b);
139 case SC_BS: return K(KT_LATIN, 0x7f);
140 case SC_TAB: return K(KT_LATIN, '\t');
141 case SC_ENTER: return K_ENTER;
142 case SC_CTRL: return K_CTRL;
143 case SC_LSHIFT: case SC_RSHIFT: return K_SHIFT;
144 case SC_ALT: return K_ALT;
145 case SC_CAPS: return K_CAPS;
146 case SC_NUM: return K_NUM;
147 case 0x46: return K_HOLD;
148 case SC_KP_MUL: return K_PSTAR;
149 case SC_F11: return K(KT_FN, 10);
150 case SC_F12: return K(KT_FN, 11);
151
152 /* the keys with an E0 prefix (see e0_keycodes) */
153 case 96: return K_PENTER;
154 case 97: return K_CTRL;
155 case 98: return K_PSLASH;
156 case 100: return K_ALT;
157 case 102: return K_FIND;
158 case 103: return K_UP;
159 case 104: return K_PGUP;
160 case 105: return K_LEFT;
161 case 106: return K_RIGHT;
162 case 107: return K_SELECT;
163 case 108: return K_DOWN;
164 case 109: return K_PGDN;
165 case 110: return K_INSERT;
166 case 111: return K_REMOVE;
167 case KEY_PAUSE: return K_PAUSE;
168 }
169
170 if (keycode >= SC_F1 && keycode <= SC_F10)
171 return K(KT_FN, keycode - SC_F1);
172
173 if (keycode >= SC_KP7 && keycode <= SC_KP_DEL) {
174 static const uint16_t keypad[13] = {
175 K_P0 + 7, K_P0 + 8, K_P0 + 9, K_PMINUS, K_P0 + 4, K_P0 + 5, K_P0 + 6,
176 K_PPLUS, K_P0 + 1, K_P0 + 2, K_P0 + 3, K_P0, K_PDOT,
177 };
178 return keypad[keycode - SC_KP7];
179 }
180
181 if (keycode < 0 || keycode >= 128)
182 return K_HOLE;
183
184 char c = shifted_table ? shifted[keycode] : keys[keycode];
185
186 if (!c)
187 return K_HOLE;
188
189 if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
190 return K(KT_LETTER, c);
191
192 return K(KT_LATIN, (unsigned char) c);
193}
194
199{
200 extended = skip = 0;
201}
202
204static void send_key(const char *s)
205{
206 if (alt)
207 send("\033");
208 send(s);
209}
210
212static void send_char(char c)
213{
214 char buf[] = {c, '\0'};
215
216 if (!c) {
217 /* NUL (^@), which a string can't hold */
218 if (alt)
219 send("\033");
220 vt_input(buf, 1);
221 return;
222 }
223
224 send_key(buf);
225}
226
229static void cursor_key(char dir)
230{
231 struct vt *vt = vt_foreground();
232 char buf[] = {'\033', vt && vt->cursor_keys ? 'O' : '[', dir, '\0'};
233
234 send_key(buf);
235}
236
239static void editing_key(const char *s)
240{
241 if (s[1])
242 send_key(s);
243 else
244 cursor_key(s[0]);
245}
246
249static int control(char c)
250{
251 if (c >= 'a' && c <= 'z')
252 return c - 'a' + 1;
253
254 if (c >= 'A' && c <= 'Z')
255 return c - 'A' + 1;
256
257 switch (c) {
258 case '@': case '2': case ' ': case '`':
259 return 0;
260 case '[': case '3': case '{':
261 return 0x1b;
262 case '\\': case '4': case '|':
263 return 0x1c;
264 case ']': case '5': case '}':
265 return 0x1d;
266 case '^': case '6': case '~':
267 return 0x1e;
268 case '_': case '-': case '/': case '7': case '?':
269 return 0x1f;
270 case '8':
271 return 0x7f;
272 }
273
274 return c;
275}
276
279static int modifier(int code, int release, int ext)
280{
281 switch (code) {
282 case SC_LSHIFT:
283 case SC_RSHIFT:
284 /* E0 2A and E0 36 come around some keys, as if Shift was
285 * used: they aren't the Shift keys */
286 if (!ext)
287 shift = !release;
288 return 1;
289 case SC_CTRL:
290 ctrl = !release;
291 return 1;
292 case SC_ALT:
293 alt = !release;
294 return 1;
295 }
296
297 return 0;
298}
299
307void vt_scancode(int scancode)
308{
309 /* first undo the modes that a program which is gone had set */
310 vt_keypress();
311
312 struct vt *vt = vt_foreground();
313 int mode = vt ? vt->kb_mode : K_XLATE;
314
315 if (mode == K_RAW)
316 send_byte(scancode);
317
318 if (skip) {
319 --skip;
320 return;
321 }
322
323 if (scancode == 0xE0) {
324 extended = 1;
325 return;
326 }
327
328 /* Pause sends E1 1D 45 E1 9D C5: it is pressed and released at once */
329 if (scancode == 0xE1) {
330 skip = 5;
331
332 if (mode == K_MEDIUMRAW) {
334 send_byte(KEY_PAUSE | 0x80);
335 }
336 return;
337 }
338
339 int code = scancode & 0x7f, release = scancode & 0x80, ext = extended;
340 extended = 0;
341
342 if (mode != K_XLATE && mode != K_UNICODE) {
343 modifier(code, release, ext);
344
345 /* the fake Shift codes (E0 2A, E0 36) aren't keys */
346 if (mode != K_MEDIUMRAW || (ext && (code == SC_LSHIFT || code == SC_RSHIFT)))
347 return;
348
349 int keycode = ext ? e0_keycodes[code] : code;
350
351 if (keycode)
352 send_byte(keycode | release);
353 return;
354 }
355
356 if (modifier(code, release, ext))
357 return;
358
359 switch (code) {
360 case SC_CAPS:
361 if (!release)
362 caps = !caps;
363 return;
364 case SC_NUM:
365 if (!release && !ext)
366 num = !num;
367 return;
368 }
369
370 if (release)
371 return;
372
373 /* Ctrl+Alt+Del, with either Del key */
374 if (ctrl && alt && code == SC_KP_DEL) {
376 return;
377 }
378
379 /* the function keys, which switch terminals with Alt */
380 int fkey = code >= SC_F1 && code <= SC_F10 ? code - SC_F1 :
381 code == SC_F11 ? 10 : code == SC_F12 ? 11 : -1;
382
383 if (fkey >= 0) {
384 if (alt) {
385 vt_switch(fkey);
386 return;
387 }
388
389 send(fkeys[fkey]);
390 return;
391 }
392
393 if (ext) {
394 switch (code) {
395 case SC_ENTER: send_key("\r"); return;
396 case 0x35: send_char(ctrl ? control('/') : '/'); return;
397 case 0x47: send_key("\033[1~"); return;
398 case 0x48: cursor_key('A'); return;
399 case 0x49: send_key("\033[5~"); return;
400 case 0x4B: cursor_key('D'); return;
401 case 0x4D: cursor_key('C'); return;
402 case 0x4F: send_key("\033[4~"); return;
403 case 0x50: cursor_key('B'); return;
404 case 0x51: send_key("\033[6~"); return;
405 case 0x52: send_key("\033[2~"); return;
406 case 0x53: send_key("\033[3~"); return;
407 }
408
409 return;
410 }
411
412 switch (code) {
413 case SC_ESC: send_char('\033'); return;
414 case SC_BS: send_char(ctrl ? '\b' : 0x7f); return;
415 case SC_TAB: send_key(shift ? "\033[Z" : "\t"); return;
416 case SC_ENTER: send_key("\r"); return;
417 case SC_KP_MUL: send_char('*'); return;
418 }
419
420 if (code >= SC_KP7 && code <= SC_KP_DEL) {
421 int i = code - SC_KP7;
422
423 if ((num && !shift) || !keypad_keys[i])
425 else
427 return;
428 }
429
430 char c = shift ? shifted[code] : keys[code];
431
432 if (!c)
433 return;
434
435 if (caps && ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')))
436 c ^= 0x20;
437
438 if (ctrl)
439 c = control(c);
440
441 send_char(c);
442}
#define SC_CTRL
Definition keyboard.c:27
#define SC_F10
Definition keyboard.c:34
static const uint8_t e0_keycodes[128]
Definition keyboard.c:78
static int ctrl
Definition keyboard.c:101
#define SC_RSHIFT
Definition keyboard.c:29
static int modifier(int code, int release, int ext)
Keeps track of Shift, Ctrl and Alt, in every mode, since they may be held while the mode changes.
Definition keyboard.c:279
static const char keypad_digits[]
Definition keyboard.c:74
#define SC_F11
Definition keyboard.c:38
#define SC_BS
Definition keyboard.c:24
static void editing_key(const char *s)
Sends a key of the editing block: its sequence, or a cursor key if it is one letter.
Definition keyboard.c:239
static int control(char c)
Returns the control character that Ctrl with a key sends, as the Linux console does (Ctrl+A is 1,...
Definition keyboard.c:249
#define SC_KP7
Definition keyboard.c:36
static int extended
Definition keyboard.c:105
static void send_byte(int c)
Sends one byte to the foreground terminal, as typed input.
Definition keyboard.c:114
static const char * fkeys[12]
Definition keyboard.c:61
#define SC_F12
Definition keyboard.c:39
#define SC_TAB
Definition keyboard.c:25
#define SC_F1
Definition keyboard.c:33
static const char shifted[128]
Definition keyboard.c:51
#define SC_CAPS
Definition keyboard.c:32
static int num
Definition keyboard.c:101
static void cursor_key(char dir)
Sends a cursor key: ESC [ x, or ESC O x in the terminal's application cursor key mode (DECCKM).
Definition keyboard.c:229
static int alt
Definition keyboard.c:101
#define SC_NUM
Definition keyboard.c:35
#define SC_ALT
Definition keyboard.c:31
#define SC_ENTER
Definition keyboard.c:26
static void send_key(const char *s)
Sends what a key sends, with ESC before it if Alt is held.
Definition keyboard.c:204
#define SC_LSHIFT
Definition keyboard.c:28
int vt_keymap(int table, int keycode)
Says what a key is, for KDGKBENT: programs that read key codes (K_MEDIUMRAW) use it to know what each...
Definition keyboard.c:130
static void send(const char *s)
Sends a string to the foreground terminal, as typed input.
Definition keyboard.c:108
static void send_char(char c)
Sends one character, with ESC before it if Alt is held.
Definition keyboard.c:212
static int caps
Definition keyboard.c:101
#define SC_ESC
Definition keyboard.c:23
static const char * keypad_keys[13]
Definition keyboard.c:69
static const char keys[128]
Definition keyboard.c:42
#define KEY_PAUSE
Definition keyboard.c:99
#define SC_KP_MUL
Definition keyboard.c:30
void vt_scancode(int scancode)
Takes a scancode from the keyboard, and sends what the key means to the foreground terminal,...
Definition keyboard.c:307
#define SC_KP_DEL
Definition keyboard.c:37
static int shift
Definition keyboard.c:101
void vt_keyboard_reset(void)
Forgets a prefix or a sequence that a change of mode cut in the middle.
Definition keyboard.c:198
static uint64_t * table(paddr_t paddr)
Returns a page table, through the direct map.
Definition pmap.c:72
static int skip
Definition ps2mouse.c:48
void kernel_ctrlaltdel(void)
Handles Ctrl+Alt+Del from the keyboard, possibly in an interrupt: it restarts the machine,...
Definition reboot.c:62
#define NULL
Definition stddef.h:27
unsigned char uint8_t
Definition stddef.h:20
unsigned short int uint16_t
Definition stddef.h:21
A virtual terminal: its screen, its emulator's state, and its tty.
Definition vt.h:76
int cursor_keys
Definition vt.h:94
int kb_mode
Definition vt.h:124
int keypad
Definition vt.h:95
struct vt_mode mode
Definition vt.h:130
void vt_input(const char *buf, size_t size)
Gives what keys sent to the foreground terminal, as input.
Definition vt.c:375
struct vt * vt_foreground(void)
Returns the terminal in the foreground.
Definition vt.c:261
void vt_switch(int id)
Switches to another terminal, for Alt+Fn and VT_ACTIVATE.
Definition vt.c:341
void vt_keypress(void)
Undoes, at a key press, the modes that a process which is gone had set on the foreground terminal: ot...
Definition vt.c:363