From ba0c4e9426322fe1e7a14b44cdb4eae4e378127f Mon Sep 17 00:00:00 2001 From: Newsdee Date: Sun, 22 May 2016 13:26:19 +0800 Subject: [PATCH] [FIRMWARE] refactored virtual joystick to keyboard mapping into a separate file. --- mist_cfg.c | 1 + usb/hid.c | 502 ++++++++++++++++------------------------------- usb/hid.h | 10 +- usb/joymapping.c | 180 ++++++++++++++++- usb/joymapping.h | 20 ++ user_io.c | 28 ++- user_io.h | 6 +- 7 files changed, 394 insertions(+), 353 deletions(-) diff --git a/mist_cfg.c b/mist_cfg.c index 2f07829..73584ac 100644 --- a/mist_cfg.c +++ b/mist_cfg.c @@ -8,6 +8,7 @@ #include "user_io.h" #include "usb/usb.h" #include "usb/hid.h" +#include "usb/joymapping.h" //// mist_ini_parse() //// void mist_ini_parse() diff --git a/usb/hid.c b/usb/hid.c index 19649bb..4d79ea6 100644 --- a/usb/hid.c +++ b/usb/hid.c @@ -17,7 +17,6 @@ static unsigned char joysticks = 0; // number of detected usb joysticks // up to 8 buttons can be remapped #define MAX_JOYSTICK_BUTTON_REMAP 8 -#define MAX_JOYSTICK_KEYBOARD_MAP 16 /*****************************************************************************/ //NOTE: the below mapping is hardware buttons to USB, @@ -70,73 +69,6 @@ void hid_joystick_button_remap(char *s) { /*****************************************************************************/ -/* Custom parsing for joystick->keyboard map - We bind a bitmask of the virtual joypad with a keyboard USB code -*/ - -static struct { - uint16_t mask; - uint8_t modifier; - uint8_t keys[6]; // support up to 6 key codes -} joy_key_map[MAX_JOYSTICK_KEYBOARD_MAP]; - -void joy_key_map_init(void) { - memset(joy_key_map, 0, sizeof(joy_key_map)); -} - - -void joystick_key_map(char *s) { - uint8_t i,j; - uint8_t count; - uint8_t assign=0; - uint8_t len = strlen(s); - uint8_t scancode=0; - char *token; - - hid_debugf("%s(%s)", __FUNCTION__, s); - - if(len < 3) { - hid_debugf("malformed entry"); - return; - } - - // parse remap request - for(i=0;i223) { - // bit 0 1 2 3 4 5 6 7 - // key LCTRL LSHIFT LALT LGUI RCTRL RSHIFT RALT RGUI - // - scancode -= 223; - joy_key_map[i].modifier |= (0x01 << (scancode-1)); - } else { - // max 6 keys - if (assign < 7) - joy_key_map[i].keys[assign++] = scancode; - } - } - s = strtok (NULL, ","); - count+=1; - } - return; // finished processing input string so exit - } - } -} - -/*****************************************************************************/ - uint8_t hid_get_joysticks(void) { return joysticks; @@ -592,7 +524,7 @@ static void handle_5200daptor(usb_hid_iface_info_t *iface, uint8_t *buf) { // iprintf("5200: %d %d %d %d %d %d\n", buf[0],buf[1],buf[2],buf[3],buf[4],buf[5]); // generate key events - user_io_kbd(0x00, buf); + user_io_kbd(0x00, buf, UIO_PRIORITY_GAMEPAD); // save current state of keys iface->key_state = keys; @@ -651,287 +583,195 @@ static uint16_t collect_bits(uint8_t *p, uint16_t offset, uint8_t size, bool is_ static void usb_process_iface (usb_hid_iface_info_t *iface, uint16_t read, uint8_t *buf) { - - uint8_t keyb_hit = 0; // successfully received some bytes if(iface->has_boot_mode && !iface->ignore_boot_mode) { - if(iface->device_type == HID_DEVICE_MOUSE) { - // boot mouse needs at least three bytes - if(read >= 3) - // forward all three bytes to the user_io layer - user_io_mouse(buf[0], buf[1], buf[2]); - } - - if(iface->device_type == HID_DEVICE_KEYBOARD) { - // boot kbd needs at least eight bytes - if(read >= 8) { - user_io_kbd(buf[0], buf+2); - if (buf[0]||buf[1]) keyb_hit=1; //declare keyboard as pressed for later overrides - } - } + if(iface->device_type == HID_DEVICE_MOUSE) { + // boot mouse needs at least three bytes + if(read >= 3) + // forward all three bytes to the user_io layer + user_io_mouse(buf[0], buf[1], buf[2]); + } + + if(iface->device_type == HID_DEVICE_KEYBOARD) { + // boot kbd needs at least eight bytes + if(read >= 8) { + user_io_kbd(buf[0], buf+2, UIO_PRIORITY_KEYBOARD); + } + } } // use more complex parser for all joysticks. Use it for mice only if // it's explicitely stated not to use boot mode - if((iface->device_type == HID_DEVICE_JOYSTICK) || - ((iface->device_type == HID_DEVICE_MOUSE) && - iface->ignore_boot_mode)) { + if((iface->device_type == HID_DEVICE_JOYSTICK) + || ((iface->device_type == HID_DEVICE_MOUSE) + && iface->ignore_boot_mode)) { - hid_report_t *conf = &iface->conf; + hid_report_t *conf = &iface->conf; // check size of report. If a report id was given then one // additional byte is present with a matching report id if((read == conf->report_size+(conf->report_id?1:0)) && - (!conf->report_id || (buf[0] == conf->report_id))) { + (!conf->report_id || (buf[0] == conf->report_id))) { - uint8_t btn = 0, jmap = 0; - uint8_t btn_extra = 0; - int16_t a[2]; - uint8_t idx, i; + uint8_t btn = 0, jmap = 0; + uint8_t btn_extra = 0; + int16_t a[2]; + uint8_t idx, i; - // skip report id if present - uint8_t *p = buf+(conf->report_id?1:0); + // skip report id if present + uint8_t *p = buf+(conf->report_id?1:0); - // hid_debugf("data:"); hexdump(buf, read, 0); - - // two axes ... - for(i=0;i<2;i++) { - // if logical minimum is > logical maximum then logical minimum - // is signed. This means that the value itself is also signed - bool is_signed = conf->joystick_mouse.axis[i].logical.min > - conf->joystick_mouse.axis[i].logical.max; - a[i] = collect_bits(p, conf->joystick_mouse.axis[i].offset, - conf->joystick_mouse.axis[i].size, is_signed); - } - - // ... and four first buttons - for(i=0;i<4;i++) - if(p[conf->joystick_mouse.button[i].byte_offset] & - conf->joystick_mouse.button[i].bitmask) btn |= (1<joystick_mouse.button[i].byte_offset] & - conf->joystick_mouse.button[i].bitmask) btn_extra |= (1<<(i-4)); + // hid_debugf("data:"); hexdump(buf, read, 0); + + // two axes ... + for(i=0;i<2;i++) { + // if logical minimum is > logical maximum then logical minimum + // is signed. This means that the value itself is also signed + bool is_signed = conf->joystick_mouse.axis[i].logical.min > + conf->joystick_mouse.axis[i].logical.max; + a[i] = collect_bits(p, conf->joystick_mouse.axis[i].offset, + conf->joystick_mouse.axis[i].size, is_signed); + } + + // ... and four first buttons + for(i=0;i<4;i++) + if(p[conf->joystick_mouse.button[i].byte_offset] & + conf->joystick_mouse.button[i].bitmask) btn |= (1<joystick_mouse.button[i].byte_offset] & + conf->joystick_mouse.button[i].bitmask) btn_extra |= (1<<(i-4)); - //if (btn_extra != 0) - // iprintf("EXTRA BTNS:%d\n", btn_extra); - + //if (btn_extra != 0) + // iprintf("EXTRA BTNS:%d\n", btn_extra); - // ---------- process mouse ------------- - if(iface->device_type == HID_DEVICE_MOUSE) { - // iprintf("mouse %d %d %x\n", (int16_t)a[0], (int16_t)a[1], btn); - // limit mouse movement to +/- 128 - for(i=0;i<2;i++) { - if((int16_t)a[i] > 127) a[i] = 127; - if((int16_t)a[i] < -128) a[i] = -128; - } - user_io_mouse(btn, a[0], a[1]); - } - - // ---------- process joystick ------------- - if(iface->device_type == HID_DEVICE_JOYSTICK) { - - for(i=0;i<2;i++) { - // scale to 0 -> 255 range. 99% of the joysticks already deliver that - if((conf->joystick_mouse.axis[i].logical.min != 0) || - (conf->joystick_mouse.axis[i].logical.max != 255)) { - a[i] = ((a[i] - conf->joystick_mouse.axis[i].logical.min) * 255)/ - (conf->joystick_mouse.axis[i].logical.max - - conf->joystick_mouse.axis[i].logical.min); - } - } - - // handle hat if present and overwrite any axis value - if(conf->joystick_mouse.hat.size && !mist_cfg.joystick_ignore_hat) { - uint8_t hat = collect_bits(p, conf->joystick_mouse.hat.offset, - conf->joystick_mouse.hat.size, 0); - - // we don't want more than 4 bits - uint8_t size = conf->joystick_mouse.hat.size; - while(size-- > 4) - hat >>= 1; - - // iprintf("HAT = %d\n", hat); - - // TODO: Deal with 3 bit (4 direction/no diagonal) hats - static const uint8_t hat2x[] = { 127,255,255,255,127, 0, 0, 0 }; - static const uint8_t hat2y[] = { 0, 0,127,255,255,255,127, 0 }; - - if(hat&8) { - // hat is idle - don't override analog - /* - if (a[0] > JOYSTICK_AXIS_TRIGGER_MIN) || a[0] < JOYSTICK_AXIS_TRIGGER_MAX) a[0] = JOYSTICK_AXIS_MID; - if (a[1] > JOYSTICK_AXIS_TRIGGER_MIN) || a[1] < JOYSTICK_AXIS_TRIGGER_MAX) a[1] = JOYSTICK_AXIS_MID; - */ - } else { - uint8_t x_val = hat2x[hat]; - uint8_t y_val = hat2y[hat]; - // cancel out with X analog axis if it pushes on the opposite direction - if(x_val < JOYSTICK_AXIS_TRIGGER_MIN) { - // hat pointing left, compensate if analog is pointing right - if (a[0] > JOYSTICK_AXIS_TRIGGER_MAX) { a[0] = JOYSTICK_AXIS_MID; } - else a[0] = x_val; - } else { - if(x_val > JOYSTICK_AXIS_TRIGGER_MAX) { - // hat pointing right, compensate if analog pointing left - if (a[0] < JOYSTICK_AXIS_TRIGGER_MIN) { a[0] = JOYSTICK_AXIS_MID; } - else a[0] = x_val; - } - } - // same logic for Y axis - if(y_val < JOYSTICK_AXIS_TRIGGER_MIN) { - // hat pointing down - if (a[1] > JOYSTICK_AXIS_TRIGGER_MAX) { a[1] = JOYSTICK_AXIS_MID; } - else a[1] = y_val; - } else { - if(y_val > JOYSTICK_AXIS_TRIGGER_MAX) { - // hat pointing up - if (a[1] < JOYSTICK_AXIS_TRIGGER_MIN) { a[1] = JOYSTICK_AXIS_MID; } - else a[1] = y_val; //otherwise override - } - } - } - } - - // iprintf("JOY X:%d Y:%d\n", a[0], a[1]); - - if(a[0] < JOYSTICK_AXIS_TRIGGER_MIN) jmap |= JOY_LEFT; - if(a[0] > JOYSTICK_AXIS_TRIGGER_MAX) jmap |= JOY_RIGHT; - if(a[1] < JOYSTICK_AXIS_TRIGGER_MIN) jmap |= JOY_UP; - if(a[1] > JOYSTICK_AXIS_TRIGGER_MAX) jmap |= JOY_DOWN; - jmap |= btn << JOY_BTN_SHIFT; // add buttons - - // map virtual joypad - uint16_t vjoy = jmap; - vjoy |= btn_extra << 8; - vjoy = virtual_joystick_mapping( conf->joystick_mouse.vid, conf->joystick_mouse.pid, vjoy ); - - //iprintf("VIRTUAL JOY:%d\n", vjoy); - //if (jmap != 0) iprintf("JMAP pre map:%d\n", jmap); - - //now go back to original variables for downstream processing - btn_extra = ((vjoy & 0xFF00) >> 8); - jmap = (vjoy & 0x00FF); - - //if (jmap != 0) iprintf("JMAP post map:%d\n", jmap); - - // swap joystick 0 and 1 since 1 is the one - // used primarily on most systems - idx = iface->jindex; - if(idx == 0) idx = 1; - else if(idx == 1) idx = 0; - - // check if joystick state has changed - if(jmap != iface->jmap) { - // and feed into joystick input system - user_io_digital_joystick(idx, jmap); - iface->jmap = jmap; - } - - // also send analog values - user_io_analog_joystick(idx, a[0]-128, a[1]-128); - - // do special 5200daptor treatment - if(iface->is_5200daptor) - handle_5200daptor(iface, buf); - - // use button combinations as shortcut for certain keys - if(!mist_cfg.joystick_disable_shortcuts) { - uint8_t buf[6] = { 0,0,0,0,0,0 }; - uint8_t key_hit = 0; - - // if OSD is open control it via USB joystick - if(user_io_osd_is_visible() && !mist_cfg.joystick_ignore_osd) { - - if(vjoy & JOY_A) buf[0] = 0x28; // ENTER - if(vjoy & JOY_B) buf[0] = 0x29; // ESC - if(vjoy & JOY_START) buf[0] = 0x45; // F12 - if(vjoy & JOY_LEFT) buf[0] = 0x50; // left arrow - if(vjoy & JOY_RIGHT) buf[0] = 0x4F; // right arrow - // up and down uses SELECT or L for faster scrolling - if(vjoy & JOY_UP) { - if (vjoy & JOY_SELECT || vjoy & JOY_L) buf[1] = 0x4B; // page up - else buf[1] = 0x52; // up arrow - } - if(vjoy & JOY_DOWN) { - if (vjoy & JOY_SELECT || vjoy & JOY_L) buf[1] = 0x4E; // page down - else buf[1] = 0x51; // down arrow - } - user_io_kbd(0x00, buf); // generate key events - key_hit=1; - - } else { - - // shortcuts mapped if start is pressed (take priority) - if (vjoy & JOY_START) { - if(vjoy & JOY_A) buf[0] = 0x28; // ENTER - if(vjoy & JOY_B) buf[1] = 0x2C; // SPACE - if(vjoy & JOY_L) buf[1] = 0x29; // ESC - if(vjoy & JOY_R) buf[1] = 0x3A; // F1 - if(vjoy & JOY_SELECT) buf[2] = 0x45; //F12 // i.e. open OSD in most cores - user_io_kbd(0x00, buf); // generate key events - key_hit=1; - - } else { - - // shortcuts with SELECT - mouse emulation - if (vjoy & JOY_SELECT) { - unsigned char but = 0; - char a0 = 0; - char a1 = 0; - if (vjoy & JOY_L) but |= 1; - if (vjoy & JOY_R) but |= 2; - if (vjoy & JOY_LEFT) a0 = -4; - if (vjoy & JOY_RIGHT) a0 = 4; - if (vjoy & JOY_UP) a1 = -2; - if (vjoy & JOY_DOWN) a1 = 2; - user_io_mouse(but, a0, a1); - } - - } - - // process mapped keyboard commands from mist.ini - uint8_t i, j, count=0; - uint8_t mapped_hit = 0; - uint8_t modifier = 0; - uint8_t has_mapping = 0; - uint8_t joy_buf[6] = { 0,0,0,0,0,0 }; - for(i=0;idevice_type == HID_DEVICE_MOUSE) { + // iprintf("mouse %d %d %x\n", (int16_t)a[0], (int16_t)a[1], btn); + // limit mouse movement to +/- 128 + for(i=0;i<2;i++) { + if((int16_t)a[i] > 127) a[i] = 127; + if((int16_t)a[i] < -128) a[i] = -128; } - for (j=0; j<6; j++) { - if (joy_key_map[i].keys[j]) { - joy_buf[j] = joy_key_map[i].keys[j]; - mapped_hit=1; - //iprintf("j2k code:%d\n", joy_buf[j]); - - } - } - } + user_io_mouse(btn, a[0], a[1]); } - // generate key events but only if no other keys were pressed - if (has_mapping && !keyb_hit && !key_hit) { - if(mapped_hit) - user_io_kbd(modifier, joy_buf); - else - user_io_kbd(0x00, joy_buf); - } - } - - } // end joy->keyboard shortcuts - - - } // end joystick handling - - } // end hid custom report parsing - + + // ---------- process joystick ------------- + if(iface->device_type == HID_DEVICE_JOYSTICK) { + + for(i=0;i<2;i++) { + // scale to 0 -> 255 range. 99% of the joysticks already deliver that + if((conf->joystick_mouse.axis[i].logical.min != 0) || + (conf->joystick_mouse.axis[i].logical.max != 255)) { + a[i] = ((a[i] - conf->joystick_mouse.axis[i].logical.min) * 255)/ + (conf->joystick_mouse.axis[i].logical.max - + conf->joystick_mouse.axis[i].logical.min); + } + } + + // handle hat if present and overwrite any axis value + if(conf->joystick_mouse.hat.size && !mist_cfg.joystick_ignore_hat) { + uint8_t hat = collect_bits(p, conf->joystick_mouse.hat.offset, + conf->joystick_mouse.hat.size, 0); + + // we don't want more than 4 bits + uint8_t size = conf->joystick_mouse.hat.size; + while(size-- > 4) + hat >>= 1; + + // iprintf("HAT = %d\n", hat); + + // TODO: Deal with 3 bit (4 direction/no diagonal) hats + static const uint8_t hat2x[] = { 127,255,255,255,127, 0, 0, 0 }; + static const uint8_t hat2y[] = { 0, 0,127,255,255,255,127, 0 }; + + if(hat&8) { + // hat is idle - don't override analog + /* + if (a[0] > JOYSTICK_AXIS_TRIGGER_MIN) || a[0] < JOYSTICK_AXIS_TRIGGER_MAX) a[0] = JOYSTICK_AXIS_MID; + if (a[1] > JOYSTICK_AXIS_TRIGGER_MIN) || a[1] < JOYSTICK_AXIS_TRIGGER_MAX) a[1] = JOYSTICK_AXIS_MID; + */ + } else { + uint8_t x_val = hat2x[hat]; + uint8_t y_val = hat2y[hat]; + // cancel out with X analog axis if it pushes on the opposite direction + if(x_val < JOYSTICK_AXIS_TRIGGER_MIN) { + // hat pointing left, compensate if analog is pointing right + if (a[0] > JOYSTICK_AXIS_TRIGGER_MAX) { a[0] = JOYSTICK_AXIS_MID; } + else a[0] = x_val; + } else { + if(x_val > JOYSTICK_AXIS_TRIGGER_MAX) { + // hat pointing right, compensate if analog pointing left + if (a[0] < JOYSTICK_AXIS_TRIGGER_MIN) { a[0] = JOYSTICK_AXIS_MID; } + else a[0] = x_val; + } + } + // same logic for Y axis + if(y_val < JOYSTICK_AXIS_TRIGGER_MIN) { + // hat pointing down + if (a[1] > JOYSTICK_AXIS_TRIGGER_MAX) { a[1] = JOYSTICK_AXIS_MID; } + else a[1] = y_val; + } else { + if(y_val > JOYSTICK_AXIS_TRIGGER_MAX) { + // hat pointing up + if (a[1] < JOYSTICK_AXIS_TRIGGER_MIN) { a[1] = JOYSTICK_AXIS_MID; } + else a[1] = y_val; //otherwise override + } + } + } + } // end joystick hat handler + + // iprintf("JOY X:%d Y:%d\n", a[0], a[1]); + + if(a[0] < JOYSTICK_AXIS_TRIGGER_MIN) jmap |= JOY_LEFT; + if(a[0] > JOYSTICK_AXIS_TRIGGER_MAX) jmap |= JOY_RIGHT; + if(a[1] < JOYSTICK_AXIS_TRIGGER_MIN) jmap |= JOY_UP; + if(a[1] > JOYSTICK_AXIS_TRIGGER_MAX) jmap |= JOY_DOWN; + jmap |= btn << JOY_BTN_SHIFT; // add buttons + + // map virtual joypad + uint16_t vjoy = jmap; + vjoy |= btn_extra << 8; + vjoy = virtual_joystick_mapping( conf->joystick_mouse.vid, conf->joystick_mouse.pid, vjoy ); + + //iprintf("VIRTUAL JOY:%d\n", vjoy); + //if (jmap != 0) iprintf("JMAP pre map:%d\n", jmap); + + //now go back to original variables for downstream processing + btn_extra = ((vjoy & 0xFF00) >> 8); + jmap = (vjoy & 0x00FF); + + //if (jmap != 0) iprintf("JMAP post map:%d\n", jmap); + + // swap joystick 0 and 1 since 1 is the one + // used primarily on most systems + idx = iface->jindex; + if(idx == 0) idx = 1; + else if(idx == 1) idx = 0; + + // check if joystick state has changed + if(jmap != iface->jmap) { + // and feed into joystick input system + user_io_digital_joystick(idx, jmap); + iface->jmap = jmap; + } + + // also send analog values + user_io_analog_joystick(idx, a[0]-128, a[1]-128); + + // do special 5200daptor treatment + if(iface->is_5200daptor) + handle_5200daptor(iface, buf); + + // apply keyboard mappings + virtual_joystick_keyboard ( vjoy ); + + } // end joystick handling + + } // end hid custom report parsing } // end of HID complex parsing } diff --git a/usb/hid.h b/usb/hid.h index e7075e6..567e365 100644 --- a/usb/hid.h +++ b/usb/hid.h @@ -100,15 +100,9 @@ void hid_set_kbd_led(unsigned char led, bool on); uint8_t hid_get_joysticks(void); int8_t hid_keyboard_present(void); +// HID low-level remapping - do not confuse with virtual joystick in joymapping.h void hid_joystick_button_remap_init(void); void hid_joystick_button_remap(char *); - -void virtual_joystick_remap_init(void); -void virtual_joystick_remap(char *); - -void joystick_key_map_init(void); -void joystick_key_map(char *); - -void joy_key_map_init(void); +void joy_key_map_init(void); // older function, prefer to use joymapping.h function #endif // HID_H diff --git a/usb/joymapping.c b/usb/joymapping.c index 1f3bd98..2379cac 100644 --- a/usb/joymapping.c +++ b/usb/joymapping.c @@ -19,10 +19,10 @@ This file defines how to handle mapping in the MiST controllers in various ways: #define MAX_VIRTUAL_JOYSTICK_REMAP 8 #define MAX_JOYSTICK_KEYBOARD_MAP 16 -/*****************************************************************************/ -/* Virtual joystick remap - custom parsing - The mapping translates directions plus generic HID buttons (1-12) into a standard MiST "virtual joystick" -*/ +/*****************************************************************************\ + Virtual joystick remap - custom parsing + The mapping translates directions plus generic HID buttons (1-12) into a sandard MiST "virtual joystick" +\****************************************************************************/ static struct { uint16_t vid; @@ -118,7 +118,7 @@ void virtual_joystick_remap(char *s) { /* Translates USB input into internal virtual joystick, with some default handling for common/known gampads */ - uint16_t virtual_joystick_mapping (uint16_t vid, uint16_t pid, uint16_t joy_input) { +uint16_t virtual_joystick_mapping (uint16_t vid, uint16_t pid, uint16_t joy_input) { uint8_t i; @@ -247,3 +247,173 @@ void virtual_joystick_remap(char *s) { return vjoy; } +/*****************************************************************************\ + Virtual joystick to Keyboard mapping + binds different button states of internal joypad to verious key combinations +\****************************************************************************/ + +/*****************************************************************************/ + +/* Custom parsing for joystick->keyboard map + We bind a bitmask of the virtual joypad with a keyboard USB code +*/ + +static struct { + uint16_t mask; + uint8_t modifier; + uint8_t keys[6]; // support up to 6 key codes +} joy_key_map[MAX_JOYSTICK_KEYBOARD_MAP]; + +void joy_key_map_init(void) { + memset(joy_key_map, 0, sizeof(joy_key_map)); +} + + +void joystick_key_map(char *s) { + uint8_t i,j; + uint8_t count; + uint8_t assign=0; + uint8_t len = strlen(s); + uint8_t scancode=0; + char *token; + + hid_debugf("%s(%s)", __FUNCTION__, s); + + if(len < 3) { + hid_debugf("malformed entry"); + return; + } + + // parse remap request + for(i=0;i223) { + // bit 0 1 2 3 4 5 6 7 + // key LCTRL LSHIFT LALT LGUI RCTRL RSHIFT RALT RGUI + // + scancode -= 223; + joy_key_map[i].modifier |= (0x01 << (scancode-1)); + } else { + // max 6 keys + if (assign < 7) + joy_key_map[i].keys[assign++] = scancode; + } + } + s = strtok (NULL, ","); + count+=1; + } + return; // finished processing input string so exit + } + } +} + +/*****************************************************************************/ + +void virtual_joystick_keyboard ( uint16_t vjoy, uint8_t keyb_hit ) { + + // ignore if globally switched off + if(mist_cfg.joystick_disable_shortcuts) + return; + + // use button combinations as shortcut for certain keys + uint8_t buf[6] = { 0,0,0,0,0,0 }; + uint8_t key_hit = 0; + + // if OSD is open control it via USB joystick + if(user_io_osd_is_visible() && !mist_cfg.joystick_ignore_osd) { + + if(vjoy & JOY_A) buf[0] = 0x28; // ENTER + if(vjoy & JOY_B) buf[0] = 0x29; // ESC + if(vjoy & JOY_START) buf[0] = 0x45; // F12 + if(vjoy & JOY_LEFT) buf[0] = 0x50; // left arrow + if(vjoy & JOY_RIGHT) buf[0] = 0x4F; // right arrow + + // up and down uses SELECT or L for faster scrolling + if(vjoy & JOY_UP) { + if (vjoy & JOY_SELECT || vjoy & JOY_L) buf[1] = 0x4B; // page up + else buf[1] = 0x52; // up arrow + } + if(vjoy & JOY_DOWN) { + if (vjoy & JOY_SELECT || vjoy & JOY_L) buf[1] = 0x4E; // page down + else buf[1] = 0x51; // down arrow + } + user_io_kbd(0x00, buf, UIO_PRIORITY_GAMEPAD); // generate key events + if (buf[0]!=0 || buf[1]!=0) { + key_hit=1; + } + + } else { + + // shortcuts mapped if start is pressed (take priority) + if (vjoy & JOY_START) { + if(vjoy & JOY_A) buf[0] = 0x28; // ENTER + if(vjoy & JOY_B) buf[1] = 0x2C; // SPACE + if(vjoy & JOY_L) buf[1] = 0x29; // ESC + if(vjoy & JOY_R) buf[1] = 0x3A; // F1 + if(vjoy & JOY_SELECT) buf[2] = 0x45; //F12 // i.e. open OSD in most cores + user_io_kbd(0x00, buf, UIO_PRIORITY_GAMEPAD); // generate key events + if(buf[0]!=0 || buf[1]!=0 || buf[2]!= 0) { + key_hit=1; + } + } else { + + // shortcuts with SELECT - mouse emulation + if (vjoy & JOY_SELECT) { + unsigned char but = 0; + char a0 = 0; + char a1 = 0; + if (vjoy & JOY_L) but |= 1; + if (vjoy & JOY_R) but |= 2; + if (vjoy & JOY_LEFT) a0 = -4; + if (vjoy & JOY_RIGHT) a0 = 4; + if (vjoy & JOY_UP) a1 = -2; + if (vjoy & JOY_DOWN) a1 = 2; + user_io_mouse(but, a0, a1); + } + + } + } + + // process mapped keyboard commands from mist.ini + uint8_t i, j, count=0; + uint8_t mapped_hit = 0; + uint8_t modifier = 0; + uint8_t has_mapping = 0; + uint8_t joy_buf[6] = { 0,0,0,0,0,0 }; + for(i=0;iJoystick mapping and Keyboard bindings) +/*****************************************************************************/ + + #ifndef JOYMAPPING_H #define JOYMAPPING_H #include #include +/*****************************************************************************/ + +// INI parsing void virtual_joystick_remap_init(void); void virtual_joystick_remap(char *); +// runtime mapping uint16_t virtual_joystick_mapping (uint16_t vid, uint16_t pid, uint16_t joy_input); +/*****************************************************************************/ + +// INI parsing +void joystick_key_map_init(void); +void joystick_key_map(char *); + +// runtime mapping +void virtual_joystick_keyboard ( uint16_t vjoy ); + +/*****************************************************************************/ + #endif // JOYMAPPING_H diff --git a/user_io.c b/user_io.c index 8d24c73..d6223bb 100644 --- a/user_io.c +++ b/user_io.c @@ -53,6 +53,10 @@ AT91PS_PMC a_pPMC = AT91C_BASE_PMC; // keep state of caps lock static char caps_lock_toggle = 0; +// avoid multiple keyboard/controllers to interfere +static uint8_t latest_keyb_priority = 0; // keyboard=0, joypad with key mappings=1 + + // mouse position storage for ps2 and minimig rate limitation #define X 0 #define Y 1 @@ -1391,7 +1395,15 @@ static char key_used_by_osd(unsigned short s) { (core_type == CORE_TYPE_8BIT)); } -void user_io_kbd(unsigned char m, unsigned char *k) { +void user_io_kbd(unsigned char m, unsigned char *k, uint8_t priority) { + + // ignore lower priority clears if higher priority key was pressed + if (m==0 && k[0]==0 && k[1]==0 && k[2]==0) { + if (priority < latest_keyb_priority) + return; + } + latest_keyb_priority = priority; // set for next calloc + if((core_type == CORE_TYPE_MINIMIG) || (core_type == CORE_TYPE_MINIMIG2) || (core_type == CORE_TYPE_MIST) || @@ -1448,13 +1460,13 @@ void user_io_kbd(unsigned char m, unsigned char *k) { // check if state of mouse buttons has changed // (on a mouse only two buttons are supported) if((last_btn & (JOY_BTN1 | JOY_BTN2)) != - (emu_state & (JOY_BTN1 | JOY_BTN2))) { - if(emu_mode == EMU_MOUSE) { - unsigned char b; - if(emu_state & JOY_BTN1) b |= 1; - if(emu_state & JOY_BTN2) b |= 2; - user_io_mouse(b, 0, 0); - } + (emu_state & (JOY_BTN1 | JOY_BTN2))) { + if(emu_mode == EMU_MOUSE) { + unsigned char b; + if(emu_state & JOY_BTN1) b |= 1; + if(emu_state & JOY_BTN2) b |= 2; + user_io_mouse(b, 0, 0); + } } // check if state of joystick buttons has changed diff --git a/user_io.h b/user_io.h index e1de388..4df6f37 100644 --- a/user_io.h +++ b/user_io.h @@ -114,6 +114,10 @@ #define UIO_PARITY_MARK 3 #define UIO_PARITY_SPACE 4 +#define UIO_PRIORITY_KEYBOARD 0 +#define UIO_PRIORITY_GAMEPAD 1 + + // serial status data type returned from the core typedef struct { uint32_t bitrate; // 300, 600 ... 115200 @@ -153,7 +157,7 @@ void user_io_eth_receive_tx_frame(uint8_t *, uint16_t); // hooks from the usb layer void user_io_mouse(unsigned char b, char x, char y); -void user_io_kbd(unsigned char m, unsigned char *k); +void user_io_kbd(unsigned char m, unsigned char *k, uint8_t priority); char user_io_create_config_name(char *s); void user_io_digital_joystick(unsigned char, unsigned char); void user_io_analog_joystick(unsigned char, char, char);