Advertisement
spore29

retrogame.c

Jul 22nd, 2016
225
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 25.80 KB | None | 0 0
  1. /*
  2. ADAFRUIT RETROGAME UTILITY: remaps buttons on Raspberry Pi GPIO header
  3. to virtual USB keyboard presses.  Great for classic game emulators!
  4. Retrogame is interrupt-driven and efficient (usually under 0.3% CPU use)
  5. and debounces inputs for glitch-free gaming.
  6.  
  7. Connect one side of button(s) to GND pin (there are several on the GPIO
  8. header, but see later notes) and the other side to GPIO pin of interest.
  9. Internal pullups are used; no resistors required.  Avoid pins 8 and 10;
  10. these are configured as a serial port by default on most systems (this
  11. can be disabled but takes some doing).  Pin configuration is currently
  12. set in global table; no config file yet.  See later comments.
  13.  
  14. Must be run as root, i.e. 'sudo ./retrogame &' or configure init scripts
  15. to launch automatically at system startup.
  16.  
  17. Requires uinput kernel module.  This is typically present on popular
  18. Raspberry Pi Linux distributions but not enabled on some older varieties.
  19. To enable, either type:
  20.  
  21.     sudo modprobe uinput
  22.  
  23. Or, to make this persistent between reboots, add a line to /etc/modules:
  24.  
  25.     uinput
  26.  
  27. Prior versions of this code, when being compiled for use with the Cupcade
  28. or PiGRRL projects, required CUPCADE to be #defined.  This is no longer
  29. the case; instead a test is performed to see if a PiTFT is connected, and
  30. one of two I/O tables is automatically selected.
  31.  
  32. Written by Phil Burgess for Adafruit Industries, distributed under BSD
  33. License.  Adafruit invests time and resources providing this open source
  34. code, please support Adafruit and open-source hardware by purchasing
  35. products from Adafruit!
  36.  
  37.  
  38. Copyright (c) 2013 Adafruit Industries.
  39. All rights reserved.
  40.  
  41. Redistribution and use in source and binary forms, with or without
  42. modification, are permitted provided that the following conditions are met:
  43.  
  44. - Redistributions of source code must retain the above copyright notice,
  45.   this list of conditions and the following disclaimer.
  46. - Redistributions in binary form must reproduce the above copyright notice,
  47.   this list of conditions and the following disclaimer in the documentation
  48.   and/or other materials provided with the distribution.
  49.  
  50. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  51. AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  52. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  53. ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
  54. LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  55. CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  56. SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  57. INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  58. CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  59. ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  60. POSSIBILITY OF SUCH DAMAGE.
  61. */
  62.  
  63. #include <stdio.h>
  64. #include <stdlib.h>
  65. #include <string.h>
  66. #include <unistd.h>
  67. #include <fcntl.h>
  68. #include <poll.h>
  69. #include <signal.h>
  70. #include <sys/mman.h>
  71. #include <linux/input.h>
  72. #include <linux/uinput.h>
  73.  
  74.  
  75. // START HERE ------------------------------------------------------------
  76. // This table remaps GPIO inputs to keyboard values.  In this initial
  77. // implementation there's a 1:1 relationship (can't attach multiple keys
  78. // to a button) and the list is fixed in code; there is no configuration
  79. // file.  Buttons physically connect between GPIO pins and ground.  There
  80. // are only a few GND pins on the GPIO header, so a breakout board is
  81. // often needed.  If you require just a couple extra ground connections
  82. // and have unused GPIO pins, set the corresponding key value to GND to
  83. // create a spare ground point.
  84.  
  85. #define GND -1
  86. struct {
  87.         int pin;
  88.         int key;
  89. } *io, // In main() this pointer is set to one of the two tables below.
  90.    ioTFT[] = {
  91.         // This pin/key table is used if an Adafruit PiTFT display
  92.         // is detected (e.g. Cupcade or PiGRRL).
  93.         // Input   Output (from /usr/include/linux/input.h)
  94.         {   2,     KEY_LEFT     },   // Joystick (4 pins)
  95.         {   3,     KEY_RIGHT    },
  96.         {   4,     KEY_DOWN     },
  97.         {  17,     KEY_UP       },
  98.         {  27,     KEY_Z        },   // A/Fire/jump/primary
  99.         {  22,     KEY_X        },   // B/Bomb/secondary
  100.         {  23,     KEY_R        },   // Credit
  101.         {  18,     KEY_Q        },   // Start 1P
  102.         {  -1,     -1           } }, // END OF LIST, DO NOT CHANGE
  103.         // MAME must be configured with 'z' & 'x' as buttons 1 & 2 -
  104.         // this was required for the accompanying 'menu' utility to
  105.         // work (catching crtl/alt w/ncurses gets totally NASTY).
  106.         // Credit/start are likewise moved to 'r' & 'q,' reason being
  107.         // to play nicer with certain emulators not liking numbers.
  108.         // GPIO options are 'maxed out' with PiTFT + above table.
  109.         // If additional buttons are desired, will need to disable
  110.         // serial console and/or use P5 header.  Or use keyboard.
  111.    ioStandard[] = {
  112.         // This pin/key table is used when the PiTFT isn't found
  113.         // (using HDMI or composite instead), as with our original
  114.         // retro gaming guide.
  115.         // Input   Output (from /usr/include/linux/input.h)
  116.         { 4,  KEY_LEFT     }, // Joystick (4 pins)
  117.         { 19, KEY_RIGHT    },
  118.         { 16, KEY_UP       },
  119.         { 26, KEY_DOWN     },
  120.         { 15, KEY_LEFTCTRL }, // A/Fire/jump/primary/RED
  121.         { 14, KEY_LEFTALT  }, // B/Bomb/secondary/YELLOW
  122.         { 20, KEY_LEFTSHIFT}, // X/BLUE
  123.         { 18, KEY_W        }, // Y/GREEN
  124.         {  5, KEY_RIGHTCTRL}, // Select
  125.         {  6, KEY_ENTER    }, // Start
  126.         { 12, KEY_A        }, // L Shoulder
  127.         { 13, KEY_S        }, // R Shoulder
  128.         { 17, KEY_ESC      }, // Exit ROM PiTFT Button 1
  129.         { 22, KEY_KP5      }, // PiTFT Button 2
  130.         { 23, KEY_KPMINUS  }, // PiTFT Button 3
  131.         { 27, KEY_F12      }, // PiTFT Button 4
  132.         // For credit/start/etc., use USB keyboard or add more buttons.
  133.         {  -1,     -1           } }; // END OF LIST, DO NOT CHANGE
  134.  
  135. // A "Vulcan nerve pinch" (holding down a specific button combination
  136. // for a few seconds) issues an 'esc' keypress to MAME (which brings up
  137. // an exit menu or quits the current game).  The button combo is
  138. // configured with a bitmask corresponding to elements in the above io[]
  139. // array.  The default value here uses elements 6 and 7 (credit and start
  140. // in the Cupcade pinout).  If you change this, make certain it's a combo
  141. // that's not likely to occur during actual gameplay (i.e. avoid using
  142. // joystick directions or hold-for-rapid-fire buttons).
  143. // Also key auto-repeat times are set here.  This is for navigating the
  144. // game menu using the 'gamera' utility; MAME disregards key repeat
  145. // events (as it should).
  146. const unsigned long vulcanMask = (1L << 6) | (1L << 7);
  147. const int           vulcanKey  = KEY_ESC, // Keycode to send
  148.                     vulcanTime = 1500,    // Pinch time in milliseconds
  149.                     repTime1   = 500,     // Key hold time to begin repeat
  150.                     repTime2   = 100;     // Time between key repetitions
  151.  
  152.  
  153. // A few globals ---------------------------------------------------------
  154.  
  155. char
  156.   *progName,                         // Program name (for error reporting)
  157.    sysfs_root[] = "/sys/class/gpio", // Location of Sysfs GPIO files
  158.    running      = 1;                 // Signal handler will set to 0 (exit)
  159. volatile unsigned int
  160.   *gpio;                             // GPIO register table
  161. const int
  162.    debounceTime = 20;                // 20 ms for button debouncing
  163.  
  164.  
  165. // Some utility functions ------------------------------------------------
  166.  
  167. // Set one GPIO pin attribute through the Sysfs interface.
  168. int pinConfig(int pin, char *attr, char *value) {
  169.         char filename[50];
  170.         int  fd, w, len = strlen(value);
  171.         sprintf(filename, "%s/gpio%d/%s", sysfs_root, pin, attr);
  172.         if((fd = open(filename, O_WRONLY)) < 0) return -1;
  173.         w = write(fd, value, len);
  174.         close(fd);
  175.         return (w != len); // 0 = success
  176. }
  177.  
  178. // Un-export any Sysfs pins used; don't leave filesystem cruft.  Also
  179. // restores any GND pins to inputs.  Write errors are ignored as pins
  180. // may be in a partially-initialized state.
  181. void cleanup() {
  182.         char buf[50];
  183.         int  fd, i;
  184.         sprintf(buf, "%s/unexport", sysfs_root);
  185.         if((fd = open(buf, O_WRONLY)) >= 0) {
  186.                 for(i=0; io[i].pin >= 0; i++) {
  187.                         // Restore GND items to inputs
  188.                         if(io[i].key == GND)
  189.                                 pinConfig(io[i].pin, "direction", "in");
  190.                         // And un-export all items regardless
  191.                         sprintf(buf, "%d", io[i].pin);
  192.                         write(fd, buf, strlen(buf));
  193.                 }
  194.                 close(fd);
  195.         }
  196. }
  197.  
  198. // Quick-n-dirty error reporter; print message, clean up and exit.
  199. void err(char *msg) {
  200.         printf("%s: %s.  Try 'sudo %s'.\n", progName, msg, progName);
  201.         cleanup();
  202.         exit(1);
  203. }
  204.  
  205. // Interrupt handler -- set global flag to abort main loop.
  206. void signalHandler(int n) {
  207.         running = 0;
  208. }
  209.  
  210. // Detect Pi board type.  Doesn't return super-granular details,
  211. // just the most basic distinction needed for GPIO compatibility:
  212. // 0: Pi 1 Model B revision 1
  213. // 1: Pi 1 Model B revision 2, Model A, Model B+, Model A+
  214. // 2: Pi 2 Model B
  215.  
  216. static int boardType(void) {
  217.         FILE *fp;
  218.         char  buf[1024], *ptr;
  219.         int   n, board = 1; // Assume Pi1 Rev2 by default
  220.  
  221.         // Relies on info in /proc/cmdline.  If this becomes unreliable
  222.         // in the future, alt code below uses /proc/cpuinfo if any better.
  223. #if 1
  224.         if((fp = fopen("/proc/cmdline", "r"))) {
  225.                 while(fgets(buf, sizeof(buf), fp)) {
  226.                         if((ptr = strstr(buf, "mem_size=")) &&
  227.                            (sscanf(&ptr[9], "%x", &n) == 1) &&
  228.                            (n == 0x3F000000)) {
  229.                                 board = 2; // Appears to be a Pi 2
  230.                                 break;
  231.                         } else if((ptr = strstr(buf, "boardrev=")) &&
  232.                                   (sscanf(&ptr[9], "%x", &n) == 1) &&
  233.                                   ((n == 0x02) || (n == 0x03))) {
  234.                                 board = 0; // Appears to be an early Pi
  235.                                 break;
  236.                         }
  237.                 }
  238.                 fclose(fp);
  239.         }
  240. #else
  241.         char s[8];
  242.         if((fp = fopen("/proc/cpuinfo", "r"))) {
  243.                 while(fgets(buf, sizeof(buf), fp)) {
  244.                         if((ptr = strstr(buf, "Hardware")) &&
  245.                            (sscanf(&ptr[8], " : %7s", s) == 1) &&
  246.                            (!strcmp(s, "BCM2709"))) {
  247.                                 board = 2; // Appears to be a Pi 2
  248.                                 break;
  249.                         } else if((ptr = strstr(buf, "Revision")) &&
  250.                                   (sscanf(&ptr[8], " : %x", &n) == 1) &&
  251.                                   ((n == 0x02) || (n == 0x03))) {
  252.                                 board = 0; // Appears to be an early Pi
  253.                                 break;
  254.                         }
  255.                 }
  256.                 fclose(fp);
  257.         }
  258. #endif
  259.  
  260.         return board;
  261. }
  262.  
  263. // Main stuff ------------------------------------------------------------
  264.  
  265. #define PI1_BCM2708_PERI_BASE 0x20000000
  266. #define PI1_GPIO_BASE         (PI1_BCM2708_PERI_BASE + 0x200000)
  267. #define PI2_BCM2708_PERI_BASE 0x3F000000
  268. #define PI2_GPIO_BASE         (PI2_BCM2708_PERI_BASE + 0x200000)
  269. #define BLOCK_SIZE            (4*1024)
  270. #define GPPUD                 (0x94 / 4)
  271. #define GPPUDCLK0             (0x98 / 4)
  272.  
  273. int main(int argc, char *argv[]) {
  274.  
  275.         // A few arrays here are declared with 32 elements, even though
  276.         // values aren't needed for io[] members where the 'key' value is
  277.         // GND.  This simplifies the code a bit -- no need for mallocs and
  278.         // tests to create these arrays -- but may waste a handful of
  279.         // bytes for any declared GNDs.
  280.         char                   buf[50],      // For sundry filenames
  281.                                c,            // Pin input value ('0'/'1')
  282.                                board;        // 0=Pi1Rev1, 1=Pi1Rev2, 2=Pi2
  283.         int                    fd,           // For mmap, sysfs, uinput
  284.                                i, j,         // Asst. counter
  285.                                bitmask,      // Pullup enable bitmask
  286.                                timeout = -1, // poll() timeout
  287.                                intstate[32], // Last-read state
  288.                                extstate[32], // Debounced state
  289.                                lastKey = -1; // Last key down (for repeat)
  290.         unsigned long          bitMask, bit; // For Vulcan pinch detect
  291.         volatile unsigned char shortWait;    // Delay counter
  292.         struct input_event     keyEv, synEv; // uinput events
  293.         struct pollfd          p[32];        // GPIO file descriptors
  294.  
  295.         progName = argv[0];             // For error reporting
  296.         signal(SIGINT , signalHandler); // Trap basic signals (exit cleanly)
  297.         signal(SIGKILL, signalHandler);
  298.  
  299.         // Select io[] table for Cupcade (TFT) or 'normal' project.
  300.         io = (access("/etc/modprobe.d/adafruit.conf", F_OK) ||
  301.               access("/dev/fb1", F_OK)) ? ioStandard : ioTFT;
  302.  
  303.         // If this is a "Revision 1" Pi board (no mounting holes),
  304.         // remap certain pin numbers in the io[] array for compatibility.
  305.         // This way the code doesn't need modification for old boards.
  306.         board = boardType();
  307.         if(board == 0) {
  308.                 for(i=0; io[i].pin >= 0; i++) {
  309.                         if(     io[i].pin ==  2) io[i].pin = 0;
  310.                         else if(io[i].pin ==  3) io[i].pin = 1;
  311.                         else if(io[i].pin == 27) io[i].pin = 21;
  312.                 }
  313.         }
  314.  
  315.         // ----------------------------------------------------------------
  316.         // Although Sysfs provides solid GPIO interrupt handling, there's
  317.         // no interface to the internal pull-up resistors (this is by
  318.         // design, being a hardware-dependent feature).  It's necessary to
  319.         // grapple with the GPIO configuration registers directly to enable
  320.         // the pull-ups.  Based on GPIO example code by Dom and Gert van
  321.         // Loo on elinux.org
  322.  
  323.         if((fd = open("/dev/mem", O_RDWR | O_SYNC)) < 0)
  324.                 err("Can't open /dev/mem");
  325.         gpio = mmap(            // Memory-mapped I/O
  326.           NULL,                 // Any adddress will do
  327.           BLOCK_SIZE,           // Mapped block length
  328.           PROT_READ|PROT_WRITE, // Enable read+write
  329.           MAP_SHARED,           // Shared with other processes
  330.           fd,                   // File to map
  331.           (board == 2) ?
  332.            PI2_GPIO_BASE :      // -> GPIO registers
  333.            PI1_GPIO_BASE);
  334.  
  335.         close(fd);              // Not needed after mmap()
  336.         if(gpio == MAP_FAILED) err("Can't mmap()");
  337.         // Make combined bitmap of pullup-enabled pins:
  338.         for(bitmask=i=0; io[i].pin >= 0; i++)
  339.                 if(io[i].key != GND) bitmask |= (1 << io[i].pin);
  340.         gpio[GPPUD]     = 2;                    // Enable pullup
  341.         for(shortWait=150;--shortWait;);        // Min 150 cycle wait
  342.         gpio[GPPUDCLK0] = bitmask;              // Set pullup mask
  343.         for(shortWait=150;--shortWait;);        // Wait again
  344.         gpio[GPPUD]     = 0;                    // Reset pullup registers
  345.         gpio[GPPUDCLK0] = 0;
  346.         (void)munmap((void *)gpio, BLOCK_SIZE); // Done with GPIO mmap()
  347.  
  348.  
  349.         // ----------------------------------------------------------------
  350.         // All other GPIO config is handled through the sysfs interface.
  351.  
  352.         sprintf(buf, "%s/export", sysfs_root);
  353.         if((fd = open(buf, O_WRONLY)) < 0) // Open Sysfs export file
  354.                 err("Can't open GPIO export file");
  355.         for(i=j=0; io[i].pin >= 0; i++) { // For each pin of interest...
  356.                 sprintf(buf, "%d", io[i].pin);
  357.                 write(fd, buf, strlen(buf));             // Export pin
  358.                 pinConfig(io[i].pin, "active_low", "0"); // Don't invert
  359.                 if(io[i].key == GND) {
  360.                         // Set pin to output, value 0 (ground)
  361.                         if(pinConfig(io[i].pin, "direction", "out") ||
  362.                            pinConfig(io[i].pin, "value"    , "0"))
  363.                                 err("Pin config failed (GND)");
  364.                 } else {
  365.                         // Set pin to input, detect rise+fall events
  366.                         if(pinConfig(io[i].pin, "direction", "in") ||
  367.                            pinConfig(io[i].pin, "edge"     , "both"))
  368.                                 err("Pin config failed");
  369.                         // Get initial pin value
  370.                         sprintf(buf, "%s/gpio%d/value",
  371.                           sysfs_root, io[i].pin);
  372.                         // The p[] file descriptor array isn't necessarily
  373.                         // aligned with the io[] array.  GND keys in the
  374.                         // latter are skipped, but p[] requires contiguous
  375.                         // entries for poll().  So the pins to monitor are
  376.                         // at the head of p[], and there may be unused
  377.                         // elements at the end for each GND.  Same applies
  378.                         // to the intstate[] and extstate[] arrays.
  379.                         if((p[j].fd = open(buf, O_RDONLY)) < 0)
  380.                                 err("Can't access pin value");
  381.                         intstate[j] = 0;
  382.                         if((read(p[j].fd, &c, 1) == 1) && (c == '0'))
  383.                                 intstate[j] = 1;
  384.                         extstate[j] = intstate[j];
  385.                         p[j].events  = POLLPRI; // Set up poll() events
  386.                         p[j].revents = 0;
  387.                         j++;
  388.                 }
  389.         } // 'j' is now count of non-GND items in io[] table
  390.         close(fd); // Done exporting
  391.  
  392.  
  393.         // ----------------------------------------------------------------
  394.         // Set up uinput
  395.  
  396. #if 1
  397.         // Retrogame normally uses /dev/uinput for generating key events.
  398.         // Cupcade requires this and it's the default.  SDL2 (used by
  399.         // some newer emulators) doesn't like it, wants /dev/input/event0
  400.         // instead.  Enable that code by changing to "#if 0" above.
  401.         if((fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK)) < 0)
  402.                 err("Can't open /dev/uinput");
  403.         if(ioctl(fd, UI_SET_EVBIT, EV_KEY) < 0)
  404.                 err("Can't SET_EVBIT");
  405.         for(i=0; io[i].pin >= 0; i++) {
  406.                 if(io[i].key != GND) {
  407.                         if(ioctl(fd, UI_SET_KEYBIT, io[i].key) < 0)
  408.                                 err("Can't SET_KEYBIT");
  409.                 }
  410.         }
  411.         if(ioctl(fd, UI_SET_KEYBIT, vulcanKey) < 0) err("Can't SET_KEYBIT");
  412.         struct uinput_user_dev uidev;
  413.         memset(&uidev, 0, sizeof(uidev));
  414.         snprintf(uidev.name, UINPUT_MAX_NAME_SIZE, "retrogame");
  415.         uidev.id.bustype = BUS_USB;
  416.         uidev.id.vendor  = 0x1;
  417.         uidev.id.product = 0x1;
  418.         uidev.id.version = 1;
  419.         if(write(fd, &uidev, sizeof(uidev)) < 0)
  420.                 err("write failed");
  421.         if(ioctl(fd, UI_DEV_CREATE) < 0)
  422.                 err("DEV_CREATE failed");
  423. #else // SDL2 prefers this event methodology
  424.         if((fd = open("/dev/input/event0", O_WRONLY | O_NONBLOCK)) < 0)
  425.                 err("Can't open /dev/input/event0");
  426. #endif
  427.  
  428.         // Initialize input event structures
  429.         memset(&keyEv, 0, sizeof(keyEv));
  430.         keyEv.type  = EV_KEY;
  431.         memset(&synEv, 0, sizeof(synEv));
  432.         synEv.type  = EV_SYN;
  433.         synEv.code  = SYN_REPORT;
  434.         synEv.value = 0;
  435.  
  436.         // 'fd' is now open file descriptor for issuing uinput events
  437.  
  438.  
  439.         // ----------------------------------------------------------------
  440.         // Monitor GPIO file descriptors for button events.  The poll()
  441.         // function watches for GPIO IRQs in this case; it is NOT
  442.         // continually polling the pins!  Processor load is near zero.
  443.  
  444.         while(running) { // Signal handler can set this to 0 to exit
  445.                 // Wait for IRQ on pin (or timeout for button debounce)
  446.                 if(poll(p, j, timeout) > 0) { // If IRQ...
  447.                         for(i=0; i<j; i++) {       // Scan non-GND pins...
  448.                                 if(p[i].revents) { // Event received?
  449.                                         // Read current pin state, store
  450.                                         // in internal state flag, but
  451.                                         // don't issue to uinput yet --
  452.                                         // must wait for debounce!
  453.                                         lseek(p[i].fd, 0, SEEK_SET);
  454.                                         read(p[i].fd, &c, 1);
  455.                                         if(c == '0')      intstate[i] = 1;
  456.                                         else if(c == '1') intstate[i] = 0;
  457.                                         p[i].revents = 0; // Clear flag
  458.                                 }
  459.                         }
  460.                         timeout = debounceTime; // Set timeout for debounce
  461.                         c       = 0;            // Don't issue SYN event
  462.                         // Else timeout occurred
  463.                 } else if(timeout == debounceTime) { // Button debounce timeout
  464.                         // 'j' (number of non-GNDs) is re-counted as
  465.                         // it's easier than maintaining an additional
  466.                         // remapping table or a duplicate key[] list.
  467.                         bitMask = 0L; // Mask of buttons currently pressed
  468.                         bit     = 1L;
  469.                         for(c=i=j=0; io[i].pin >= 0; i++, bit<<=1) {
  470.                                 if(io[i].key != GND) {
  471.                                         // Compare internal state against
  472.                                         // previously-issued value.  Send
  473.                                         // keystrokes only for changed states.
  474.                                         if(intstate[j] != extstate[j]) {
  475.                                                 extstate[j] = intstate[j];
  476.                                                 keyEv.code  = io[i].key;
  477.                                                 keyEv.value = intstate[j];
  478.                                                 write(fd, &keyEv,
  479.                                                   sizeof(keyEv));
  480.                                                 c = 1; // Follow w/SYN event
  481.                                                 if(intstate[j]) { // Press?
  482.                                                         // Note pressed key
  483.                                                         // and set initial
  484.                                                         // repeat interval.
  485.                                                         lastKey = i;
  486.                                                         timeout = repTime1;
  487.                                                 } else { // Release?
  488.                                                         // Stop repeat and
  489.                                                         // return to normal
  490.                                                         // IRQ monitoring
  491.                                                         // (no timeout).
  492.                                                         lastKey = timeout = -1;
  493.                                                 }
  494.                                         }
  495.                                         j++;
  496.                                         if(intstate[i]) bitMask |= bit;
  497.                                 }
  498.                         }
  499.  
  500.                         // If the "Vulcan nerve pinch" buttons are pressed,
  501.                         // set long timeout -- if this time elapses without
  502.                         // a button state change, esc keypress will be sent.
  503.                         if((bitMask & vulcanMask) == vulcanMask)
  504.                                 timeout = vulcanTime;
  505.                 } else if(timeout == vulcanTime) { // Vulcan timeout occurred
  506.                         // Send keycode (MAME exits or displays exit menu)
  507.                         keyEv.code = vulcanKey;
  508.                         for(i=1; i>= 0; i--) { // Press, release
  509.                                 keyEv.value = i;
  510.                                 write(fd, &keyEv, sizeof(keyEv));
  511.                                 usleep(10000); // Be slow, else MAME flakes
  512.                                 write(fd, &synEv, sizeof(synEv));
  513.                                 usleep(10000);
  514.                         }
  515.                         timeout = -1; // Return to normal processing
  516.                         c       = 0;  // No add'l SYN required
  517.                 } else if(lastKey >= 0) { // Else key repeat timeout
  518.                         if(timeout == repTime1) timeout = repTime2;
  519.                         else if(timeout > 30)   timeout -= 5; // Accelerate
  520.                         c           = 1; // Follow w/SYN event
  521.                         keyEv.code  = io[lastKey].key;
  522.                         keyEv.value = 2; // Key repeat event
  523.                         write(fd, &keyEv, sizeof(keyEv));
  524.                 }
  525.                 if(c) write(fd, &synEv, sizeof(synEv));
  526.         }
  527.  
  528.         // ----------------------------------------------------------------
  529.         // Clean up
  530.  
  531.         ioctl(fd, UI_DEV_DESTROY); // Destroy and
  532.         close(fd);                 // close uinput
  533.         cleanup();                 // Un-export pins
  534.  
  535.         puts("Done.");
  536.  
  537.         return 0;
  538. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement