console.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477
  1. #include <u.h>
  2. #include <libc.h>
  3. enum {
  4. Spec = 0xF800, /* Unicode private space */
  5. PF = Spec|0x20, /* num pad function key */
  6. View = Spec|0x00, /* view (shift window up) */
  7. Shift = Spec|0x60,
  8. Break = Spec|0x61,
  9. Ctrl = Spec|0x62,
  10. Alt = Spec|0x63,
  11. Caps = Spec|0x64,
  12. Num = Spec|0x65,
  13. Middle = Spec|0x66,
  14. Altgr = Spec|0x67,
  15. Kmouse = Spec|0x100,
  16. No = 0x00, /* peter */
  17. KF = 0xF000, /* function key (begin Unicode private space) */
  18. Home = KF|13,
  19. Up = KF|14,
  20. Pgup = KF|15,
  21. Print = KF|16,
  22. Left = KF|17,
  23. Right = KF|18,
  24. End = KF|24,
  25. Down = View,
  26. Pgdown = KF|19,
  27. Ins = KF|20,
  28. Del = 0x7F,
  29. Scroll = KF|21,
  30. };
  31. typedef struct Keybscan Keybscan;
  32. struct Keybscan {
  33. int esc1;
  34. int esc2;
  35. int alt;
  36. int altgr;
  37. int caps;
  38. int ctl;
  39. int num;
  40. int shift;
  41. int collecting;
  42. int nk;
  43. Rune kc[5];
  44. int buttons;
  45. };
  46. static Keybscan kbscan;
  47. static Rune kbtab[256] =
  48. {
  49. [0x00] No, '\x1b', '1', '2', '3', '4', '5', '6',
  50. [0x08] '7', '8', '9', '0', '-', '=', '\b', '\t',
  51. [0x10] 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i',
  52. [0x18] 'o', 'p', '[', ']', '\n', Ctrl, 'a', 's',
  53. [0x20] 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';',
  54. [0x28] '\'', '`', Shift, '\\', 'z', 'x', 'c', 'v',
  55. [0x30] 'b', 'n', 'm', ',', '.', '/', Shift, '*',
  56. [0x38] Alt, ' ', Ctrl, KF|1, KF|2, KF|3, KF|4, KF|5,
  57. [0x40] KF|6, KF|7, KF|8, KF|9, KF|10, Num, Scroll, '7',
  58. [0x48] '8', '9', '-', '4', '5', '6', '+', '1',
  59. [0x50] '2', '3', '0', '.', No, No, No, KF|11,
  60. [0x58] KF|12, No, No, No, No, No, No, No,
  61. [0x60] No, No, No, No, No, No, No, No,
  62. [0x68] No, No, No, No, No, No, No, No,
  63. [0x70] No, No, No, No, No, No, No, No,
  64. [0x78] No, View, No, Up, No, No, No, No,
  65. };
  66. static Rune kbtabshift[256] =
  67. {
  68. [0x00] No, '\x1b', '!', '@', '#', '$', '%', '^',
  69. [0x08] '&', '*', '(', ')', '_', '+', '\b', '\t',
  70. [0x10] 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I',
  71. [0x18] 'O', 'P', '{', '}', '\n', Ctrl, 'A', 'S',
  72. [0x20] 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':',
  73. [0x28] '"', '~', Shift, '|', 'Z', 'X', 'C', 'V',
  74. [0x30] 'B', 'N', 'M', '<', '>', '?', Shift, '*',
  75. [0x38] Alt, ' ', Ctrl, KF|1, KF|2, KF|3, KF|4, KF|5,
  76. [0x40] KF|6, KF|7, KF|8, KF|9, KF|10, Num, Scroll, '7',
  77. [0x48] '8', '9', '-', '4', '5', '6', '+', '1',
  78. [0x50] '2', '3', '0', '.', No, No, No, KF|11,
  79. [0x58] KF|12, No, No, No, No, No, No, No,
  80. [0x60] No, No, No, No, No, No, No, No,
  81. [0x68] No, No, No, No, No, No, No, No,
  82. [0x70] No, No, No, No, No, No, No, No,
  83. [0x78] No, Up, No, Up, No, No, No, No,
  84. };
  85. static Rune kbtabesc1[256] =
  86. {
  87. [0x00] No, No, No, No, No, No, No, No,
  88. [0x08] No, No, No, No, No, No, No, No,
  89. [0x10] No, No, No, No, No, No, No, No,
  90. [0x18] No, No, No, No, '\n', Ctrl, No, No,
  91. [0x20] No, No, No, No, No, No, No, No,
  92. [0x28] No, No, Shift, No, No, No, No, No,
  93. [0x30] No, No, No, No, No, '/', No, Print,
  94. [0x38] Altgr, No, No, No, No, No, No, No,
  95. [0x40] No, No, No, No, No, No, Break, Home,
  96. [0x48] Up, Pgup, No, Left, No, Right, No, End,
  97. [0x50] Down, Pgdown, Ins, Del, No, No, No, No,
  98. [0x58] No, No, No, No, No, No, No, No,
  99. [0x60] No, No, No, No, No, No, No, No,
  100. [0x68] No, No, No, No, No, No, No, No,
  101. [0x70] No, No, No, No, No, No, No, No,
  102. [0x78] No, Up, No, No, No, No, No, No,
  103. };
  104. static Rune kbtabaltgr[256] =
  105. {
  106. [0x00] No, No, No, No, No, No, No, No,
  107. [0x08] No, No, No, No, No, No, No, No,
  108. [0x10] No, No, No, No, No, No, No, No,
  109. [0x18] No, No, No, No, '\n', Ctrl, No, No,
  110. [0x20] No, No, No, No, No, No, No, No,
  111. [0x28] No, No, Shift, No, No, No, No, No,
  112. [0x30] No, No, No, No, No, '/', No, Print,
  113. [0x38] Altgr, No, No, No, No, No, No, No,
  114. [0x40] No, No, No, No, No, No, Break, Home,
  115. [0x48] Up, Pgup, No, Left, No, Right, No, End,
  116. [0x50] Down, Pgdown, Ins, Del, No, No, No, No,
  117. [0x58] No, No, No, No, No, No, No, No,
  118. [0x60] No, No, No, No, No, No, No, No,
  119. [0x68] No, No, No, No, No, No, No, No,
  120. [0x70] No, No, No, No, No, No, No, No,
  121. [0x78] No, Up, No, No, No, No, No, No,
  122. };
  123. static Rune kbtabctrl[256] =
  124. {
  125. [0x00] No, '\x1b', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16',
  126. [0x08] '\x17', '\x18', '\x19', '\x10', '\n', '\x1d', '\b', '\t',
  127. [0x10] '\x11', '\x17', '\x05', '\x12', '\x14', '\x19', '\x15', '\t',
  128. [0x18] '\x0f', '\x10', '\x1b', '\x1d', '\n', Ctrl, '\x01', '\x13',
  129. [0x20] '\x04', '\x06', '\x07', '\b', '\n', '\x0b', '\x0c', '\x1b',
  130. [0x28] '\x07', No, Shift, '\x1c', '\x1a', '\x18', '\x03', '\x16',
  131. [0x30] '\x02', '\x0e', '\n', '\x0c', '\x0e', '\x0f', Shift, '\n',
  132. [0x38] Alt, No, Ctrl, '\x05', '\x06', '\x07', '\x04', '\x05',
  133. [0x40] '\x06', '\x07', '\x0c', '\n', '\x0e', '\x05', '\x06', '\x17',
  134. [0x48] '\x18', '\x19', '\n', '\x14', '\x15', '\x16', '\x0b', '\x11',
  135. [0x50] '\x12', '\x13', '\x10', '\x0e', No, No, No, '\x0f',
  136. [0x58] '\x0c', No, No, No, No, No, No, No,
  137. [0x60] No, No, No, No, No, No, No, No,
  138. [0x68] No, No, No, No, No, No, No, No,
  139. [0x70] No, No, No, No, No, No, No, No,
  140. [0x78] No, '\x07', No, '\b', No, No, No, No,
  141. };
  142. int
  143. keybscan(uint8_t code, char *out, int len)
  144. {
  145. Rune c;
  146. int keyup;
  147. int off;
  148. c = code;
  149. off = 0;
  150. if(len < 16){
  151. fprint(2, "keybscan: input buffer too short to be safe\n");
  152. return -1;
  153. }
  154. if(c == 0xe0){
  155. kbscan.esc1 = 1;
  156. return off;
  157. } else if(c == 0xe1){
  158. kbscan.esc2 = 2;
  159. return off;
  160. }
  161. keyup = c&0x80;
  162. c &= 0x7f;
  163. if(c > sizeof kbtab){
  164. c |= keyup;
  165. if(c != 0xFF) /* these come fairly often: CAPSLOCK U Y */
  166. fprint(2, "unknown key %ux\n", c);
  167. return off;
  168. }
  169. if(kbscan.esc1){
  170. c = kbtabesc1[c];
  171. kbscan.esc1 = 0;
  172. } else if(kbscan.esc2){
  173. kbscan.esc2--;
  174. return off;
  175. } else if(kbscan.shift)
  176. c = kbtabshift[c];
  177. else if(kbscan.altgr)
  178. c = kbtabaltgr[c];
  179. else if(kbscan.ctl)
  180. c = kbtabctrl[c];
  181. else
  182. c = kbtab[c];
  183. if(kbscan.caps && c<='z' && c>='a')
  184. c += 'A' - 'a';
  185. /*
  186. * keyup only important for shifts
  187. */
  188. if(keyup){
  189. switch(c){
  190. case Alt:
  191. kbscan.alt = 0;
  192. break;
  193. case Shift:
  194. kbscan.shift = 0;
  195. /*mouseshifted = 0;*/
  196. break;
  197. case Ctrl:
  198. kbscan.ctl = 0;
  199. break;
  200. case Altgr:
  201. kbscan.altgr = 0;
  202. break;
  203. case Kmouse|1:
  204. case Kmouse|2:
  205. case Kmouse|3:
  206. case Kmouse|4:
  207. case Kmouse|5:
  208. kbscan.buttons &= ~(1<<(c-Kmouse-1));
  209. /*if(kbdmouse)kbdmouse(kbscan.buttons);*/
  210. break;
  211. }
  212. return off;
  213. }
  214. /*
  215. * normal character
  216. */
  217. if(!(c & (Spec|KF))){
  218. off += runetochar(out+off, &c);
  219. return off;
  220. } else {
  221. switch(c){
  222. case Caps:
  223. kbscan.caps ^= 1;
  224. return off;
  225. case Num:
  226. kbscan.num ^= 1;
  227. return off;
  228. case Shift:
  229. kbscan.shift = 1;
  230. /*mouseshifted = 1;*/
  231. return off;
  232. case Alt:
  233. kbscan.alt = 1;
  234. /*
  235. * VMware and Qemu use Ctl-Alt as the key combination
  236. * to make the VM give up keyboard and mouse focus.
  237. * This has the unfortunate side effect that when you
  238. * come back into focus, Plan 9 thinks you want to type
  239. * a compose sequence (you just typed alt).
  240. *
  241. * As a clumsy hack around this, we look for ctl-alt
  242. * and don't treat it as the start of a compose sequence.
  243. */
  244. return off;
  245. case Ctrl:
  246. kbscan.ctl = 1;
  247. return off;
  248. case Altgr:
  249. kbscan.altgr = 1;
  250. return off;
  251. case Kmouse|1:
  252. case Kmouse|2:
  253. case Kmouse|3:
  254. case Kmouse|4:
  255. case Kmouse|5:
  256. kbscan.buttons |= 1<<(c-Kmouse-1);
  257. /*if(kbdmouse)kbdmouse(kbscan.buttons);*/
  258. return off;
  259. }
  260. }
  261. off += runetochar(out+off, &c);
  262. return off;
  263. }
  264. enum {
  265. Black = 0x00,
  266. Blue = 0x01,
  267. Green = 0x02,
  268. Cyan = 0x03,
  269. Red = 0x04,
  270. Magenta = 0x05,
  271. Brown = 0x06,
  272. Grey = 0x07,
  273. Bright = 0x08,
  274. Blinking = 0x80,
  275. Attr = (Black<<4)|Grey, /* (background<<4)|foreground */
  276. Cursor = (Grey<<4)|Black,
  277. };
  278. enum {
  279. Width = 80*2,
  280. Height = 25,
  281. };
  282. int cgapos;
  283. uint8_t CGA[16384];
  284. static void
  285. cgaputc(int c)
  286. {
  287. int i;
  288. uint8_t *cga, *p;
  289. cga = CGA;
  290. cga[cgapos] = ' ';
  291. cga[cgapos+1] = Attr;
  292. switch(c){
  293. case '\r':
  294. break;
  295. case '\n':
  296. cgapos = cgapos/Width;
  297. cgapos = (cgapos+1)*Width;
  298. break;
  299. case '\t':
  300. i = 8 - ((cgapos/2)&7);
  301. while(i-- > 0)
  302. cgaputc(' ');
  303. break;
  304. case '\b':
  305. if(cgapos >= 2)
  306. cgapos -= 2;
  307. break;
  308. default:
  309. cga[cgapos++] = c;
  310. cga[cgapos++] = Attr;
  311. break;
  312. }
  313. if(cgapos >= (Width*Height)){
  314. memmove(cga, &cga[Width], Width*(Height-1));
  315. p = &cga[Width*(Height-1)];
  316. for(i = 0; i < Width/2; i++){
  317. *p++ = ' ';
  318. *p++ = Attr;
  319. }
  320. cgapos -= Width;
  321. }
  322. cga[cgapos] = ' ';
  323. cga[cgapos+1] = Cursor;
  324. }
  325. static void
  326. cgawrite(uint8_t *buf, int len)
  327. {
  328. int i;
  329. for(i = 0; i < len; i++)
  330. cgaputc(buf[i]);
  331. }
  332. static void
  333. cgaflush(int fd)
  334. {
  335. pwrite(fd, CGA, Width*Height, 0);
  336. }
  337. void
  338. main(int argc, char *argv[])
  339. {
  340. int ps2fd, cgafd;
  341. int pid, wpid;
  342. int i, n, off, len;
  343. int frchld[2];
  344. int tochld[2];
  345. static uint8_t ibuf[32];
  346. static char buf[8*sizeof ibuf];
  347. if(argc < 2){
  348. fprint(2, "usage: %s cmd args...\n", argv[0]);
  349. exits("usage");
  350. }
  351. if((ps2fd = open("#P/ps2keyb", OREAD)) == -1){
  352. errstr(buf, sizeof buf);
  353. fprint(2, "open #P/ps2keyb: %s\n", buf);
  354. exits("open");
  355. }
  356. if((cgafd = open("#P/cgamem", OWRITE)) == -1){
  357. errstr(buf, sizeof buf);
  358. fprint(2, "open #P/cgamem: %s\n", buf);
  359. exits("open");
  360. }
  361. pipe(frchld);
  362. pipe(tochld);
  363. // rfnameg to put command into a new pgid (in case we are init)
  364. switch(pid = rfork(RFPROC|RFFDG|RFNOTEG|RFNAMEG)){
  365. case -1:
  366. exits("fork");
  367. case 0:
  368. close(ps2fd);
  369. close(cgafd);
  370. close(tochld[0]);
  371. close(frchld[1]);
  372. dup(tochld[1], 0);
  373. dup(frchld[0], 1);
  374. dup(frchld[0], 2);
  375. close(tochld[1]);
  376. close(frchld[0]);
  377. exec(argv[1], argv+1);
  378. exits("exec");
  379. default:
  380. close(tochld[1]);
  381. close(frchld[0]);
  382. break;
  383. }
  384. switch(wpid = rfork(RFPROC|RFFDG)){
  385. case -1:
  386. exits("rfork");
  387. case 0:
  388. off = 0;
  389. close(cgafd);
  390. close(frchld[1]);
  391. while((len = read(ps2fd, ibuf, sizeof ibuf)) > 0){
  392. for(i = 0; i < len; i++){
  393. if((n = keybscan(ibuf[i], buf+off, sizeof buf - off)) == -1){
  394. fprint(2, "keybscan -1\n");
  395. break;
  396. }
  397. off += n;
  398. }
  399. if(off > 0){
  400. write(tochld[0], buf, off);
  401. off = 0;
  402. }
  403. }
  404. postnote(PNPROC, getppid(), "interrupt");
  405. exits(nil);
  406. default:
  407. close(0);
  408. close(ps2fd);
  409. close(tochld[0]);
  410. while((n = read(frchld[1], buf, sizeof buf)) >= 0){
  411. Dir *dirp;
  412. if(n > 0){
  413. cgawrite(buf, n);
  414. }
  415. if((dirp = dirfstat(frchld[1])) != nil){
  416. if(dirp->length == 0)
  417. cgaflush(cgafd);
  418. free(dirp);
  419. } else {
  420. cgaflush(cgafd);
  421. }
  422. }
  423. if(len == -1){
  424. errstr(buf, sizeof buf);
  425. fprint(2, "read %s: %s\n", argv[1], buf);
  426. exits("read");
  427. }
  428. close(cgafd);
  429. postnote(PNPROC, wpid, "interrupt");
  430. postnote(PNPROC, pid, "interrupt");
  431. waitpid();
  432. waitpid();
  433. }
  434. exits(nil);
  435. }