xref: /plan9/sys/src/9/teg2/kbd.c (revision 3de6a9c0b3d5cf34fc4090d0bf1930d83799a7fd)
1 /*
2  * simulated keyboard input for systems with none (except via uart or usb)
3  *
4  * gutted version of ps2 version from ../pc
5  */
6 #include	"u.h"
7 #include	"../port/lib.h"
8 #include	"mem.h"
9 #include	"dat.h"
10 #include	"fns.h"
11 #include	"io.h"
12 #include	"../port/error.h"
13 
14 enum {
15 	Spec=		0xF800,		/* Unicode private space */
16 	PF=		Spec|0x20,	/* num pad function key */
17 	View=		Spec|0x00,	/* view (shift window up) */
18 	KF=		0xF000,		/* function key (begin Unicode private space) */
19 	Shift=		Spec|0x60,
20 	Break=		Spec|0x61,
21 	Ctrl=		Spec|0x62,
22 	Latin=		Spec|0x63,
23 	Caps=		Spec|0x64,
24 	Num=		Spec|0x65,
25 	Middle=		Spec|0x66,
26 	Altgr=		Spec|0x67,
27 	Kmouse=		Spec|0x100,
28 	No=		0x00,		/* peter */
29 
30 	Home=		KF|13,
31 	Up=		KF|14,
32 	Pgup=		KF|15,
33 	Print=		KF|16,
34 	Left=		KF|17,
35 	Right=		KF|18,
36 	End=		KF|24,
37 	Down=		View,
38 	Pgdown=		KF|19,
39 	Ins=		KF|20,
40 	Del=		0x7F,
41 	Scroll=		KF|21,
42 
43 	Nscan=	128,
44 
45 	Int=	0,			/* kbscans indices */
46 	Ext,
47 	Nscans,
48 };
49 
50 /*
51  * The codes at 0x79 and 0x7b are produced by the PFU Happy Hacking keyboard.
52  * A 'standard' keyboard doesn't produce anything above 0x58.
53  */
54 Rune kbtab[Nscan] =
55 {
56 [0x00]	No,	0x1b,	'1',	'2',	'3',	'4',	'5',	'6',
57 [0x08]	'7',	'8',	'9',	'0',	'-',	'=',	'\b',	'\t',
58 [0x10]	'q',	'w',	'e',	'r',	't',	'y',	'u',	'i',
59 [0x18]	'o',	'p',	'[',	']',	'\n',	Ctrl,	'a',	's',
60 [0x20]	'd',	'f',	'g',	'h',	'j',	'k',	'l',	';',
61 [0x28]	'\'',	'`',	Shift,	'\\',	'z',	'x',	'c',	'v',
62 [0x30]	'b',	'n',	'm',	',',	'.',	'/',	Shift,	'*',
63 [0x38]	Latin,	' ',	Ctrl,	KF|1,	KF|2,	KF|3,	KF|4,	KF|5,
64 [0x40]	KF|6,	KF|7,	KF|8,	KF|9,	KF|10,	Num,	Scroll,	'7',
65 [0x48]	'8',	'9',	'-',	'4',	'5',	'6',	'+',	'1',
66 [0x50]	'2',	'3',	'0',	'.',	No,	No,	No,	KF|11,
67 [0x58]	KF|12,	No,	No,	No,	No,	No,	No,	No,
68 [0x60]	No,	No,	No,	No,	No,	No,	No,	No,
69 [0x68]	No,	No,	No,	No,	No,	No,	No,	No,
70 [0x70]	No,	No,	No,	No,	No,	No,	No,	No,
71 [0x78]	No,	View,	No,	Up,	No,	No,	No,	No,
72 };
73 
74 Rune kbtabshift[Nscan] =
75 {
76 [0x00]	No,	0x1b,	'!',	'@',	'#',	'$',	'%',	'^',
77 [0x08]	'&',	'*',	'(',	')',	'_',	'+',	'\b',	'\t',
78 [0x10]	'Q',	'W',	'E',	'R',	'T',	'Y',	'U',	'I',
79 [0x18]	'O',	'P',	'{',	'}',	'\n',	Ctrl,	'A',	'S',
80 [0x20]	'D',	'F',	'G',	'H',	'J',	'K',	'L',	':',
81 [0x28]	'"',	'~',	Shift,	'|',	'Z',	'X',	'C',	'V',
82 [0x30]	'B',	'N',	'M',	'<',	'>',	'?',	Shift,	'*',
83 [0x38]	Latin,	' ',	Ctrl,	KF|1,	KF|2,	KF|3,	KF|4,	KF|5,
84 [0x40]	KF|6,	KF|7,	KF|8,	KF|9,	KF|10,	Num,	Scroll,	'7',
85 [0x48]	'8',	'9',	'-',	'4',	'5',	'6',	'+',	'1',
86 [0x50]	'2',	'3',	'0',	'.',	No,	No,	No,	KF|11,
87 [0x58]	KF|12,	No,	No,	No,	No,	No,	No,	No,
88 [0x60]	No,	No,	No,	No,	No,	No,	No,	No,
89 [0x68]	No,	No,	No,	No,	No,	No,	No,	No,
90 [0x70]	No,	No,	No,	No,	No,	No,	No,	No,
91 [0x78]	No,	Up,	No,	Up,	No,	No,	No,	No,
92 };
93 
94 Rune kbtabesc1[Nscan] =
95 {
96 [0x00]	No,	No,	No,	No,	No,	No,	No,	No,
97 [0x08]	No,	No,	No,	No,	No,	No,	No,	No,
98 [0x10]	No,	No,	No,	No,	No,	No,	No,	No,
99 [0x18]	No,	No,	No,	No,	'\n',	Ctrl,	No,	No,
100 [0x20]	No,	No,	No,	No,	No,	No,	No,	No,
101 [0x28]	No,	No,	Shift,	No,	No,	No,	No,	No,
102 [0x30]	No,	No,	No,	No,	No,	'/',	No,	Print,
103 [0x38]	Altgr,	No,	No,	No,	No,	No,	No,	No,
104 [0x40]	No,	No,	No,	No,	No,	No,	Break,	Home,
105 [0x48]	Up,	Pgup,	No,	Left,	No,	Right,	No,	End,
106 [0x50]	Down,	Pgdown,	Ins,	Del,	No,	No,	No,	No,
107 [0x58]	No,	No,	No,	No,	No,	No,	No,	No,
108 [0x60]	No,	No,	No,	No,	No,	No,	No,	No,
109 [0x68]	No,	No,	No,	No,	No,	No,	No,	No,
110 [0x70]	No,	No,	No,	No,	No,	No,	No,	No,
111 [0x78]	No,	Up,	No,	No,	No,	No,	No,	No,
112 };
113 
114 Rune kbtabaltgr[Nscan] =
115 {
116 [0x00]	No,	No,	No,	No,	No,	No,	No,	No,
117 [0x08]	No,	No,	No,	No,	No,	No,	No,	No,
118 [0x10]	No,	No,	No,	No,	No,	No,	No,	No,
119 [0x18]	No,	No,	No,	No,	'\n',	Ctrl,	No,	No,
120 [0x20]	No,	No,	No,	No,	No,	No,	No,	No,
121 [0x28]	No,	No,	Shift,	No,	No,	No,	No,	No,
122 [0x30]	No,	No,	No,	No,	No,	'/',	No,	Print,
123 [0x38]	Altgr,	No,	No,	No,	No,	No,	No,	No,
124 [0x40]	No,	No,	No,	No,	No,	No,	Break,	Home,
125 [0x48]	Up,	Pgup,	No,	Left,	No,	Right,	No,	End,
126 [0x50]	Down,	Pgdown,	Ins,	Del,	No,	No,	No,	No,
127 [0x58]	No,	No,	No,	No,	No,	No,	No,	No,
128 [0x60]	No,	No,	No,	No,	No,	No,	No,	No,
129 [0x68]	No,	No,	No,	No,	No,	No,	No,	No,
130 [0x70]	No,	No,	No,	No,	No,	No,	No,	No,
131 [0x78]	No,	Up,	No,	No,	No,	No,	No,	No,
132 };
133 
134 Rune kbtabctrl[Nscan] =
135 {
136 [0x00]	No,	'', 	'', 	'', 	'', 	'', 	'', 	'',
137 [0x08]	'', 	'', 	'', 	'', 	'
138 ', 	'', 	'\b',	'\t',
139 [0x10]	'', 	'', 	'', 	'', 	'', 	'', 	'', 	'\t',
140 [0x18]	'', 	'', 	'', 	'', 	'\n',	Ctrl,	'', 	'',
141 [0x20]	'', 	'', 	'', 	'\b',	'\n',	'', 	'', 	'',
142 [0x28]	'', 	No, 	Shift,	'', 	'', 	'', 	'', 	'',
143 [0x30]	'', 	'', 	'
144 ', 	'', 	'', 	'', 	Shift,	'\n',
145 [0x38]	Latin,	No, 	Ctrl,	'', 	'', 	'', 	'', 	'',
146 [0x40]	'', 	'', 	'', 	'
147 ', 	'', 	'', 	'', 	'',
148 [0x48]	'', 	'', 	'
149 ', 	'', 	'', 	'', 	'', 	'',
150 [0x50]	'', 	'', 	'', 	'', 	No,	No,	No,	'',
151 [0x58]	'', 	No,	No,	No,	No,	No,	No,	No,
152 [0x60]	No,	No,	No,	No,	No,	No,	No,	No,
153 [0x68]	No,	No,	No,	No,	No,	No,	No,	No,
154 [0x70]	No,	No,	No,	No,	No,	No,	No,	No,
155 [0x78]	No,	'', 	No,	'\b',	No,	No,	No,	No,
156 };
157 
158 int mouseshifted;
159 void (*kbdmouse)(int);
160 
161 static int kdebug;
162 
163 typedef struct Kbscan Kbscan;
164 struct Kbscan {
165 	int	esc1;
166 	int	esc2;
167 	int	alt;
168 	int	altgr;
169 	int	caps;
170 	int	ctl;
171 	int	num;
172 	int	shift;
173 	int	collecting;
174 	int	nk;
175 	Rune	kc[5];
176 	int	buttons;
177 };
178 
179 Kbscan kbscans[Nscans];	/* kernel and external scan code state */
180 
kbdputsc(int c,int external)181 /*
182  * Scan code processing
183  */
184 void
185 kbdputsc(int c, int external)
186 {
187 	int i, keyup;
188 	Kbscan *kbscan;
189 
190 	if(external)
191 		kbscan = &kbscans[Ext];
192 	else
193 		kbscan = &kbscans[Int];
194 
195 	if(kdebug)
196 		print("sc %x ms %d\n", c, mouseshifted);
197 	/*
198 	 *  e0's is the first of a 2 character sequence, e1 the first
199 	 *  of a 3 character sequence (on the safari)
200 	 */
201 	if(c == 0xe0){
202 		kbscan->esc1 = 1;
203 		return;
204 	} else if(c == 0xe1){
205 		kbscan->esc2 = 2;
206 		return;
207 	}
208 
209 	keyup = c & 0x80;
210 	c &= 0x7f;
211 	if(c > sizeof kbtab){
212 		c |= keyup;
213 		if(c != 0xFF)	/* these come fairly often: CAPSLOCK U Y */
214 			print("unknown key %ux\n", c);
215 		return;
216 	}
217 
218 	if(kbscan->esc1){
219 		c = kbtabesc1[c];
220 		kbscan->esc1 = 0;
221 	} else if(kbscan->esc2){
222 		kbscan->esc2--;
223 		return;
224 	} else if(kbscan->shift)
225 		c = kbtabshift[c];
226 	else if(kbscan->altgr)
227 		c = kbtabaltgr[c];
228 	else if(kbscan->ctl)
229 		c = kbtabctrl[c];
230 	else
231 		c = kbtab[c];
232 
233 	if(kbscan->caps && c<='z' && c>='a')
234 		c += 'A' - 'a';
235 
236 	/*
237 	 *  keyup only important for shifts
238 	 */
239 	if(keyup){
240 		switch(c){
241 		case Latin:
242 			kbscan->alt = 0;
243 			break;
244 		case Shift:
245 			kbscan->shift = 0;
246 			mouseshifted = 0;
247 			if(kdebug)
248 				print("shiftclr\n");
249 			break;
250 		case Ctrl:
251 			kbscan->ctl = 0;
252 			break;
253 		case Altgr:
254 			kbscan->altgr = 0;
255 			break;
256 		case Kmouse|1:
257 		case Kmouse|2:
258 		case Kmouse|3:
259 		case Kmouse|4:
260 		case Kmouse|5:
261 			kbscan->buttons &= ~(1<<(c-Kmouse-1));
262 			if(kbdmouse)
263 				kbdmouse(kbscan->buttons);
264 			break;
265 		}
266 		return;
267 	}
268 
269 	/*
270 	 *  normal character
271 	 */
272 	if(!(c & (Spec|KF))){
273 		if(kbscan->ctl)
274 			if(kbscan->alt && c == Del)
275 				exit(0);
276 		if(!kbscan->collecting){
277 			kbdputc(kbdq, c);
278 			return;
279 		}
280 		kbscan->kc[kbscan->nk++] = c;
281 		c = latin1(kbscan->kc, kbscan->nk);
282 		if(c < -1)	/* need more keystrokes */
283 			return;
284 		if(c != -1)	/* valid sequence */
285 			kbdputc(kbdq, c);
286 		else	/* dump characters */
287 			for(i=0; i<kbscan->nk; i++)
288 				kbdputc(kbdq, kbscan->kc[i]);
289 		kbscan->nk = 0;
290 		kbscan->collecting = 0;
291 		return;
292 	} else {
293 		switch(c){
294 		case Caps:
295 			kbscan->caps ^= 1;
296 			return;
297 		case Num:
298 			kbscan->num ^= 1;
299 			return;
300 		case Shift:
301 			kbscan->shift = 1;
302 			if(kdebug)
303 				print("shift\n");
304 			mouseshifted = 1;
305 			return;
306 		case Latin:
307 			kbscan->alt = 1;
308 			/*
309 			 * VMware and Qemu use Ctl-Alt as the key combination
310 			 * to make the VM give up keyboard and mouse focus.
311 			 * This has the unfortunate side effect that when you
312 			 * come back into focus, Plan 9 thinks you want to type
313 			 * a compose sequence (you just typed alt).
314 			 *
315 			 * As a clumsy hack around this, we look for ctl-alt
316 			 * and don't treat it as the start of a compose sequence.
317 			 */
318 			if(!kbscan->ctl){
319 				kbscan->collecting = 1;
320 				kbscan->nk = 0;
321 			}
322 			return;
323 		case Ctrl:
324 			kbscan->ctl = 1;
325 			return;
326 		case Altgr:
327 			kbscan->altgr = 1;
328 			return;
329 		case Kmouse|1:
330 		case Kmouse|2:
331 		case Kmouse|3:
332 		case Kmouse|4:
333 		case Kmouse|5:
334 			kbscan->buttons |= 1<<(c-Kmouse-1);
335 			if(kbdmouse)
336 				kbdmouse(kbscan->buttons);
337 			return;
338 		case KF|11:
339 			print("kbd debug on, F12 turns it off\n");
340 			kdebug = 1;
341 			break;
342 		case KF|12:
343 			kdebug = 0;
344 			break;
345 		}
346 	}
347 	kbdputc(kbdq, c);
348 }
349 
350 void
351 kbdenable(void)
352 {
353 #ifdef notdef
354 	kbdq = qopen(4*1024, 0, 0, 0);
355 	if(kbdq == nil)
356 		panic("kbdinit");
357 	qnoblock(kbdq, 1);
358 #endif
kbdputmap(ushort m,ushort scanc,Rune r)359 	kbscans[Int].num = 0;
360 }
361 
362 void
363 kbdputmap(ushort m, ushort scanc, Rune r)
364 {
365 	if(scanc >= Nscan)
366 		error(Ebadarg);
367 	switch(m) {
368 	default:
369 		error(Ebadarg);
370 	case 0:
371 		kbtab[scanc] = r;
372 		break;
373 	case 1:
374 		kbtabshift[scanc] = r;
375 		break;
376 	case 2:
377 		kbtabesc1[scanc] = r;
378 		break;
379 	case 3:
380 		kbtabaltgr[scanc] = r;
381 		break;
382 	case 4:
383 		kbtabctrl[scanc] = r;
384 		break;
kbdgetmap(uint offset,int * t,int * sc,Rune * r)385 	}
386 }
387 
388 int
389 kbdgetmap(uint offset, int *t, int *sc, Rune *r)
390 {
391 	if ((int)offset < 0)
392 		error(Ebadarg);
393 	*t = offset/Nscan;
394 	*sc = offset%Nscan;
395 	switch(*t) {
396 	default:
397 		return 0;
398 	case 0:
399 		*r = kbtab[*sc];
400 		return 1;
401 	case 1:
402 		*r = kbtabshift[*sc];
403 		return 1;
404 	case 2:
405 		*r = kbtabesc1[*sc];
406 		return 1;
407 	case 3:
408 		*r = kbtabaltgr[*sc];
409 		return 1;
410 	case 4:
411 		*r = kbtabctrl[*sc];
412 		return 1;
413 	}
414 }
415