#include #include #include #include #include #include #include //#include // XXX Linux botch #include #include extern const char *__progname; typedef struct client CLIENT; struct client { CLIENT *flink; CLIENT *blink; int fd; int pid; int bid; char *peertext; int state; int downp; int buttons; int dx; int dy; int prevbuttons; } ; static int uifd; static int accfd; static int accid; static CLIENT *allclients; static const int keys[] = { #define FOO(x) KEY_##x, #include "keys" #undef FOO }; /* * We want to initialize unused elements to -1. If we don't mention * them at all, C initializes them to 0. As it happens, no KEY_* is * zero, but we don't want to depend on that (though I am willing to * depend on none of them being -1...hmm, maybe I should fix that). * * But C does promise that, if we initialize a given element more than * once, the last value is the one that sticks. So we initialize the * whole array to -1, then (re)initialize the elements we want to be * other than -1. */ #define R4(n) n, n, n, n #define R16(n) R4(n), R4(n), R4(n), R4(n) #define R64(n) R16(n), R16(n), R16(n), R16(n) static const signed short int map_sun[128] = { [0] = R64(-1), R64(-1), [0x05] = KEY_F1, // F1 [0x06] = KEY_F2, // F2 [0x08] = KEY_F3, // F3 [0x0a] = KEY_F4, // F4 [0x0c] = KEY_F5, // F5 [0x0e] = KEY_F6, // F6 [0x10] = KEY_F7, // F7 [0x11] = KEY_F8, // F8 [0x12] = KEY_F9, // F9 [0x15] = KEY_F10, // R1 [0x16] = KEY_F11, // R2 [0x17] = KEY_F12, // R3 [0x1d] = KEY_ESC, // ESC [0x1e] = KEY_1, // 1! [0x1f] = KEY_2, // 2@ [0x20] = KEY_3, // 3# [0x21] = KEY_4, // 4$ [0x22] = KEY_5, // 5% [0x23] = KEY_6, // 6^ [0x24] = KEY_7, // 7& [0x25] = KEY_8, // 8* [0x26] = KEY_9, // 9( [0x27] = KEY_0, // 0) [0x28] = KEY_MINUS, // -_ [0x29] = KEY_EQUAL, // =+ [0x58] = KEY_BACKSLASH, // \| [0x2a] = KEY_GRAVE, // `~ [0x2b] = KEY_DELETE, // BackSpace [0x35] = KEY_TAB, // Tab [0x36] = KEY_Q, // Q [0x37] = KEY_W, // W [0x38] = KEY_E, // E [0x39] = KEY_R, // R [0x3a] = KEY_T, // T [0x3b] = KEY_Y, // Y [0x3c] = KEY_U, // U [0x3d] = KEY_I, // I [0x3e] = KEY_O, // O [0x3f] = KEY_P, // P [0x40] = KEY_LEFTBRACE, // [{ [0x41] = KEY_RIGHTBRACE, // ]} [0x45] = KEY_UP, // R8/up [0x4c] = KEY_LEFTCTRL, // Control [0x4d] = KEY_A, // A [0x4e] = KEY_S, // S [0x4f] = KEY_D, // D [0x50] = KEY_F, // F [0x51] = KEY_G, // G [0x52] = KEY_H, // H [0x53] = KEY_J, // J [0x54] = KEY_K, // K [0x55] = KEY_L, // L [0x56] = KEY_SEMICOLON, // ;: [0x57] = KEY_APOSTROPHE, // '" [0x59] = KEY_ENTER, // Return [0x5b] = KEY_LEFT, // R10/left [0x5d] = KEY_RIGHT, // R12/right [0x63] = KEY_LEFTSHIFT, // LShift [0x64] = KEY_Z, // Z [0x65] = KEY_X, // X [0x66] = KEY_C, // C [0x67] = KEY_V, // Vl [0x68] = KEY_B, // B [0x69] = KEY_N, // N [0x6a] = KEY_M, // M [0x6b] = KEY_COMMA, // ,< [0x6c] = KEY_DOT, // .> [0x6d] = KEY_SLASH, // /? [0x6e] = KEY_RIGHTSHIFT, // RShift [0x6f] = KEY_BACKSPACE, // LineFeed [0x71] = KEY_DOWN, // R14/down [0x79] = KEY_SPACE // space }; #undef R4 #undef R16 #undef R64 #include static void dlog(const char *, ...) __attribute__((__format__(__printf__,1,2))); static void dlog(const char *fmt, ...) { va_list ap; static int dfd = -1; static FILE *df; switch (dfd) { case -1: dfd = open("LOG.dbg",O_WRONLY|O_APPEND,0); if (dfd < 0) { dfd = -2; case -2: return; } df = fdopen(dfd,"a"); break; } va_start(ap,fmt); vfprintf(df,fmt,ap); va_end(ap); fflush(df); } static void gen(int type, int code, int val) { struct input_event ie; ie.type = type; ie.code = code; ie.value = val; ie.time.tv_sec = 0; ie.time.tv_usec = 0; write(uifd,&ie,sizeof(ie)); } static void down(int key) { dlog("key %d down\n",key); gen(EV_KEY,key,1); gen(EV_SYN,SYN_REPORT,0); } static void up(int key) { dlog("key %d up\n",key); gen(EV_KEY,key,0); gen(EV_SYN,SYN_REPORT,0); } static void mouse_event(CLIENT *c) { int any; dlog("buttons %d->%d (%d,%d)\n",c->buttons,c->prevbuttons,c->dx,c->dy); any = 0; if (c->buttons != c->prevbuttons) { if ((c->buttons ^ c->prevbuttons) & 1) gen(EV_KEY,BTN_LEFT,(c->buttons&1)?1:0); if ((c->buttons ^ c->prevbuttons) & 2) gen(EV_KEY,BTN_MIDDLE,(c->buttons&2)?1:0); if ((c->buttons ^ c->prevbuttons) & 4) gen(EV_KEY,BTN_RIGHT,(c->buttons&4)?1:0); c->prevbuttons = c->buttons; any = 1; } if (c->dx) { gen(EV_REL,REL_X,c->dx); any = 1; } if (c->dy) { gen(EV_REL,REL_Y,c->dy); any = 1; } if (any) gen(EV_SYN,SYN_REPORT,0); } static void teardown(void) { ioctl(uifd,UI_DEV_DESTROY,0); close(uifd); } static int sun_to_evkey(int sunkey) { if ((sunkey < 0) || (sunkey > 127)) return(-1); return(map_sun[sunkey]); } static int signed7(unsigned char v) { v &= 0x7f; if (v & 0x40) return(((int)v)-(int)0x80); else return(v); } static void setnb(int fd) { fcntl(fd,F_SETFL,fcntl(fd,F_GETFL,0)|O_NONBLOCK); } static int client_ibyte(CLIENT *c, unsigned char b) { int ikey; switch (c->state) { case 0: switch (b) { case 0x80 ... 0x87: c->buttons = b & 7; c->state = 1; break; case 0x88: c->downp = 1; c->state = 3; break; case 0x89: c->downp = 0; c->state = 3; break; case 0x8a: break; } break; case 1: if (b & 0x80) { c->state = 0; break; } c->dx = signed7(b); c->state = 2; break; case 2: if (b & 0x80) { c->state = 0; break; } // Linux dy is reverse of Sun mice c->dy = - signed7(b); mouse_event(c); c->state = 0; break; case 3: if (b & 0x80) { c->state = 0; break; } ikey = sun_to_evkey(b); if (ikey >= 0) { if (c->downp) down(ikey); else up(ikey); } c->state = 0; break; } } static int free_client(void *cv) { CLIENT *c; c = cv; aio_remove_block(c->bid); free(c); } static void close_client(CLIENT *c) { if (c->pid == AIO_NOID) return; aio_remove_poll(c->pid); c->pid = AIO_NOID; close(c->fd); c->fd = -1; free(c->peertext); c->peertext = 0; c->bid = aio_add_block(&free_client,c); } static void rd_client(void *cv) { CLIENT *c; unsigned char rbuf[256]; int nr; int i; c = cv; nr = read(c->fd,&rbuf[0],sizeof(rbuf)); if (nr < 0) { switch (errno) { case EINTR: case EWOULDBLOCK: return; break; } fprintf(stderr,"%s: read from %s: %s\n",__progname,c->peertext,strerror(errno)); close_client(c); return; } if (nr == 0) { close_client(c); return; } for (i=0;ifd = new; c->pid = aio_add_poll(new,&aio_rwtest_always,&aio_rwtest_never,&rd_client,0,c); c->bid = AIO_NOID; c->peertext = txt; c->state = 0; c->prevbuttons = 0; c->flink = allclients; c->blink = 0; if (allclients) allclients->blink = c; allclients = c; } static void setup(void) { struct uinput_setup setup; int i; struct sockaddr_in sin; uifd = open("/dev/uinput",O_WRONLY|O_NONBLOCK,0); if (uifd < 0) { fprintf(stderr,"%s: can't open /dev/uinput: %s\n",__progname,strerror(errno)); exit(1); } ioctl(uifd,UI_SET_EVBIT,EV_KEY); ioctl(uifd,UI_SET_KEYBIT,BTN_LEFT); ioctl(uifd,UI_SET_KEYBIT,BTN_MIDDLE); ioctl(uifd,UI_SET_KEYBIT,BTN_RIGHT); for (i=(sizeof(keys)/sizeof(keys[i]))-1;i>=0;i--) ioctl(uifd,UI_SET_KEYBIT,keys[i]); ioctl(uifd,UI_SET_EVBIT,EV_REL); ioctl(uifd,UI_SET_RELBIT,REL_X); ioctl(uifd,UI_SET_RELBIT,REL_Y); bzero(&setup,sizeof(setup)); setup.id.bustype = BUS_USB; setup.id.vendor = 0x0000; setup.id.product = 0x0000; strncpy(&setup.name[0],"None",sizeof(setup.name)); ioctl(uifd,UI_DEV_SETUP,&setup); ioctl(uifd,UI_DEV_CREATE); accfd = socket(AF_INET,SOCK_STREAM,0); if (accfd < 0) { fprintf(stderr,"%s: AF_INET SOCK_STREAM socket: %s\n",__progname,strerror(errno)); exit(1); } bzero(&sin,sizeof(sin)); // XXX API botch sin.sin_family = AF_INET; // sin.sin_len = sizeof(sin); XXX Linux botch bcopy("\xac\x10\0\7",&sin.sin_addr,4); sin.sin_port = htons(27114); if (bind(accfd,(void *)&sin,sizeof(sin)) < 0) { fprintf(stderr,"%s: bind to 172.16.0.7/27114: %s\n",__progname,strerror(errno)); exit(1); } if (listen(accfd,10) < 0) { fprintf(stderr,"%s: listen on 172.16.0.7/27114: %s\n",__progname,strerror(errno)); exit(1); } accid = aio_add_poll(accfd,&aio_rwtest_always,&aio_rwtest_never,&accept_new,0,0); } int main(void); int main(void) { aio_poll_init(); setup(); sleep(1); aio_event_loop(); return(0); }