#include "inc.h" #include typedef u8int u8; typedef u16int u16; enum { WIDTH = 576, HEIGHT = 454 }; int borderw, borderh; RKeyboardctl *kbctl; Mousectl *mctl; Image *fbimg; u8 fb[WIDTH*HEIGHT]; u8 readbuf[64*1024]; int netfd; u16 b2w(u8 *b) { return b[0] | b[1]<<8; } void w2b(u8 *b, u16 w) { b[0] = w; b[1] = w>>8; } void msgheader(u8 *b, u8 type, u16 length) { w2b(b, length); b[2] = type; } /* These bits are directly sent to the 11 */ enum { MOD_RSHIFT = 0100, MOD_LSHIFT = 0200, MOD_RTOP = 00400, MOD_LTOP = 01000, MOD_RCTRL = 02000, MOD_LCTRL = 04000, MOD_RMETA = 010000, MOD_LMETA = 020000, MOD_SLOCK = 040000, }; #define MOD_SHIFT (MOD_LSHIFT | MOD_RSHIFT) #define MOD_CTRL (MOD_LCTRL | MOD_RCTRL) /* Map key symbols to Knight keyboard codes as best we can */ int symbolmap[128]; int fnmap[] = { 020, // F1 CALL 001, // F2 ESC 064, // F3 next/back 021, // F4 CLEAR -1, // F5 -1, // F6 -1, // F7 -1, // F8 -1, // F9 -1, // F10 -1, // F11 000, // F12 BREAK }; void initsymbolmap(void) { int i; for(i = 0; i < 128; i++) symbolmap[i] = -1; symbolmap[010] = 017; // BACKSPACE symbolmap[011] = 022; // TAB symbolmap[012] = 062; // RETURN symbolmap[033] = 023; // ALT MODE symbolmap[' '] = 077; symbolmap['!'] = 002 | MOD_LSHIFT; symbolmap['"'] = 003 | MOD_LSHIFT; symbolmap['#'] = 004 | MOD_LSHIFT; symbolmap['%'] = 006 | MOD_LSHIFT; symbolmap['$'] = 005 | MOD_LSHIFT; symbolmap['&'] = 007 | MOD_LSHIFT; symbolmap['\''] = 010 | MOD_LSHIFT; symbolmap['('] = 011 | MOD_LSHIFT; symbolmap[')'] = 012 | MOD_LSHIFT; symbolmap['*'] = 061 | MOD_LSHIFT; symbolmap['+'] = 060 | MOD_LSHIFT; symbolmap[','] = 074; symbolmap['-'] = 014; symbolmap['.'] = 075; symbolmap['/'] = 076; symbolmap['0'] = 013; symbolmap['1'] = 002; symbolmap['2'] = 003; symbolmap['3'] = 004; symbolmap['4'] = 005; symbolmap['5'] = 006; symbolmap['6'] = 007; symbolmap['7'] = 010; symbolmap['8'] = 011; symbolmap['9'] = 012; symbolmap[':'] = 061; symbolmap[';'] = 060; symbolmap['<'] = 074 | MOD_LSHIFT; symbolmap['='] = 014 | MOD_LSHIFT; symbolmap['>'] = 075 | MOD_LSHIFT; symbolmap['?'] = 076 | MOD_LSHIFT; symbolmap['@'] = 015; symbolmap['A'] = 047 | MOD_LSHIFT; symbolmap['B'] = 071 | MOD_LSHIFT; symbolmap['C'] = 067 | MOD_LSHIFT; symbolmap['D'] = 051 | MOD_LSHIFT; symbolmap['E'] = 026 | MOD_LSHIFT; symbolmap['F'] = 052 | MOD_LSHIFT; symbolmap['G'] = 053 | MOD_LSHIFT; symbolmap['H'] = 054 | MOD_LSHIFT; symbolmap['I'] = 033 | MOD_LSHIFT; symbolmap['J'] = 055 | MOD_LSHIFT; symbolmap['K'] = 056 | MOD_LSHIFT; symbolmap['L'] = 057 | MOD_LSHIFT; symbolmap['M'] = 073 | MOD_LSHIFT; symbolmap['N'] = 072 | MOD_LSHIFT; symbolmap['O'] = 034 | MOD_LSHIFT; symbolmap['P'] = 035 | MOD_LSHIFT; symbolmap['Q'] = 024 | MOD_LSHIFT; symbolmap['R'] = 027 | MOD_LSHIFT; symbolmap['S'] = 050 | MOD_LSHIFT; symbolmap['T'] = 030 | MOD_LSHIFT; symbolmap['U'] = 032 | MOD_LSHIFT; symbolmap['V'] = 070 | MOD_LSHIFT; symbolmap['W'] = 025 | MOD_LSHIFT; symbolmap['X'] = 066 | MOD_LSHIFT; symbolmap['Y'] = 031 | MOD_LSHIFT; symbolmap['Z'] = 065 | MOD_LSHIFT; symbolmap['['] = 036; symbolmap['\\'] = 040; symbolmap[']'] = 037; symbolmap['^'] = 016; symbolmap['_'] = 013 | MOD_LSHIFT; symbolmap['`'] = 015 | MOD_LSHIFT; symbolmap['a'] = 047; symbolmap['b'] = 071; symbolmap['c'] = 067; symbolmap['d'] = 051; symbolmap['e'] = 026; symbolmap['f'] = 052; symbolmap['g'] = 053; symbolmap['h'] = 054; symbolmap['i'] = 033; symbolmap['j'] = 055; symbolmap['k'] = 056; symbolmap['l'] = 057; symbolmap['m'] = 073; symbolmap['n'] = 072; symbolmap['o'] = 034; symbolmap['p'] = 035; symbolmap['q'] = 024; symbolmap['r'] = 027; symbolmap['s'] = 050; symbolmap['t'] = 030; symbolmap['u'] = 032; symbolmap['v'] = 070; symbolmap['w'] = 025; symbolmap['x'] = 066; symbolmap['y'] = 031; symbolmap['z'] = 065; symbolmap['{'] = 036 | MOD_LSHIFT; symbolmap['|'] = 040 | MOD_LSHIFT; symbolmap['}'] = 037 | MOD_LSHIFT; symbolmap['~'] = 016 | MOD_LSHIFT; symbolmap[0177] = 046; // RUBOUT } void redraw(void) { loadimage(fbimg, fbimg->r, fb, WIDTH*HEIGHT/8); draw(screen, rectaddpt(fbimg->r, screen->r.min), fbimg, nil, ZP); flushimage(display, 1); } enum { /* TV to 11 */ MSG_KEYDN = 0, MSG_GETFB, /* 11 to TV */ MSG_FB, MSG_WD, MSG_CLOSE, }; void unpackfb(u8 *src, int x, int y, int w, int h) { int i; u8 *dst; dst = fb; if(x == 0 && y == 0 && w == WIDTH && h == HEIGHT){ for(i = 0; i < WIDTH*HEIGHT/16; i++){ dst[0] = src[1]; dst[1] = src[0]; dst += 2; src += 2; } }else print("too dumb to unpack %d %d %d %d\n", x, y, w, h); } void getupdate(u16 addr, u16 wd) { addr *= 2; fb[addr+0] = wd>>8; fb[addr+1] = wd; } void getfb(void) { u8 *b, buf[11]; int x, y, w, h; x = 0; y = 0; w = WIDTH; h = HEIGHT; b = buf; msgheader(b, MSG_GETFB, 9); b += 3; w2b(b, x); w2b(b+2, y); w2b(b+4, w); w2b(b+6, h); write(netfd, buf, 11); } void protocol(void*) { u16 len; u8 *b, type; int x, y, w, h; b = readbuf; if(readn(netfd, b, 2) != 2) threadexitsall("botch"); print("%o %o\n", b[0], b[1]); getfb(); while(readn(netfd, &len, 2) == 2){ len = b2w((u8*)&len); b = readbuf; readn(netfd, b, len); type = *b++; switch(type){ case MSG_FB: x = b2w(b); y = b2w(b+2); w = b2w(b+4); h = b2w(b+6); b += 8; unpackfb(b, x*16, y, w*16, h); break; case MSG_WD: getupdate(b2w(b), b2w(b+2)); break; case MSG_CLOSE: close(netfd); break; default: print("unknown msg %d\n", type); } } threadexitsall(nil); } void resize(int w, int h) { int fd; fd = open("/dev/wctl", OWRITE); if(fd >= 0){ fprint(fd, "resize -dx %d -dy %d", w, h); close(fd); } } void mthread(void*) { static char *menustr[] = { "Exit", nil }; static Menu menu = { menustr }; int sel; while(readmouse(mctl) != -1){ if(mctl->buttons & 4) { sel = menuhit(3, mctl, &menu, _screen); switch(sel) { case 0: threadexitsall(nil); } } } } int curmod; int mapupper(int key) { // US layout hardcoded, this sucks if(key >= 'a' && key <= 'z') return key + 'A'-'a'; switch(key){ case '`': return '~'; case '1': return '!'; case '2': return '@'; case '3': return '#'; case '4': return '$'; case '5': return '%'; case '6': return '^'; case '7': return '&'; case '8': return '*'; case '9': return '('; case '0': return ')'; case '-': return '_'; case '=': return '+'; case '[': return '{'; case ']': return '}'; case '\\': return '|'; case ';': return ':'; case '\'': return '"'; case ',': return '<'; case '.': return '>'; case '/': return '?'; } return -1; } void keydown(int key) { int k; u8 buf[5]; switch(key){ case Kshift: curmod |= MOD_LSHIFT; break; case Kctl: curmod |= MOD_LCTRL; break; case Kalt: curmod |= MOD_LMETA; break; default: ; int mod = curmod; if(key >= 0 && key < 128) { if(curmod & MOD_LSHIFT && (k = mapupper(key)) > 0){ key = k; mod &= ~MOD_LSHIFT; } key = symbolmap[key]; } else if(key >= (KF|1) && key <= (KF|12)) key = fnmap[key - (KF|1)]; else break; if(key >= 0){ key |= mod; msgheader(buf, MSG_KEYDN, 3); w2b(buf+3, key); write(netfd, buf, 5); } } } void keyup(int key) { switch(key){ case Kshift: curmod &= ~MOD_LSHIFT; break; case Kctl: curmod &= ~MOD_LCTRL; break; case Kalt: curmod &= ~MOD_LMETA; break; } } void kbthread(void*) { char *s; Rune *prev, *down; prev = runesmprint(""); for(;;){ s = recvp(kbctl->c); switch(s[0]) { case 'c': break; case 'k': // down case 'K': // up down = runesmprint("%s", s+1); for(int i = 0; prev[i]; i++) if(runestrchr(down, prev[i]) == nil) keyup(prev[i]); for(int i = 0; down[i]; i++) if(runestrchr(prev, down[i]) == nil) keydown(down[i]); free(prev); prev = down; break; /* MOD_RTOP = 00400, MOD_LTOP = 01000, MOD_SLOCK = 040000, */ } // flushimage(display, 1); } } void resthread(void*) { threadsetname("resizethread"); for(;;){ recvul(mctl->resizec); if(getwindow(display, Refnone) < 0) sysfatal("resize failed: %r"); redraw(); } } void wctl(char *cmd) { int fd; if((fd = open("/dev/wctl", OWRITE)) < 0) return; fprint(fd, "%s", cmd); close(fd); } void threadmain(int argc, char *argv[]) { char *host = getenv("its"); if(argc > 1) host = argv[1]; if(host == nil) host = "its"; char *dialstr = smprint("tcp!%s!11100", host); netfd = dial(dialstr, nil, nil, nil); if(netfd < 0){ fprint(2, "couldn't dial %s\n", dialstr); exits("no connection"); } //rfork(RFENVG); //newwindow("-dx 576 -dy 454"); wctl("resize -dx 576 -dy 454"); if(initdraw(nil, nil, "tvcon") < 0) sysfatal("initdraw: %r"); kbctl = initkbd(nil, nil); if(kbctl == nil) sysfatal("inikeyboard: %r"); mctl = initmouse(nil, screen); if(mctl == nil) sysfatal("initmouse: %r"); fbimg = allocimage(display, Rect(0, 0, WIDTH, HEIGHT), CHAN1(CMap, 1), 0, 0); initsymbolmap(); threadcreate(mthread, nil, mainstacksize); threadcreate(kbthread, nil, mainstacksize); threadcreate(resthread, nil, mainstacksize); borderw = WIDTH - Dx(screen->r); borderh = HEIGHT - Dy(screen->r); resize(WIDTH + borderw, HEIGHT + borderh); proccreate(protocol, nil, mainstacksize); for(;;){ redraw(); yield(); } }