/* This file is part of MiST-firmware MiST-firmware is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. MiST-firmware is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* This file defines how to handle mapping in the MiST controllers in various ways: 1) USB input to internal "virtual joystick" (standardizes inputs) 2) Virtual joystick to keyboard */ #include #include #include #include "timer.h" #include "debug.h" #include "joymapping.h" #include "../user_io.h" #include "../mist_cfg.h" // up to 8 buttons can be remapped #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 sandard MiST "virtual joystick" \****************************************************************************/ static joymapping_t joystick_mappers[MAX_VIRTUAL_JOYSTICK_REMAP]; static uint16_t default_joystick_mapping [16] = { JOY_RIGHT, JOY_LEFT, JOY_DOWN, JOY_UP, JOY_A, JOY_B, JOY_SELECT, JOY_START, JOY_X, JOY_Y, JOY_L, JOY_R, JOY_L2, JOY_R2, JOY_L3, JOY_R3 }; static char dump_mapping() { for(int i=0;i %d", joystick_mappers[i].vid, joystick_mappers[i].pid, count, joystick_mappers[i].mapping[count]); } token = strtok (NULL, ","); count++; } return 0; // finished processing input string so exit } } return 0; } void virtual_joystick_remap_update(joymapping_t *map) { for(int i=0;ivid && joystick_mappers[i].pid == map->pid && joystick_mappers[i].tag == map->tag) || !joystick_mappers[i].vid) { memcpy(&joystick_mappers[i], map, sizeof(joymapping_t)); return; } } } void virtual_joystick_tag_update(uint16_t vid, uint16_t pid, int newtag) { // first search for the entry to update with the largest tag int old = -1, new = -1, i, oldtag = 0; for(i=0;i= oldtag) { old = i; } } if (old == -1) return; // old entry not found // now search if the entry with the same newtag already there for(i=0;i= tag) { for(i=0; i<16; i++) mapping[i]=joystick_mappers[j].mapping[i]; use_default=0; tag = joystick_mappers[j].tag + 1; } } // apply default mapping to rest of buttons if requested if (use_default) { for(i=4; i<16; i++) if (mapping[i]==0) mapping[i]=default_joystick_mapping[i]; } uint16_t vjoy = 0; for(i=0; i<16; i++) if (joy_input & (0x01<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)); } char joystick_key_map(char *s, char action, int tag) { 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(action == INI_SAVE) return 0; if(len < 3) { hid_debugf("malformed entry"); return 0; } // 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 0; // finished processing input string so exit } } } /*****************************************************************************/ bool virtual_joystick_keyboard ( uint16_t vjoy ) { // ignore if globally switched off if(mist_cfg.joystick_disable_shortcuts) return false; // use button combinations as shortcut for certain keys uint8_t buf[6] = { 0,0,0,0,0,0 }; // if OSD is open control it via USB joystick if(user_io_osd_is_visible() && !mist_cfg.joystick_ignore_osd) { int idx = 0; if(vjoy & JOY_A) buf[idx++] = 0x28; // ENTER if(vjoy & JOY_B) buf[idx++] = 0x29; // ESC if(vjoy & JOY_START) buf[idx++] = 0x45; // F12 if(vjoy & JOY_LEFT) buf[idx++] = 0x50; // left arrow if(vjoy & JOY_RIGHT) buf[idx++] = 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[idx] = 0x4B; // page up else buf[idx] = 0x52; // up arrow if (idx < 6) idx++; //avoid overflow if we assigned 6 already } if(vjoy & JOY_DOWN) { if (vjoy & JOY_SELECT || vjoy & JOY_L) buf[idx] = 0x4E; // page down else buf[idx] = 0x51; // down arrow if (idx < 6) idx++; //avoid overflow if we assigned 6 already } if (!(vjoy & JOY_UP) && !(vjoy & JOY_DOWN)) { if (vjoy & JOY_L) buf[idx++] = 0x56;// KP- else if (vjoy & JOY_R) buf[idx++] = 0x57;// KP+ } } else { // shortcuts mapped if start is pressed (take priority) if (vjoy & JOY_START) { //iprintf("joy2key START is pressed\n"); int idx = 0; if(vjoy & JOY_A) buf[idx++] = 0x28; // ENTER if(vjoy & JOY_B) buf[idx++] = 0x2C; // SPACE if(vjoy & JOY_L) buf[idx++] = 0x29; // ESC if(vjoy & JOY_R) buf[idx++] = 0x3A; // F1 if(vjoy & JOY_SELECT) buf[idx++] = 0x45; //F12 // i.e. open OSD in most cores } else { // shortcuts with SELECT - mouse emulation if (vjoy & JOY_SELECT) { //iprintf("joy2key SELECT is pressed\n"); 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(0, but, a0, a1, 0); } } } // process mapped keyboard commands from mist.ini uint8_t i, j, k, 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;i=6) break; // max keys reached if (joy_key_map[i].keys[j]) { buf[k++] = joy_key_map[i].keys[j]; mapped_hit=1; //iprintf("joy2key hit:%d\n", joy_key_map[i].keys[j]); } } } } // generate key events but only if no other keys were pressed if (has_mapping && mapped_hit) { user_io_kbd(modifier, buf, UIO_PRIORITY_GAMEPAD, 0, 0); } else { user_io_kbd(0x00, buf, UIO_PRIORITY_GAMEPAD, 0, 0); } return (buf[0] ? true : false); }