/* Daemon to monitor the CTS line of the selected serial device and send a predefined phrase to the currently focused window when the line goes high Build using: gcc -I/usr/X11R6/include -L/usr/X11R6/lib -lX11 -lXtst -o hotkey ./hotkey.c Currently port and phrase are hardcoded */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define DEVICE "/dev/ttyUSB0" #define PHRASE "Longstaff-Tyrrell" //#define PHRASE "We apologise for any inconvenience caused to your journey." #define SHIFTED_CHARS "!\"£$%^&*()_+<>:@?" void send_string(char *string, Display *pDisplay) { while(*string!=0) { char symbol = *string; string++; // limit to range of chars if(symbol>'z'||symbol<' ') continue; KeyCode keycode; keycode = XKeysymToKeycode(pDisplay, symbol); //printf("sending %c: keycode 0x%02X\n",symbol,keycode); // catch shift-modified characters if(strchr(SHIFTED_CHARS, symbol)!=NULL||isupper(symbol)) { // press left shift XTestFakeKeyEvent( pDisplay, XKeysymToKeycode(pDisplay, XK_Shift_L),True, CurrentTime ); } XTestFakeKeyEvent( pDisplay, keycode,True, CurrentTime ); XTestFakeKeyEvent( pDisplay, keycode,False, CurrentTime ); // release left shift XTestFakeKeyEvent( pDisplay, XKeysymToKeycode(pDisplay, XK_Shift_L),False, CurrentTime ); XFlush(pDisplay); } } void send_phrase() { // open display and send string Display* pDisplay = XOpenDisplay( NULL ); if( pDisplay == NULL ) return; send_string(PHRASE, pDisplay); XCloseDisplay(pDisplay); } void start_daemon() { // start the daemon (from http://www.netzmafia.de/skripten/unix/linux-daemon-howto.html) // Our process ID and Session ID pid_t pid, sid; // Fork off the parent process pid = fork(); if(pid < 0) exit(EXIT_FAILURE); // If we got a good PID, then we can exit the parent process. if(pid > 0) exit(EXIT_SUCCESS); // Change the file mode mask umask(0); // Open any logs here // Create a new SID for the child process sid = setsid(); if(sid < 0) { // Log the failure exit(EXIT_FAILURE); } // Change the current working directory if ((chdir("/")) < 0) { // Log the failure exit(EXIT_FAILURE); } // Close out the standard file descriptors close(STDIN_FILENO); close(STDOUT_FILENO); close(STDERR_FILENO); } int main(int argc, char **argv) { char *device = DEVICE; start_daemon(); int fd = open(device, O_RDWR | O_NDELAY); if(fd < 0) { perror(device); return -1; } struct termios newtio; newtio.c_cflag = B9600 | CS8 | CLOCAL | CREAD; newtio.c_iflag = IGNPAR; newtio.c_oflag = 0; newtio.c_lflag = 0; newtio.c_cc[VMIN]=1; newtio.c_cc[VTIME]=0; tcflush(fd, TCIFLUSH); tcsetattr(fd,TCSANOW,&newtio); int status; // ioctl(fd, TIOCMGET, &status); status &= ~TIOCM_DTR; status &= ~TIOCM_RTS; ioctl(fd, TIOCMSET, &status); // catch changes to CTS while(1) { // block until line changes state if(ioctl(fd, TIOCMIWAIT, TIOCM_CTS) < 0) { perror(device); return -1; } usleep(75000); // debounce switch ioctl(fd, TIOCMGET, &status); if(status & TIOCM_CTS) send_phrase(); } close(fd); exit(EXIT_SUCCESS); }