/* KindlePDFViewer: input abstraction for Lua Copyright (C) 2011 Hans-Werner Hilse This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "popen-noshell/popen_noshell.h" #include #include #include #include #include #include #include #include #ifdef EMULATE_READER #include #define EMU_EV_DEV "emu_event" #endif #include "input.h" #include #include #define CODE_IN_SAVER 10000 #define CODE_OUT_SAVER 10001 #define CODE_USB_PLUG_IN 10010 #define CODE_USB_PLUG_OUT 10011 #define CODE_CHARGING 10020 #define CODE_NOT_CHARGING 10021 #define NUM_FDS 4 int inputfds[4] = { -1, -1, -1, -1 }; #ifndef EMULATE_READER pid_t slider_pid = -1; struct popen_noshell_pass_to_pclose pclose_arg; void slider_handler(int sig) { /* Kill lipc-wait-event properly on exit */ if(pclose_arg.pid != 0) { // Be a little more gracious, lipc seems to handle SIGINT properly kill(pclose_arg.pid, SIGINT); } } #else pid_t emu_event_pid = -1; static inline void genEmuEvent(lua_State *L, int fd, int type, int code, int value) { struct input_event input; input.type = type; input.code = code; input.value = value; gettimeofday(&input.time, NULL); if(write(fd, &input, sizeof(struct input_event)) == -1) { luaL_error(L, "Failed to generate emu event.\n"); } return; } #endif int findFreeFdSlot() { int i; for(i=0; i", inputdevice); } #ifndef EMULATE_READER if(!strcmp("fake_events", inputdevice)) { /* special case: the power slider */ int pipefd[2]; pipe(pipefd); if((childpid = fork()) == -1) { return luaL_error(L, "cannot fork() slider event listener"); } if(childpid == 0) { // We send a SIGTERM to this child on exit, trap it to kill lipc properly. signal(SIGTERM, slider_handler); FILE *fp; char std_out[256]; int status; struct input_event ev; __u16 key_code = 10000; close(pipefd[0]); ev.type = EV_KEY; ev.code = key_code; ev.value = 1; /* listen power slider events (listen for ever for multiple events) */ char *argv[] = {"lipc-wait-event", "-m", "-s", "0", "com.lab126.powerd", "goingToScreenSaver,outOfScreenSaver,charging,notCharging", (char *) NULL}; /* @TODO 07.06 2012 (houqp) * plugin and out event can only be watched by: lipc-wait-event com.lab126.hal usbPlugOut,usbPlugIn */ fp = popen_noshell("lipc-wait-event", (const char * const *)argv, "r", &pclose_arg, 0); if (!fp) { err(EXIT_FAILURE, "popen_noshell()"); } /* Flush to get rid of buffering issues? */ fflush(fp); while(fgets(std_out, sizeof(std_out)-1, fp)) { if(std_out[0] == 'g') { ev.code = CODE_IN_SAVER; } else if(std_out[0] == 'o') { ev.code = CODE_OUT_SAVER; } else if((std_out[0] == 'u') && (std_out[7] == 'I')) { ev.code = CODE_USB_PLUG_IN; } else if((std_out[0] == 'u') && (std_out[7] == 'O')) { ev.code = CODE_USB_PLUG_OUT; } else if(std_out[0] == 'c') { ev.code = CODE_CHARGING; } else if(std_out[0] == 'n') { ev.code = CODE_NOT_CHARGING; } else { printf("Unrecognized event.\n"); } /* fill event struct */ gettimeofday(&ev.time, NULL); /* generate event */ if(write(pipefd[1], &ev, sizeof(struct input_event)) == -1) { printf("Failed to generate event.\n"); } } status = pclose_noshell(&pclose_arg); if (status == -1) { err(EXIT_FAILURE, "pclose_noshell()"); } else { printf("lipc-wait-event exited with status %d.\n", status); if WIFEXITED(status) { printf("lipc-wait-event exited normally with status: %d.\n", WEXITSTATUS(status)); } if WIFSIGNALED(status) { printf("lipc-wait-event terminated by signal: %d.\n", WTERMSIG(status)); } } // We're done, go away :). _exit(EXIT_SUCCESS); } else { close(pipefd[1]); inputfds[fd] = pipefd[0]; slider_pid = childpid; } #else int keep_waiting = 1; if(SDL_Init(SDL_INIT_VIDEO) < 0) { return luaL_error(L, "cannot initialize SDL."); } SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL); if((childpid = fork()) == -1) { return luaL_error(L, "cannot fork() emu event generator"); } if(childpid == 0) { struct input_event ev; SDL_Event event; /*close(pipefd[0]);*/ inputfds[fd] = open(inputdevice, O_RDWR | O_NONBLOCK); while(keep_waiting) { SDL_WaitEvent(&event); switch(event.type) { case SDL_KEYDOWN: genEmuEvent(L, inputfds[fd], EV_KEY, event.key.keysym.scancode, 1); break; case SDL_KEYUP: genEmuEvent(L, inputfds[fd], EV_KEY, event.key.keysym.scancode, 0); break; case SDL_MOUSEMOTION: /* ignore move motion here, we might use it for other * gesture in future. */ /*printf("Mouse moved by %d,%d to (%d,%d)\n", */ /*event.motion.xrel, event.motion.yrel,*/ /*event.motion.x, event.motion.y);*/ break; case SDL_MOUSEBUTTONDOWN: /* use mouse click to simulate single tap */ genEmuEvent(L, inputfds[fd], EV_ABS, ABS_MT_TRACKING_ID, 0); genEmuEvent(L, inputfds[fd], EV_ABS, ABS_MT_POSITION_X, event.button.x); genEmuEvent(L, inputfds[fd], EV_ABS, ABS_MT_POSITION_Y, event.button.y); genEmuEvent(L, inputfds[fd], EV_SYN, SYN_REPORT, 0); genEmuEvent(L, inputfds[fd], EV_ABS, ABS_MT_TRACKING_ID, -1); genEmuEvent(L, inputfds[fd], EV_SYN, SYN_REPORT, 0); /*printf("Mouse button %d pressed at (%d,%d)\n",*/ /*event.button.button, event.button.x, event.button.y);*/ break; case SDL_QUIT: /* 3 byte is enough to signal waitForInput */ write(inputfds[fd], "application forced to quit", 3); keep_waiting = 0; } } close(inputfds[fd]); // We're done, go away :). _exit(EXIT_SUCCESS); #endif } else { inputfds[fd] = open(inputdevice, O_RDONLY | O_NONBLOCK, 0); if(inputfds[fd] != -1) { ioctl(inputfds[fd], EVIOCGRAB, 1); return 0; } else { return luaL_error(L, "error opening input device <%s>: %d", inputdevice, errno); } } return 0; } static int closeInputDevices(lua_State *L) { int i; for(i=0; i nfds) nfds = inputfds[i] + 1; } /* when no value is given as argument, we pass * NULL to select() for the timeout value, setting no * timeout at all. */ num = select(nfds, &fds, NULL, NULL, (usecs < 0) ? NULL : &timeout); if(num < 0) { return luaL_error(L, "Waiting for input failed: %d\n", errno); } for(i=0; i