"Fossies" - the Fresh Open Source Software Archive

Member "key-scripter-2.1/reader.c" (11 May 2020, 20140 Bytes) of package /linux/privat/key-scripter-2.1.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "reader.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.0_vs_2.1.

    1 /*
    2  * Copyright (c) 2020 Crolix Software
    3  *
    4  * This file is licensed under the GNU General Public License.
    5  * See the file COPYING for more details.
    6  */
    7 
    8 #include <stdio.h>
    9 #include "scripter.h"
   10 #include "reader.h"
   11 
   12 bool processKeyEvent(unsigned keyCode, bool pressed);
   13 bool processMouseButtonEvent(unsigned buttonNumber, bool pressed);
   14 bool processMouseWheelEvent(unsigned clicks, bool forwardRotation);
   15 bool receiveEventsFromStardardInput();
   16 char readStandardInputCharacter();
   17 
   18 char inputCharacter;
   19 bool terminated;
   20 
   21 #ifndef _WINDOWS
   22 
   23 #include <signal.h>
   24 #include <string.h>
   25 #include <fcntl.h>
   26 #include <errno.h>
   27 #include <termios.h>
   28 #include <linux/input.h>
   29 
   30 #define MAXIMUM_DEVICES 256
   31 
   32 struct DeviceStruct {
   33     const char* fileName;
   34     const char* address;
   35     const char* name;
   36 
   37     int file;
   38     bool failed;
   39 };
   40 
   41 typedef void (*SignalHandler)(int signal);
   42 
   43 inline const char* deviceDescription(const struct DeviceStruct* device);
   44 bool blockIOSignal();
   45 void unblockIOSignal();
   46 bool registerSignalHandler(int signal, SignalHandler handler);
   47 bool openDevice(struct DeviceStruct* device);
   48 bool deviceIsAlive(const struct DeviceStruct* device);
   49 void closeDevice(const struct DeviceStruct* device);
   50 void processTerminateSignal(int signal);
   51 void processIOSignal(int signal);
   52 bool inputAvailable(int file);
   53 
   54 struct DeviceStruct devices[MAXIMUM_DEVICES];
   55 unsigned deviceCount = 0;
   56 fd_set deviceFilesMask;
   57 int deviceFilesMaskSize;
   58 
   59 bool addDevice(const char* const deviceFile, const char* const deviceAddress, const char* const deviceName) {
   60     if (deviceCount < MAXIMUM_DEVICES) {
   61         devices[deviceCount].fileName = deviceFile;
   62         devices[deviceCount].address = deviceAddress;
   63         devices[deviceCount].name = deviceName;
   64 
   65         ++deviceCount;
   66         return true;
   67     }
   68 
   69     fprintf(stderr, "Error: too many input devices specified\n");
   70     return false;
   71 }
   72 
   73 bool readEvents() {
   74     if (deviceCount > 0) {
   75         int openedDevices = 0;
   76         FD_ZERO(&deviceFilesMask);
   77         deviceFilesMaskSize = 0;
   78 
   79         bool unblockIOWhenDone = blockIOSignal();
   80 
   81         for (; openedDevices < deviceCount; ++openedDevices)
   82             if (!openDevice(&devices[openedDevices])) {
   83                 if (unblockIOWhenDone)
   84                     unblockIOSignal();
   85                 break;
   86             }
   87 
   88         if (openedDevices == deviceCount) {
   89             registerSignalHandler(SIGINT, (SignalHandler) & processTerminateSignal);
   90             registerSignalHandler(SIGTERM, (SignalHandler) & processTerminateSignal);
   91             registerSignalHandler(SIGIO, (SignalHandler) & processIOSignal);
   92 
   93             if (unblockIOWhenDone)
   94                 unblockIOSignal();
   95 
   96             terminated = false;
   97             while (!terminated) {
   98                 int aliveDevices = 0;
   99 
  100                 int deviceIndex;
  101                 for (deviceIndex = 0; deviceIndex < deviceCount; ++deviceIndex) {
  102                     struct DeviceStruct* const device = &devices[deviceIndex];
  103                     if (!device->failed) {
  104                         if (deviceIsAlive(device))
  105                             ++aliveDevices;
  106                         else {
  107                             unblockIOWhenDone = blockIOSignal();
  108 
  109                             device->failed = true;
  110                             closeDevice(device);
  111 
  112                             if (unblockIOWhenDone)
  113                                 unblockIOSignal();
  114 
  115                             fprintf(stderr, "Warning: no longer able to read input device '%s'\n", deviceDescription(device));
  116                         }
  117                     }
  118                 }
  119 
  120                 if (aliveDevices == 0)
  121                     break;
  122 
  123                 sleep(1);
  124             }
  125 
  126             signal(SIGIO, SIG_DFL);
  127         }
  128 
  129         int deviceIndex;
  130         for (deviceIndex = 0; deviceIndex < openedDevices; ++deviceIndex) {
  131             struct DeviceStruct* const device = &devices[deviceIndex];
  132             if (!device->failed)
  133                 closeDevice(device);
  134         }
  135 
  136         return openedDevices == deviceCount;
  137     }
  138 
  139     return receiveEventsFromStardardInput();
  140 }
  141 
  142 void quit() {
  143     terminated = true;
  144 }
  145 
  146 inline const char* deviceDescription(const struct DeviceStruct* const device) {
  147     return device->fileName != NULL ? device->fileName : device->address != NULL ? device->address : device->name;
  148 }
  149 
  150 bool blockIOSignal() {
  151     sigset_t signalsToBlock, previouslyBlockedSignals;
  152     sigemptyset(&signalsToBlock);
  153     sigaddset(&signalsToBlock, SIGIO);
  154 
  155     sigprocmask(SIG_BLOCK, &signalsToBlock, &previouslyBlockedSignals);
  156     return !sigismember(&previouslyBlockedSignals, SIGIO);
  157 }
  158 
  159 void unblockIOSignal() {
  160     sigset_t signalsToUnblock;
  161     sigemptyset(&signalsToUnblock);
  162     sigaddset(&signalsToUnblock, SIGIO);
  163 
  164     sigprocmask(SIG_UNBLOCK, &signalsToUnblock, NULL);
  165 }
  166 
  167 bool registerSignalHandler(const int signal, SignalHandler handler) {
  168     struct sigaction signalAction;
  169     signalAction.sa_handler = handler;
  170     signalAction.sa_flags = 0;
  171 
  172     sigemptyset(&signalAction.sa_mask);
  173     sigaddset(&signalAction.sa_mask, signal);
  174 
  175     return sigaction(signal, &signalAction, NULL) == 0;
  176 }
  177 
  178 bool openDevice(struct DeviceStruct* const device) {
  179     int file;
  180 
  181     if (device->fileName != NULL) {
  182         if ((file = open(device->fileName, O_RDONLY | O_NONBLOCK)) == -1) {
  183             fprintf(stderr, "Unable to open input device '%s' for reading: %s\n", deviceDescription(device), strerror(errno));
  184             return false;
  185         }
  186     } else {
  187         unsigned eventNumber = 0;
  188         char fileName[24];
  189         char buffer[256];
  190 
  191         while (true) {
  192             snprintf(fileName, sizeof(fileName), "/dev/input/event%u", eventNumber);
  193 
  194             file = open(fileName, O_RDONLY | O_NONBLOCK);
  195             if (file != -1) {
  196                 if (device->address != NULL ?
  197                         ioctl(file, EVIOCGPHYS(sizeof (buffer)), buffer) != -1 && strcmp(buffer, device->address) == 0 :
  198                         ioctl(file, EVIOCGNAME(sizeof (buffer)), buffer) != -1 && strcmp(buffer, device->name) == 0)
  199                     break;
  200 
  201                 close(file);
  202             } else
  203                 if (errno == ENOENT && eventNumber > 2) {
  204                 fprintf(stderr, "Unable to open input device '%s' for reading\n", deviceDescription(device));
  205                 return false;
  206             }
  207 
  208             ++eventNumber;
  209         }
  210     }
  211 
  212     if (tcflush(file, TCIFLUSH) != 0) {
  213         fd_set files;
  214         FD_ZERO(&files);
  215         FD_SET(file, &files);
  216 
  217         struct timeval timeout;
  218         timeout.tv_sec = 0;
  219         timeout.tv_usec = 0;
  220 
  221         char buffer[4];
  222 
  223         while (select(file + 1, &files, NULL, NULL, &timeout) > 0 && read(file, buffer, sizeof (buffer)) > 0);
  224     }
  225 
  226     int fileFlags;
  227     if ((fileFlags = fcntl(file, F_GETFL)) == -1 || fcntl(file, F_SETFL, fileFlags | O_ASYNC) == -1 ||
  228             fcntl(file, F_SETOWN, getpid()) == -1) {
  229         fprintf(stderr, "Error setting the file descriptor flags for input device '%s': %s\n", deviceDescription(device), strerror(errno));
  230         close(file);
  231         return false;
  232     }
  233 
  234     device->file = file;
  235     device->failed = false;
  236 
  237     FD_SET(file, &deviceFilesMask);
  238     if (deviceFilesMaskSize < file + 1)
  239         deviceFilesMaskSize = file + 1;
  240 
  241     return true;
  242 }
  243 
  244 bool deviceIsAlive(const struct DeviceStruct* const device) {
  245     int driverVersion;
  246     return !device->failed && ioctl(device->file, EVIOCGVERSION, &driverVersion) != -1;
  247 }
  248 
  249 void closeDevice(const struct DeviceStruct* const device) {
  250     deviceFilesMaskSize = 0;
  251 
  252     int deviceIndex;
  253     for (deviceIndex = 0; deviceIndex < deviceCount; ++deviceIndex) {
  254         int file = devices[deviceIndex].file;
  255         if (file != device->file && deviceFilesMaskSize < file + 1)
  256             deviceFilesMaskSize = file + 1;
  257     }
  258 
  259     FD_CLR(device->file, &deviceFilesMask);
  260 
  261     int fileFlags;
  262     if ((fileFlags = fcntl(device->file, F_GETFL)) != -1)
  263         fcntl(device->file, F_SETFL, fileFlags & ~O_ASYNC);
  264 
  265     close(device->file);
  266 }
  267 
  268 void processTerminateSignal(const int signal) {
  269     quit();
  270 }
  271 
  272 void processIOSignal(const int signal) {
  273     fd_set readyDeviceFiles = deviceFilesMask;
  274 
  275     struct timeval timeout;
  276     timeout.tv_sec = 0;
  277     timeout.tv_usec = 0;
  278 
  279     int result;
  280     while ((result = select(deviceFilesMaskSize, &readyDeviceFiles, NULL, NULL, &timeout)) == -1 && errno == EINTR);
  281 
  282     if (result > 0) {
  283         int deviceIndex;
  284         for (deviceIndex = 0; deviceIndex < deviceCount; ++deviceIndex) {
  285             struct DeviceStruct* const device = &devices[deviceIndex];
  286             if (FD_ISSET(device->file, &readyDeviceFiles) && !device->failed) {
  287                 struct input_event event;
  288 
  289                 do {
  290                     int result = read(device->file, &event, sizeof(struct input_event));
  291                     if (result == -1) {
  292                         device->failed = true;
  293                         closeDevice(device);
  294 
  295                         fprintf(stderr, "Warning: no longer able to read input device '%s'\n", deviceDescription(device));
  296                         return;
  297                     }
  298 
  299                     if (result != sizeof (struct input_event)) {
  300                         device->failed = true;
  301                         closeDevice(device);
  302 
  303                         fprintf(stderr, "Error reading input device '%s': %i bytes available instead of %lu\n",
  304                                 deviceDescription(device), result, sizeof(struct input_event));
  305                         return;
  306                     }
  307 
  308                     if (event.type == EV_KEY) {
  309                         bool pressed = event.value != 0;
  310 
  311                         if (event.code >= BTN_MOUSE && event.code < BTN_JOYSTICK)
  312                             processMouseButtonEvent(event.code - BTN_MOUSE + 1, pressed);
  313                         else {
  314                             unsigned keyCode;
  315 
  316                             switch (event.code) {
  317                                 case KEY_KPENTER:
  318                                     keyCode = 108;
  319                                     break;
  320 
  321                                 case KEY_RIGHTCTRL:
  322                                     keyCode = 109;
  323                                     break;
  324 
  325                                 case KEY_KPSLASH:
  326                                     keyCode = 112;
  327                                     break;
  328 
  329                                 case KEY_SYSRQ:
  330                                     keyCode = 111;
  331                                     break;
  332 
  333                                 case KEY_RIGHTALT:
  334                                     keyCode = 113;
  335                                     break;
  336 
  337                                 case KEY_HOME:
  338                                     keyCode = 97;
  339                                     break;
  340 
  341                                 case KEY_UP:
  342                                     keyCode = 98;
  343                                     break;
  344 
  345                                 case KEY_PAGEUP:
  346                                     keyCode = 99;
  347                                     break;
  348 
  349                                 case KEY_LEFT:
  350                                     keyCode = 100;
  351                                     break;
  352 
  353                                 case KEY_RIGHT:
  354                                     keyCode = 102;
  355                                     break;
  356 
  357                                 case KEY_END:
  358                                     keyCode = 103;
  359                                     break;
  360 
  361                                 case KEY_DOWN:
  362                                     keyCode = 104;
  363                                     break;
  364 
  365                                 case KEY_PAGEDOWN:
  366                                     keyCode = 105;
  367                                     break;
  368 
  369                                 case KEY_INSERT:
  370                                     keyCode = 106;
  371                                     break;
  372 
  373                                 case KEY_DELETE:
  374                                     keyCode = 107;
  375                                     break;
  376 
  377                                 case KEY_PAUSE:
  378                                     keyCode = 110;
  379                                     break;
  380 
  381                                 case KEY_LEFTMETA:
  382                                     keyCode = 115;
  383                                     break;
  384 
  385                                 case KEY_RIGHTMETA:
  386                                     keyCode = 116;
  387                                     break;
  388 
  389                                 case KEY_COMPOSE:
  390                                     keyCode = 117;
  391                                     break;
  392 
  393                                 default:
  394                                     keyCode = event.code + 8;
  395                             }
  396 
  397                             processKeyEvent(keyCode, pressed);
  398                         }
  399                     } else
  400                     if (event.type == EV_REL && event.code == REL_WHEEL) {
  401                         if (event.value > 0)
  402                             processMouseWheelEvent(event.value, true); else
  403                         if (event.value < 0)
  404                             processMouseWheelEvent(-event.value, false);
  405                     }
  406                 } while (inputAvailable(device->file));
  407             }
  408         }
  409     }
  410 }
  411 
  412 bool inputAvailable(const int file) {
  413     fd_set files;
  414     FD_ZERO(&files);
  415     FD_SET(file, &files);
  416 
  417     struct timeval timeout;
  418     timeout.tv_sec = 0;
  419     timeout.tv_usec = 0;
  420 
  421     int result;
  422     while ((result = select(file + 1, &files, NULL, NULL, &timeout)) == -1 && errno == EINTR);
  423 
  424     return result > 0;
  425 }
  426 
  427 #else // _WINDOWS
  428 
  429 #include "hook.h"
  430 
  431 bool readDevice;
  432 UnregisterEventListeners unregisterEventListeners;
  433 
  434 bool initializeReader(const bool inputFromDevice) {
  435     if (inputFromDevice) {
  436         HINSTANCE dllHandle = LoadLibrary(TEXT("key-scripter"));
  437         if (dllHandle == NULL) {
  438             fprintf(stderr, "Unable to load 'key-scripter.dll': received error code %li\n", GetLastError());
  439             return false;
  440         }
  441 
  442         RegisterEventListeners registerEventListeners = (RegisterEventListeners)GetProcAddress(dllHandle, "registerEventListeners");
  443         unregisterEventListeners = (UnregisterEventListeners) GetProcAddress(dllHandle, "unregisterEventListeners");
  444 
  445         if (registerEventListeners == NULL || unregisterEventListeners == NULL) {
  446             fprintf(stderr, "The key-scripter.dll is found, but is not usable\n");
  447             return false;
  448         }
  449 
  450         if (!registerEventListeners(dllHandle, (KeyEventListener)&processKeyEvent,
  451                 (MouseButtonEventListener)&processMouseButtonEvent, (MouseWheelEventListener)&processMouseWheelEvent)) {
  452             fprintf(stderr, "Unable to register all of the event hooks\n");
  453             return false;
  454         }
  455 
  456         return readDevice = true;
  457     }
  458 
  459     readDevice = false;
  460     return true;
  461 }
  462 
  463 bool readEvents() {
  464     if (!readDevice)
  465         return receiveEventsFromStardardInput();
  466 
  467     MSG message;
  468     int result;
  469 
  470     while ((result = GetMessage(&message, NULL, 0, 0)) > 0)
  471         if (result == -1) {
  472             fprintf(stderr, "Received message loop error %li\n", GetLastError());
  473             break;
  474         } else {
  475             TranslateMessage(&message);
  476             DispatchMessage(&message);
  477         }
  478 
  479     unregisterEventListeners();
  480     return result == 0;
  481 }
  482 
  483 void quit() {
  484     if (readDevice)
  485         PostQuitMessage(0);
  486     else
  487         terminated = true;
  488 }
  489 
  490 #endif // _WINDOWS
  491 
  492 bool processKeyEvent(const unsigned keyCode, const bool pressed) {
  493     return pressed ? processKeyPress(keyCode, 0) : processKeyRelease(keyCode, 0);
  494 }
  495 
  496 bool processMouseButtonEvent(const unsigned buttonNumber, const bool pressed) {
  497     return pressed ? processMouseButtonPress(buttonNumber, 0) : processMouseButtonRelease(buttonNumber, 0);
  498 }
  499 
  500 bool processMouseWheelEvent(const unsigned clicks, const bool forwardRotation) {
  501     return forwardRotation ? processForwardMouseWheelRotation(clicks, 0) : processBackwardMouseWheelRotation(clicks, 0);
  502 }
  503 
  504 bool receiveEventsFromStardardInput() {
  505     terminated = false;
  506     while (!terminated) {
  507         char command = readStandardInputCharacter();
  508         if (command == 'q')
  509             break; else
  510         if (command == 'p' || command == 'r' || command == 't' || command == 's') {
  511             unsigned value = 0;
  512             char codePoint[6];
  513             codePoint[0] = 0;
  514             unsigned long delay = 0;
  515 
  516             if (readStandardInputCharacter() == 'U') {
  517                 codePoint[0] = 'U';
  518                 value = 1;
  519 
  520                 while (!characterIsWordSeparator(readStandardInputCharacter()))
  521                     if (value < sizeof(codePoint) - 1)
  522                         codePoint[value++] = inputCharacter;
  523 
  524                 codePoint[value] = 0;
  525             } else
  526             while (inputCharacter >= '0' && inputCharacter <= '9') {
  527                 value = value * 10 + (inputCharacter - '0');
  528 
  529                 readStandardInputCharacter();
  530             }
  531 
  532             if (inputCharacter == '/')
  533                 while (readStandardInputCharacter() >= '0' && inputCharacter <= '9')
  534                     delay = delay * 10 + (inputCharacter - '0');
  535 
  536             if (value > 0)
  537                 switch (command) {
  538                     case 'p':
  539                         if (value <= MAXIMUM_KEY_CODE)
  540                             processKeyPress(value, delay);
  541                         break;
  542 
  543                     case 'r':
  544                         if (value <= MAXIMUM_KEY_CODE)
  545                             processKeyRelease(value, delay);
  546                         break;
  547 
  548                     case 't':
  549                         if (codePoint[0] != 0)
  550                             processUnicodeCharacterType(codePoint, delay); else
  551                         if (value <= MAXIMUM_KEY_CODE)
  552                             processKeyType(value, delay);
  553                         break;
  554 
  555                     case 's':
  556                         sleepMillis(value);
  557                 }
  558         } else
  559         if (command == 'm') {
  560             command = readStandardInputCharacter();
  561             if (command == 'p' || command == 'r' || command == 'c' || command == 'w' && ((command = readStandardInputCharacter()) == 'f' || command == 'b')) {
  562                 unsigned value = 0;
  563                 unsigned long delay = 0;
  564 
  565                 while (readStandardInputCharacter() >= '0' && inputCharacter <= '9')
  566                     value = value * 10 + (inputCharacter - '0');
  567 
  568                 if (inputCharacter == '/')
  569                     while (readStandardInputCharacter() >= '0' && inputCharacter <= '9')
  570                         delay = delay * 10 + (inputCharacter - '0');
  571 
  572                 if (value > 0)
  573                     switch (command) {
  574                         case 'p':
  575                             if (value <= MAXIMUM_MOUSE_BUTTON)
  576                                 processMouseButtonPress(value, delay);
  577                             break;
  578 
  579                         case 'r':
  580                             if (value <= MAXIMUM_MOUSE_BUTTON)
  581                                 processMouseButtonRelease(value, delay);
  582                             break;
  583 
  584                         case 'c':
  585                             if (value <= MAXIMUM_MOUSE_BUTTON)
  586                                 processMouseButtonClick(value, delay);
  587                             break;
  588 
  589                         case 'f':
  590                             processForwardMouseWheelRotation(value, delay);
  591                             break;
  592 
  593                         case 'b':
  594                             processBackwardMouseWheelRotation(value, delay);
  595                     }
  596             }
  597         }
  598 
  599         while (!characterIsSpace(inputCharacter))
  600             readStandardInputCharacter();
  601     }
  602 
  603     return true;
  604 }
  605 
  606 char readStandardInputCharacter() {
  607     while (true) {
  608         char buffer[1];
  609 
  610         int result = read(STDIN_FILENO, buffer, 1);
  611         if (result == 1)
  612             return inputCharacter = buffer[0];
  613 
  614         sleepMillis(1);
  615     }
  616 }