home *** CD-ROM | disk | FTP | other *** search
/ ftp.whtech.com / ftp.whtech.com.7z / ftp.whtech.com / emulators / v9t9 / linux / sources / V9t9 / source / keyboard.c < prev    next >
Encoding:
C/C++ Source or Header  |  2006-10-19  |  15.0 KB  |  617 lines

  1.  
  2. /*
  3.     ==========
  4.     KEYBOARD.C
  5.     ==========
  6. */
  7.  
  8. #include <stdlib.h>
  9. #include <stdio.h>
  10. #include <unistd.h>
  11. #include <ctype.h>
  12. #include <string.h>
  13. #include <signal.h>
  14.  
  15. #define __KEYBOARD__
  16.  
  17. #include "v9t9_common.h"
  18. #include "v9t9.h"
  19. #include "command.h"
  20. #include "command_parser.h"
  21. #include "keyboard.h"
  22. #include "timer.h"
  23.  
  24. #define _L     LOG_KEYBOARD | LOG_INFO
  25.  
  26. u8          crukeyboardmap[8];
  27. u8          caps, crukeyboardcol, AlphaLock;
  28. u8          realshift;
  29. u16         specialkey;
  30.  
  31. u8          ctrlmap[256], fctnmap[256], shiftmap[256];
  32. u32         cctrl, cfctn, cshift;
  33. u8            fakemap[256];
  34.  
  35. static void validate_shifts(void);
  36.  
  37. // these names map to SpecialKey in v9t9_module.h
  38. static const char *special_key_names[] = 
  39. {
  40.     "Pause",
  41.     "F1", "F2", "F3", "F4", "F5", "F6", 
  42.     "F7", "F8", "F9", "F10", "F11", "F12",
  43.     "Esc", "Tab",
  44.     "WinLeft", "WinRight", "WinMenu"
  45. };
  46.  
  47. #define NUMBINDINGS (SK_LAST-SK_FIRST)
  48.  
  49. /*
  50.     Bindings for special keys.
  51.     If the 'key' field is set, it must be set to
  52.     special_key_names[x] for key_binds[x];
  53.     otherwise, the keyboard module cannot generate the key.
  54. */
  55. struct {
  56.     const char *key;
  57.     char       *up, *down;
  58. } key_binds[NUMBINDINGS];
  59.  
  60. u8          bindmap[NUMBINDINGS];    /* keys currently held down */
  61.  
  62. static int  keyboard_event_tag;
  63.  
  64. static      
  65. DECL_SYMBOL_ACTION(keyboard_bind_key)
  66. {
  67.     char       *key;
  68.     char       *bind;
  69.     int         updown;            // -1 = up, 0 = none, 1 = down
  70.     int         x;
  71.  
  72.     if (task == csa_READ) {
  73.         static int bindidx;        // >0 --> find next, <0 --> show up
  74.         char tmp[32];
  75.  
  76.         if (!iter)
  77.             bindidx = 0;
  78.  
  79.         // printed up before?
  80.         if (bindidx < 0) {
  81.             sprintf(tmp, "-%s", key_binds[-bindidx].key);
  82.             command_arg_set_string(sym->args, tmp);
  83.             command_arg_set_string(sym->args->next, key_binds[-bindidx].up);
  84.             bindidx = (-bindidx)+1;
  85.             return 1;
  86.         }
  87.  
  88.         /* emit bindings for all special keys, even if current 
  89.            module doesn't support them */
  90.         while (bindidx < NUMBINDINGS && 
  91.                (/*!key_binds[bindidx].key ||*/
  92.                    !key_binds[bindidx].up ||
  93.                    !key_binds[bindidx].down)) 
  94.             bindidx++;
  95.         if (bindidx >= NUMBINDINGS)
  96.             return 0;
  97.         
  98.         if (key_binds[bindidx].up && key_binds[bindidx].down) {
  99.             sprintf(tmp, "+%s", special_key_names[bindidx]);
  100.             command_arg_set_string(sym->args, tmp);
  101.             command_arg_set_string(sym->args->next, key_binds[bindidx].down);
  102.             bindidx = -bindidx;
  103.         } else {
  104.             command_arg_set_string(sym->args, special_key_names[bindidx]);
  105.             command_arg_set_string(sym->args->next, 
  106.                                    key_binds[bindidx].up ? 
  107.                                    key_binds[bindidx].up :
  108.                                    key_binds[bindidx].down);
  109.             bindidx++;
  110.         }
  111.         return 1;
  112.     }
  113.  
  114.     if (!command_arg_get_string(sym->args, &key) ||
  115.         !command_arg_get_string(sym->args->next, &bind))
  116.         return 0;
  117.  
  118.     if (*key == '+') {
  119.         updown = 1;
  120.         key++;
  121.     } else if (*key == '-') {
  122.         updown = -1;
  123.         key++;
  124.     } else
  125.         updown = 0;
  126.  
  127.     logger(_L | L_0, "Binding %scommand to '%s':\n\t%s\n",
  128.          updown < 0 ? "up " : updown > 0 ? "down " : "", key, bind);
  129.  
  130.     for (x = 0; x < NUMBINDINGS; x++) {
  131.         if (!strcasecmp(special_key_names[x], key)) {
  132.             // if not a [+-]key, then it is a down key only,
  133.             // so remove up action
  134.             if (updown <= 0) {
  135.                 if (key_binds[x].up) {
  136.                     logger(_L | 0, "Unbinding old 'up' command:\n\t%s\n\n",
  137.                          key_binds[x].up);
  138.                     xfree(key_binds[x].up);
  139.                 }
  140.                 if (updown)
  141.                     key_binds[x].up = xstrdup(bind);
  142.                 else
  143.                     key_binds[x].down = xstrdup(bind);
  144.             } else if (updown > 0) {
  145.                 if (key_binds[x].down) {
  146.                     logger(_L | 0, "Unbinding old 'down' command:\n\t%s\n\n",
  147.                          key_binds[x].down);
  148.                     xfree(key_binds[x].down);
  149.                 }
  150.                 key_binds[x].down = xstrdup(bind);
  151.             }
  152.             break;
  153.         }
  154.     }
  155.     if (x >= NUMBINDINGS) {
  156.         parse_error("BindKey: key '%s' not defined\n", key);
  157.         return 0;
  158.     }
  159.     return 1;
  160. }
  161.  
  162. static
  163. DECL_SYMBOL_ACTION(keyboard_list_keys)
  164. {
  165.     int         x;
  166.     int         y = 0;
  167.     bool        any = false;
  168.  
  169.     if (task != csa_WRITE)
  170.         return 1;
  171.     for (x = 0; x < NUMBINDINGS; x++) {
  172.         if (key_binds[x].key) {
  173.             any = true;
  174.             if ((y += strlen(key_binds[x].key)) >= 80) {
  175.                 logger(_L | LOG_USER, "\n");
  176.                 y = 0;
  177.             }
  178.             logger(_L | LOG_USER, "%s ", key_binds[x].key);
  179.         }
  180.     }
  181.     logger(_L | LOG_USER, "\n");
  182.     if (!any)
  183.         logger(_L | LOG_USER, "<no keys to bind>\n");
  184.     return 1;
  185. }
  186.  
  187. static
  188. DECL_SYMBOL_ACTION(keyboard_list_bindings)
  189. {
  190.     int         x;
  191.     bool        any = false;
  192.  
  193.     if (task != csa_WRITE)
  194.         return 1;
  195.     for (x = 0; x < NUMBINDINGS; x++) {
  196.         if (!key_binds[x].key) {
  197.             logger(_L | LOG_USER, "<%s unavailable>\n", special_key_names[x]);
  198.         } else     if (key_binds[x].up && key_binds[x].down) {
  199.             logger(_L | LOG_USER, "+%s: %s\n" "-%s: %s\n",
  200.                  key_binds[x].key, key_binds[x].down,
  201.                  key_binds[x].key, key_binds[x].up);
  202.         } else if (key_binds[x].up || key_binds[x].down) {
  203.             logger(_L | LOG_USER, "%s: %s\n", key_binds[x].key,
  204.                  key_binds[x].down ? key_binds[x].down :
  205.                  key_binds[x].up ? key_binds[x].up : "<empty>");
  206.         } else 
  207.             continue;
  208.         any = true;
  209.     }
  210.     if (!any)
  211.         logger(_L | LOG_USER, "<no keys bound>\n");
  212.     return 1;
  213. }
  214.  
  215. static
  216. DECL_SYMBOL_ACTION(keyboard_dump_crumap)
  217. {
  218.     int i,j,b;
  219.  
  220.     logger(_L | LOG_USER, "Map of keyboard CRU:\n");
  221.     for (i = 0; i < 8; i++) {
  222.         for (b = 1, j = 0; j < 8; b<<=1,j++) {
  223.             logger(_L | LOG_USER, "%d ", !!(crukeyboardmap[i]&b));
  224.         }
  225.         logger(_L | LOG_USER, "\n");
  226.     }
  227.     return 1;
  228. }
  229.  
  230. /*    Install commands */
  231. int
  232. keyboard_preconfiginit(void)
  233. {
  234.     command_symbol_table *keyboardcommands =
  235.       command_symbol_table_new("Keyboard / Joystick Options",
  236.                                  "These are generic commands for controlling the keyboard and joystick emulation",
  237.  
  238.         command_symbol_new("AlphaLock",
  239.                             "Enable or disable ALPHA LOCK state (i.e., upon startup; CAPS performs this function at runtime)",
  240.                             c_STATIC,
  241.                             NULL /* action */ ,
  242.                             RET_FIRST_ARG,
  243.                             command_arg_new_num
  244.                             ("on|off", "state",
  245.                              NULL,
  246.                              ARG_NUM(caps),
  247.                              NULL /* next */ )
  248.                             ,
  249.  
  250.         command_symbol_new
  251.                             ("BindKey",
  252.                              "Bind a non-TI key to a command",
  253.                              c_DYNAMIC,
  254.                              keyboard_bind_key,
  255.                              NULL /* ret */ ,
  256.                              command_arg_new_string
  257.                              ("key",
  258.                               "symbolic name of key (see ListKeys); "
  259.                               "bare key name means 'perform command when key is pressed'; "
  260.                               "+key means 'perform command when key is pressed' and "
  261.                               "'perform command bound to -key when key is released'",
  262.                               NULL /* action */ ,
  263.                               NEW_ARG_STR(16),
  264.                               command_arg_new_string
  265.                               ("command",
  266.                                "text of command to execute",
  267.                                NULL /* action */ ,
  268.                                NEW_ARG_NEW_STRBUF,
  269.                                NULL /* next */ ))
  270.                              ,
  271.         command_symbol_new
  272.                              ("ListKeys",
  273.                               "List symbolic names of bindable keys",
  274.                               c_DONT_SAVE,
  275.                               keyboard_list_keys,
  276.                               NULL /* ret */ ,
  277.                               NULL    /* args */
  278.                               ,
  279.         command_symbol_new
  280.                               ("ListBindings",
  281.                                "List current key bindings",
  282.                                c_DONT_SAVE,
  283.                                keyboard_list_bindings,
  284.                                NULL /* ret */ ,
  285.                                NULL    /* args */
  286.                                ,
  287.         command_symbol_new
  288.                               ("DumpKeyMap",
  289.                                "Display map of current TI keys held down",
  290.                                c_DONT_SAVE,
  291.                                keyboard_dump_crumap,
  292.                                NULL /* ret */ ,
  293.                                NULL    /* args */
  294.                                ,
  295.  
  296.                                NULL /* next */ ))))),
  297.  
  298.          NULL /* sub */ ,
  299.  
  300.          NULL    /* next */
  301.         );
  302.  
  303.     command_symbol_table_add_subtable(universe, keyboardcommands);
  304.     return 1;
  305. }
  306.  
  307. /*    Ask keyboard module for its list of key names */
  308. int
  309. keyboard_postconfiginit(void)
  310. {
  311.     SpecialKey    *array;
  312.  
  313.     logger(_L | L_1, "keyboard_postconfiginit\n");
  314.     if (features & FE_KEYBOARD) {
  315.         int         x;
  316.  
  317.         vmKeyboard->m.kbd->getspecialkeys(&array);
  318.         for (x = 0; array[x]; x++) {
  319.             if (!(array[x] >= SK_FIRST && array[x] < SK_LAST)) {
  320.                 logger(_L | LOG_INTERNAL, "Illegal special key value %d in %s, ignoring\n",
  321.                        array[x], vmKeyboard->name);
  322.             } else {
  323.                 key_binds[array[x] - SK_FIRST].key = special_key_names[array[x] - SK_FIRST];
  324.             }
  325.         }
  326.     }
  327.     return 1;
  328. }
  329.  
  330. /*    Activate command macro
  331.  
  332.     key: 0<=key<KEYBINDINGS 
  333.     'shift' is ignored currently 
  334.  
  335. */
  336. static void
  337. keyboard_macro(int onoff, u8 shift, u8 key)
  338. {
  339.     if (onoff) {
  340.         if (bindmap[key] && key_binds[key].up)
  341.             return;                /* assume it's bad to repeat this */
  342.         else if (key_binds[key].down) {
  343.             bindmap[key] = 1;
  344.             logger(_L | L_0, "Activating binding for +'%s'\n\n\n",
  345.                  key_binds[key].key);
  346.             command_parse_text(key_binds[key].down);
  347.         } else {
  348.             if (key_binds[key].key)
  349.                 logger(_L | LOG_USER, "Nothing bound to '+%s'\n\n", key_binds[key].key);
  350.             else
  351.                 logger(_L | LOG_USER, "Special key %d not supported\n\n", key);
  352.  
  353.         }
  354.     } else {
  355.         bindmap[key] = 0;        /* don't care if it wasn't down */
  356.         if (key_binds[key].up) {
  357.             logger(_L | L_0, "Activating binding for -'%s'\n\n",
  358.                  key_binds[key].key);
  359.             command_parse_text(key_binds[key].up);
  360.         }
  361.     }
  362. }
  363.  
  364. static void
  365. keyboard_scan(int tag)
  366. {
  367.     validate_shifts();
  368.     if (features & FE_KEYBOARD)
  369.         vmKeyboardMain->m.kbd->scan();
  370. }
  371.  
  372. int
  373. keyboard_restart(void)
  374. {
  375.     memset(crukeyboardmap, 0, sizeof(crukeyboardmap));
  376.     memset(ctrlmap, 0, sizeof(ctrlmap));
  377.     memset(fctnmap, 0, sizeof(fctnmap));
  378.     memset(shiftmap, 0, sizeof(shiftmap));
  379.     memset(fakemap, 0, sizeof(fakemap));
  380.     cctrl = cfctn = cshift = 0;
  381.  
  382.     if (!keyboard_event_tag)
  383.         keyboard_event_tag = TM_UniqueTag();
  384.     TM_SetEvent(keyboard_event_tag, TM_HZ * 100 / 50, 0,
  385.                 TM_FUNC | TM_REPEAT, keyboard_scan);
  386.     return 1;
  387. }
  388.  
  389. void
  390. keyboard_restop(void)
  391. {
  392.     TM_ResetEvent(keyboard_event_tag);
  393. }
  394.  
  395.  
  396. /************************************************************/
  397.  
  398.  
  399. /*    Map of ASCII codes and their direct CRU mapping
  400.     (high nybble=row, low nybble=column), except for 0xff,
  401.     which should be faked. */
  402.  
  403. /*    NOTE: 47 = '/' in Latin-1 corresponds to the US keyboard key '/'
  404.     and '?', but on the TI keyboard, 0x75 this is the key for '/' and
  405.     '-'.  The target-specific code must trap '-', '/', '?', '_'
  406.     and should use FCTN+I for '?'.*/
  407. u8          latinto9901[128] = {
  408.     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,    /* 0-7 */
  409.     0xff, 0xff, 0xff, 0xff, 0xff, 0x50, 0xff, 0xff,    /* 8-15 */
  410.     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,    /* 16-23 */
  411.     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,    /* 24-31 */
  412.  
  413.     0x60, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,    /* 32-39 */
  414.     0xff, 0xff, 0xff, 0xff, 0x72, 0xff, 0x71, 0x75,    /* 40-47 */
  415.     0x45, 0x35, 0x31, 0x32, 0x33, 0x34, 0x44, 0x43,    /* 48-55 */
  416.     0x42, 0x41, 0xff, 0x65, 0xff, 0x70, 0xff, 0xff,    /* 56-63 */
  417.  
  418.     0xff, 0x25, 0x04, 0x02, 0x22, 0x12, 0x23, 0x24,    /* 64-71 */
  419.     0x64, 0x52, 0x63, 0x62, 0x61, 0x73, 0x74, 0x51,    /* 72-79 */
  420.     0x55, 0x15, 0x13, 0x21, 0x14, 0x53, 0x03, 0x11,    /* 80-87 */
  421.     0x01, 0x54, 0x05, 0xff, 0xff, 0xff, 0xff, 0xff,    /* 88-95 */
  422.  
  423.     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,    /* 96-103 */
  424.     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,    /* 104-111 */
  425.     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,    /* 112-119 */
  426.     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff    /* 120-127 */
  427. //      0xff,0x25,0x04,0x02,0x22,0x12,0x23,0x24,        /* 96-103 */
  428. //      0x64,0x52,0x63,0x62,0x61,0x73,0x74,0x51,        /* 104-111 */
  429. //      0x55,0x15,0x13,0x21,0x14,0x53,0x03,0x11,        /* 112-119 */
  430. //      0x01,0x54,0x05,0xff,0xff,0xff,0xff,0xff         /* 120-127 */
  431. };
  432.  
  433. void
  434. keyboard_setkey(int onoff, u8 shift, u8 key)
  435. {
  436.     u8          b, r, c;
  437.  
  438.     if (shift && onoff)
  439.         logger(_L | L_1, "turned on [%d]:  cshift=%d, cctrl=%d, cfctn=%d\n",
  440.              shift, cshift, cctrl, cfctn);
  441.  
  442.     /* macros bound to high keys */
  443.     if (key >= 128) {
  444.         keyboard_macro(onoff, shift, key - 128);
  445.         return;
  446.     }
  447.  
  448.     /*  This complicated code maintains a map of shifts
  449.        that we've explicitly turned on with other keys.  The
  450.        reason we need to know all this is that there are
  451.        multiple "on" events (repeats) but only one "off"
  452.        event.  If we do "left arrow on" (FCTN+S), 
  453.        "right arrow on" (FCTN+D), and "left arrow off" (FCTN+S)
  454.        we cannot reset FCTN since FCTN+D is still pressed.  Etc. */
  455.  
  456.     if (!onoff && !shift && fakemap[key]) {
  457.         logger(_L | L_1, "Resetting %d for key %d\n", fakemap[key], key);
  458.         shift |= fakemap[key];
  459.     }
  460.     fakemap[key] = onoff ? shift : 0;
  461.  
  462.     if (shift & SHIFT) {
  463.         if (onoff) {
  464.             if (!shiftmap[key]) {
  465.                 shiftmap[key] = 1;
  466.                 cshift++;
  467.             }
  468.             CHANGEKBDCRU(SHIFT_R, SHIFT_C, 1);
  469.         } else {
  470.             if (shiftmap[key]) {
  471.                 shiftmap[key] = 0;
  472.                 cshift--;
  473.             }
  474.             if (cshift == 0)
  475.                 CHANGEKBDCRU(SHIFT_R, SHIFT_C, 0);
  476.         }
  477.     }
  478.     if (shift & FCTN) {
  479.         if (onoff) {
  480.             if (!fctnmap[key]) {
  481.                 fctnmap[key] = 1;
  482.                 cfctn++;
  483.             }
  484.             CHANGEKBDCRU(FCTN_R, FCTN_C, 1);
  485.         } else {
  486.             if (fctnmap[key]) {
  487.                 fctnmap[key] = 0;
  488.                 cfctn--;
  489.             }
  490.             if (cfctn == 0)
  491.                 CHANGEKBDCRU(FCTN_R, FCTN_C, 0);
  492.         }
  493.     }
  494.     if (shift & CTRL) {
  495.         if (onoff) {
  496.             if (!ctrlmap[key]) {
  497.                 ctrlmap[key] = 1;
  498.                 cctrl++;
  499.             }
  500.             CHANGEKBDCRU(CTRL_R, CTRL_C, 1);
  501.         } else {
  502.             if (ctrlmap[key]) {
  503.                 ctrlmap[key] = 0;
  504.                 cctrl--;
  505.             }
  506.             if (cctrl == 0)
  507.                 CHANGEKBDCRU(CTRL_R, CTRL_C, 0);
  508.         }
  509.     }
  510.  
  511.     if (key) {
  512.         b = latinto9901[key];
  513.         if (b == 0xff)
  514.             logger(_L | LOG_ERROR,
  515.                  "keyboard_setkey:  got a key that should be faked '%c' (%d)\n\n",
  516.                  key, key);
  517.         r = b >> 4;
  518.         c = b & 15;
  519.         CHANGEKBDCRU(r, c, onoff);
  520.     } else {
  521.         if (shift & SHIFT)
  522.             realshift = (realshift & !SHIFT) | (onoff ? SHIFT : 0);
  523.         if (shift & CTRL)
  524.             realshift = (realshift & !CTRL) | (onoff ? CTRL : 0);
  525.         if (shift & FCTN)
  526.             realshift = (realshift & !FCTN) | (onoff ? FCTN : 0);
  527.     }
  528.  
  529.     if (shift && !onoff)
  530.         logger(_L | L_1, "turned off [%d]: cshift=%d, cctrl=%d, cfctn=%d\n\n",
  531.              shift, cshift, cctrl, cfctn);
  532.  
  533. }
  534.  
  535. /*
  536.  *    even with the complex checking above, fake shifts can still
  537.  *    get stuck -- check every cycle to verify that something is
  538.  *    held down besides a shift.
  539.  */
  540. #define ALL_SHIFTS    ((0x80 >> CTRL_R) | (0x80 >> FCTN_R) | (0x80 >> SHIFT_R))
  541. static void
  542. validate_shifts(void)
  543. {
  544.     // all shifts are on column 0
  545.     if (crukeyboardmap[0]
  546.     &&     !realshift
  547.     &&    !(crukeyboardmap[0] & ~ALL_SHIFTS))
  548.     {
  549.         int col;
  550.         for (col = 1; col < 6; col++)
  551.             if (crukeyboardmap[col])
  552.                 return;
  553.         
  554.         logger(_L|L_1, "Clearing fake shifts\n");
  555.  
  556.         memset(shiftmap, 0, sizeof(shiftmap));
  557.         memset(ctrlmap, 0, sizeof(ctrlmap));
  558.         memset(fctnmap, 0, sizeof(fctnmap));
  559.         crukeyboardmap[0] &= ~ALL_SHIFTS;
  560.         cshift = cfctn = cctrl = 0;
  561.     }
  562. }
  563.  
  564. int
  565. keyboard_isset(u8 shift, u8 key)
  566. {
  567.     u8          b, r, c;
  568.     int         res = 0;
  569.  
  570.     if (shift & SHIFT && TESTKBDCRU(SHIFT_R, SHIFT_C))
  571.         res = 1;
  572.     if (shift & CTRL && TESTKBDCRU(CTRL_R, CTRL_C))
  573.         res = 1;
  574.     if (shift & FCTN && TESTKBDCRU(FCTN_R, FCTN_C))
  575.         res = 1;
  576.  
  577.     if (key) {
  578.         b = latinto9901[key];
  579.         if (b == 0xff)
  580.             logger(_L | L_0,
  581.                  "keyboard_isset:  got a key that should be faked '%c' (%d)\n\n",
  582.                  key, key);
  583.         r = b >> 4;
  584.         c = b & 15;
  585.         return res && TESTKBDCRU(r, c);
  586.     } else
  587.         return res;
  588. }
  589.  
  590. /*    Set joystick bits.  
  591.     'mask' tells whether to set axes or buttons. */
  592.  
  593. //  Joy = 1 or 2, x=-1,0,1, y=-1,0,1, fire=0,1
  594. void
  595. keyboard_setjoyst(int joy, int mask, int x, int y, int fire)
  596. {
  597.     if (mask & JOY_X) {
  598.         logger(_L | L_1, "changing JOY_X (%d)\n\n", x);
  599.         CHANGEJOYCRU(joy, JOY_LEFT_R, x < 0);
  600.         CHANGEJOYCRU(joy, JOY_RIGHT_R, x > 0);
  601.     }
  602.     if (mask & JOY_Y) {
  603.         logger(_L | L_1, "changing JOY_Y (%d)\n\n", y);
  604.         CHANGEJOYCRU(joy, JOY_UP_R, y < 0);
  605.         CHANGEJOYCRU(joy, JOY_DOWN_R, y > 0);
  606.     }
  607.     if (mask & JOY_B) {
  608.         logger(_L | L_1, "changing JOY_B (%d)\n\n", fire);
  609.         CHANGEJOYCRU(joy, JOY_FIRE_R, fire);
  610.     }
  611.  
  612.     /*  clear unused bits  */
  613.     CHANGEJOYCRU(joy, 0, 0);
  614.     CHANGEJOYCRU(joy, 1, 0);
  615.     CHANGEJOYCRU(joy, 2, 0);
  616. }
  617.