static uint8_t process_keyboard(inode_t* inode, struct tty_context* tio, int fd, int* pos) { keyboard_t k; if(sys_read(fd, &k, sizeof(keyboard_t)) == 0) { errno = EIO; return 0; } switch(k.vkey) { case KEY_LEFTALT: tty_keys = !!(k.down) ? tty_keys | K_ALT : tty_keys & ~K_ALT; return 0; case KEY_RIGHTALT: tty_keys = !!(k.down) ? tty_keys | K_ALTGR : tty_keys & ~K_ALTGR; return 0; case KEY_LEFTSHIFT: case KEY_RIGHTSHIFT: tty_keys = !!(k.down) ? tty_keys | K_SHIFT : tty_keys & ~K_SHIFT; return 0; case KEY_LEFTCTRL: case KEY_RIGHTCTRL: tty_keys = !!(k.down) ? tty_keys | K_CTRL : tty_keys & ~K_CTRL; return 0; case KEY_CAPSLOCK: tty_capslock = !(k.down) ? tty_capslock : !tty_capslock; return 0; default: break; } if(!k.down) return 0; int16_t key; uint8_t ch; switch(tty_keys) { #define _(x, y) \ case x : { key = tty_keymap.y[k.vkey] & 0x0FFF; break; } _(0, plain); _(K_SHIFT, shift); _(K_ALTGR, altgr); _(K_SHIFT | K_ALTGR, shift_altgr); _(K_CTRL, ctrl); _(K_SHIFT | K_CTRL, shift_ctrl); _(K_ALTGR | K_CTRL, altgr_ctrl); _(K_ALTGR | K_SHIFT | K_CTRL, altgr_shift_ctrl); _(K_ALT, alt); _(K_SHIFT | K_ALT, shift_alt); _(K_ALTGR | K_ALT, altgr_alt); _(K_ALTGR | K_SHIFT | K_ALT, altgr_shift_alt); _(K_CTRL | K_ALT, ctrl_alt); _(K_SHIFT | K_CTRL | K_ALT, shift_ctrl_alt); _(K_ALTGR | K_CTRL | K_ALT, altgr_ctrl_alt); _(K_ALTGR | K_SHIFT | K_CTRL | K_ALT, altgr_shift_ctrl_alt); default: key = 0; break; #undef _ } ch = KVAL(key); switch(KTYP(key)) { case KT_LATIN: case KT_LETTER: if(tty_capslock) { if(tty_keys & K_SHIFT) ch += ch >= 'A' && ch <= 'z' ? 32 : 0; else ch -= ch >= 'a' && ch <= 'Z' ? 32 : 0; } case KT_ASCII: break; case KT_SPEC: case KT_PAD: if(!__kmap[KTYP(key)] || !__kmap[KTYP(key)][KVAL(key)]) return 0; ch = __kmap[KTYP(key)][KVAL(key)][0]; break; default: if(!__kmap[KTYP(key)] || !__kmap[KTYP(key)][KVAL(key)]) return 0; fifo_write(&tio->in, __kmap[KTYP(key)][KVAL(key)], strlen(__kmap[KTYP(key)][KVAL(key)])); *pos = *pos + strlen(__kmap[KTYP(key)][KVAL(key)]); if(tio->ios.c_lflag & ECHO) tty_output_write(inode, __kmap[KTYP(key)][KVAL(key)], 0, strlen(__kmap[KTYP(key)][KVAL(key)])); return 0; } return ch; }
int tty_read(struct inode* inode, void* ptr, off_t pos, size_t len) { if(unlikely(!inode || !ptr)) { errno = EINVAL; return -1; } if(unlikely(!inode->userdata)) { errno = EINVAL; return -1; } if(unlikely(!len)) return 0; struct tty_context* tio = (struct tty_context*) inode->userdata; uint8_t* buf = (uint8_t*) ptr; int p = 0; if(tio->pgrp != current_task->pgid) sys_exit((1 << 31) | W_STOPCODE(SIGTTIN)); int fd = sys_open(TTY_DEFAULT_INPUT_DEVICE, O_RDONLY, 0); if(fd < 0) { errno = EIO; return -1; } if(fifo_available(&tio->in)) { char tmp[BUFSIZ]; for(int j = 0; (j = fifo_read(&tio->in, tmp, sizeof(tmp))) > 0;) fifo_write(&tio->uin, tmp, j); } while(p < len) { uint8_t ch; if(fifo_available(&tio->uin)) fifo_read(&tio->uin, &ch, sizeof(ch)); else ch = process_keyboard(inode, tio, fd, &p); switch(ch) { case 0: continue; case '\b': case '\x7f': if(tio->ios.c_lflag & ICANON) { if(p > 0) { fifo_peek(&tio->in, 1); p--; if(tio->ios.c_lflag & ECHOE) ch = '\b'; else ch = '\x7f'; if(tio->ios.c_lflag & ECHO) tty_output_write(inode, &ch, 0, 1); } continue; } /* No processing */ ch = '\b'; break; default: break; } if(unlikely(ch < 32)) { for(int i = 0; i < NCCS; i++) { if(ch != tio->ios.c_cc[i]) continue; fifo_write(&tio->in, &ch, 1); p++; ch = 0; break; } if(unlikely(!ch)) continue; } if(!(tio->ios.c_iflag & IGNCR)) { if(ch == '\n') break; } char utf8[UTF8_MAX_LENGTH]; size_t utf8len = ucs2_to_utf8((int32_t) ch, utf8); fifo_write(&tio->in, utf8, utf8len); p += utf8len; if(tio->ios.c_lflag & ECHO) tty_output_write(inode, utf8, 0, utf8len); } if(p < len) { if(!(tio->ios.c_iflag & IGNCR)) { char ch = '\n'; fifo_write(&tio->in, &ch, 1); p++; if((tio->ios.c_lflag & ECHO) || (tio->ios.c_lflag & ICANON && tio->ios.c_lflag & ECHONL)) tty_output_write(inode, &ch, 0, 1); } } else p = len; if(fifo_available(&tio->in)) fifo_read(&tio->in, buf, p); sys_close(fd); return p; }
void __printk_emit_tty(char c) { tty_output_write(printk_tty->selfdevice, &c, 1, 0); if (c == '\n') __printk_emit_tty('\r'); }