mirror of
https://github.com/mist-devel/mist-firmware.git
synced 2026-01-11 23:43:04 +00:00
659 lines
19 KiB
C
659 lines
19 KiB
C
/*
|
|
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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/*
|
|
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 <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
#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<MAX_VIRTUAL_JOYSTICK_REMAP;i++) {
|
|
if(joystick_mappers[i].vid && joystick_mappers[i].pid) {
|
|
iprintf("map[%d]: VID: %04x PID: %04x tag: %d\n", i, joystick_mappers[i].vid, joystick_mappers[i].pid, joystick_mappers[i].tag);
|
|
}
|
|
}
|
|
}
|
|
|
|
static char idx = 0;
|
|
|
|
void virtual_joystick_remap_init(char save) {
|
|
if(save)
|
|
idx = 0;
|
|
else
|
|
memset(joystick_mappers, 0, sizeof(joystick_mappers));
|
|
}
|
|
|
|
/* Parses an input comma-separated string into a mapping strucutre
|
|
The string is expected to have the following format: [VID],[PID],[comma separated list of buttons]
|
|
and requires at least 13 characters in length
|
|
*/
|
|
|
|
char virtual_joystick_remap(char *s, char action, int tag) {
|
|
|
|
uint8_t i;
|
|
uint8_t count;
|
|
uint8_t len = strlen(s);
|
|
uint16_t value = 0;
|
|
uint16_t pid, vid;
|
|
char *token;
|
|
char *sub_token;
|
|
|
|
|
|
// save entry to string
|
|
if(action == INI_SAVE) {
|
|
hid_debugf("%s(tag: %d)", __FUNCTION__, tag);
|
|
|
|
while(1) {
|
|
if (idx == MAX_VIRTUAL_JOYSTICK_REMAP || joystick_mappers[idx].vid == 0)
|
|
return 0;
|
|
if(joystick_mappers[idx].tag == tag) {
|
|
siprintf(s, "%04X,%04X", joystick_mappers[idx].vid, joystick_mappers[idx].pid);
|
|
for (count=0; count<16; count++) {
|
|
char hex[16];
|
|
siprintf(hex, ",%X", joystick_mappers[idx].mapping[count]);
|
|
strcat(s, hex);
|
|
}
|
|
idx++;
|
|
return 1;
|
|
}
|
|
idx++;
|
|
}
|
|
}
|
|
|
|
hid_debugf("%s(%s)", __FUNCTION__, s);
|
|
|
|
// load entry from string
|
|
if(len < 13) {
|
|
hid_debugf("malformed entry");
|
|
return 0;
|
|
}
|
|
|
|
token = strtok (s, ",");
|
|
if (!token) {
|
|
hid_debugf("no vid");
|
|
return 0;
|
|
}
|
|
vid = strtol(token, NULL, 16);
|
|
if (vid==0) {
|
|
hid_debugf("invalid vid");
|
|
return 0; // invalid vid
|
|
}
|
|
|
|
token = strtok (NULL, ",");
|
|
if (!token) {
|
|
hid_debugf("no pid");
|
|
return 0;
|
|
}
|
|
pid = strtol(token, NULL, 16);
|
|
if (pid==0) {
|
|
hid_debugf("invalid pid");
|
|
return 0; // invalid vid
|
|
}
|
|
|
|
// parse remap request
|
|
for(i=0;i<MAX_VIRTUAL_JOYSTICK_REMAP;i++) {
|
|
// update if the same vid/pid/tag found, or use the first empty slot
|
|
if((joystick_mappers[i].vid == vid &&
|
|
joystick_mappers[i].pid == pid &&
|
|
joystick_mappers[i].tag == tag) ||
|
|
!joystick_mappers[i].vid) {
|
|
// init mapping data
|
|
for (count=0; count<16; count++)
|
|
joystick_mappers[i].mapping[count]=0;
|
|
|
|
joystick_mappers[i].vid = vid;
|
|
joystick_mappers[i].pid = pid;
|
|
joystick_mappers[i].tag = tag;
|
|
// default assignment for directions
|
|
joystick_mappers[i].mapping[0] = JOY_RIGHT;
|
|
joystick_mappers[i].mapping[1] = JOY_LEFT;
|
|
joystick_mappers[i].mapping[2] = JOY_DOWN;
|
|
joystick_mappers[i].mapping[3] = JOY_UP;
|
|
count = 0;
|
|
token = strtok (NULL, ",");
|
|
while(token!=NULL) {
|
|
value = strtol(token, NULL, 16);
|
|
if (count < 16) {
|
|
//parse sub-tokens sequentially and assign 16-bit value to them
|
|
joystick_mappers[i].mapping[count] = value;
|
|
hid_debugf("parsed: %x/%x %d -> %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;i<MAX_VIRTUAL_JOYSTICK_REMAP;i++) {
|
|
if((joystick_mappers[i].vid == map->vid &&
|
|
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<MAX_VIRTUAL_JOYSTICK_REMAP;i++) {
|
|
if(joystick_mappers[i].vid == vid &&
|
|
joystick_mappers[i].pid == pid &&
|
|
joystick_mappers[i].tag >= 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<MAX_VIRTUAL_JOYSTICK_REMAP;i++) {
|
|
if(joystick_mappers[i].vid == vid &&
|
|
joystick_mappers[i].pid == pid &&
|
|
joystick_mappers[i].tag == newtag) {
|
|
|
|
new = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (new == -1) {
|
|
// no entry with the same tag, simply update
|
|
joystick_mappers[old].tag = newtag;
|
|
} else if (new != old) {
|
|
memcpy(&joystick_mappers[new].mapping, &joystick_mappers[old].mapping, 16*sizeof(uint16_t));
|
|
// delete the old entry
|
|
for(i = old; i<MAX_VIRTUAL_JOYSTICK_REMAP; i++) {
|
|
if (i==(MAX_VIRTUAL_JOYSTICK_REMAP-1)) {
|
|
memset(&joystick_mappers[i], 0, sizeof(joymapping_t));
|
|
} else {
|
|
memcpy(&joystick_mappers[i], &joystick_mappers[i+1].mapping, sizeof(joymapping_t));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
char* get_joystick_alias( uint16_t vid, uint16_t pid ) {
|
|
|
|
if(vid==0x0F30 && pid==0x1012)
|
|
return JOYSTICK_ALIAS_QANBA_Q4RAF;
|
|
|
|
if(vid==0x081F && pid==0xE401)
|
|
return JOYSTICK_ALIAS_CHEAP_SNES;
|
|
|
|
if(vid==0x0583 && pid==0x2060)
|
|
return JOYSTICK_ALIAS_IBUFALLO_SNES;
|
|
|
|
if(vid==0x0411 && pid==0x00C6)
|
|
return JOYSTICK_ALIAS_IBUFALLO_SNES;
|
|
|
|
if (vid==VID_RETROLINK && pid==0x0006)
|
|
return JOYSTICK_ALIAS_RETROLINK_GC;
|
|
|
|
if (vid==VID_RETROLINK && pid==0x0011)
|
|
return JOYSTICK_ALIAS_RETROLINK_NES;
|
|
|
|
if(vid==0x1F4F && pid==0x0003)
|
|
return JOYSTICK_ALIAS_ROYDS_EX;
|
|
|
|
if(vid==VID_DAPTOR && pid==0xF947)
|
|
return JOYSTICK_ALIAS_ATARI_DAPTOR2;
|
|
|
|
if(vid==VID_DAPTOR && pid==0xF421)
|
|
return JOYSTICK_ALIAS_NEOGEO_DAPTOR;
|
|
|
|
if(vid==VID_DAPTOR && pid==0xF6EC)
|
|
return JOYSTICK_ALIAS_NEOGEO_DAPTOR;
|
|
|
|
if(vid==VID_DAPTOR && pid==0xF672)
|
|
return JOYSTICK_ALIAS_VISION_DAPTOR;
|
|
|
|
if(vid==0x1345 && pid==0x1030)
|
|
return JOYSTICK_ALIAS_RETRO_FREAK;
|
|
|
|
if(vid==0x1235 && (pid==0xab11 || pid==0xab21))
|
|
return JOYSTICK_ALIAS_8BITDO_SFC30;
|
|
|
|
if(vid==0x1002 && pid==0x9000)
|
|
return JOYSTICK_ALIAS_8BITDO_FC30;
|
|
|
|
if(vid==0x040b && pid==0x6533)
|
|
return JOYSTICK_ALIAS_SPEEDLINK_COMP;
|
|
|
|
if(vid==0x0738 && pid==0x2217)
|
|
return JOYSTICK_ALIAS_SPEEDLINK_COMP;
|
|
|
|
if(vid==0x045E && pid==0x028E)
|
|
return JOYSTICK_ALIAS_XBOX;
|
|
|
|
if(vid==0x1C59 && pid==0x0026)
|
|
return JOYSTICK_ALIAS_RETRO_GAMES_THEGAMEPAD;
|
|
|
|
return JOYSTICK_ALIAS_NONE;
|
|
|
|
}
|
|
|
|
/* 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) {
|
|
|
|
uint8_t i;
|
|
|
|
// defines translations between physical buttons and virtual joysticks
|
|
uint16_t mapping[16];
|
|
// keep directions by default
|
|
for(i=0; i<4; i++)
|
|
mapping[i]=default_joystick_mapping[i];
|
|
// blank the rest
|
|
for(i=4; i<16; i++) mapping[i]=0;
|
|
|
|
uint8_t use_default=1;
|
|
uint8_t btn_off = 3; // start at three since array is 0 based, so 4 = button 1
|
|
|
|
// mapping for Qanba Q4RAF
|
|
if( vid==0x0F30 && pid==0x1012) {
|
|
mapping[btn_off+1] = JOY_A;
|
|
mapping[btn_off+2] = JOY_B;
|
|
mapping[btn_off+4] = JOY_A;
|
|
mapping[btn_off+3] = JOY_B;
|
|
mapping[btn_off+5] = JOY_X; //for jump
|
|
mapping[btn_off+6] = JOY_SELECT;
|
|
mapping[btn_off+8] = JOY_SELECT;
|
|
mapping[btn_off+10] = JOY_START;
|
|
use_default=0;
|
|
}
|
|
|
|
// mapping for no-brand cheap snes clone pad
|
|
if(vid==0x081F && pid==0xE401) {
|
|
mapping[btn_off+2] = JOY_A;
|
|
mapping[btn_off+3] = JOY_B;
|
|
mapping[btn_off+1] = JOY_B; // allow two ways to hold the controller
|
|
mapping[btn_off+4] = JOY_UP;
|
|
mapping[btn_off+5] = JOY_L | JOY_L2; // also bind to buttons for flippers
|
|
mapping[btn_off+6] = JOY_R | JOY_R2;
|
|
mapping[btn_off+9] = JOY_SELECT;
|
|
mapping[btn_off+10] = JOY_START;
|
|
use_default=0;
|
|
}
|
|
|
|
// mapping for iBuffalo SNES pad - BSGP801
|
|
if(vid==0x0583 && pid==0x2060) {
|
|
mapping[btn_off+1] = JOY_A;
|
|
mapping[btn_off+2] = JOY_B;
|
|
mapping[btn_off+3] = JOY_B; // allow two ways to hold the controller
|
|
mapping[btn_off+4] = JOY_UP;
|
|
mapping[btn_off+5] = JOY_L | JOY_L2; // also bind to buttons for flippers
|
|
mapping[btn_off+6] = JOY_R | JOY_R2;
|
|
mapping[btn_off+7] = JOY_SELECT;
|
|
mapping[btn_off+8] = JOY_START;
|
|
use_default=0;
|
|
}
|
|
|
|
//mapping for Buffalo NES pad - BGCFC801
|
|
if(vid==0x0411 && pid==0x00C6) {
|
|
mapping[btn_off+1] = JOY_A;
|
|
mapping[btn_off+2] = JOY_B;
|
|
mapping[btn_off+3] = JOY_B; // allow two ways to hold the controller
|
|
mapping[btn_off+4] = JOY_UP;
|
|
mapping[btn_off+5] = JOY_L | JOY_L2; // also bind to buttons for flippers
|
|
mapping[btn_off+6] = JOY_R | JOY_R2;
|
|
mapping[btn_off+7] = JOY_SELECT;
|
|
mapping[btn_off+8] = JOY_START;
|
|
use_default=0;
|
|
}
|
|
|
|
//mapping for RetroLink N64 and Gamecube pad (same vid/pid)
|
|
if(vid==VID_RETROLINK && pid==0x0006) {
|
|
mapping[btn_off+7] = JOY_A; // A on N64 pad
|
|
mapping[btn_off+9] = JOY_B; // B on N64 pad
|
|
mapping[btn_off+3] = JOY_A; // A on GC pad
|
|
mapping[btn_off+4] = JOY_B; // B on GC pad
|
|
mapping[btn_off+5] = JOY_L | JOY_SELECT;
|
|
mapping[btn_off+8] = JOY_L | JOY_SELECT; // Z button on N64 pad
|
|
mapping[btn_off+6] = JOY_R | JOY_SELECT;
|
|
mapping[btn_off+10] = JOY_START;
|
|
use_default=0;
|
|
}
|
|
|
|
//mapping for ROYDS Stick.EX
|
|
if(vid==0x1F4F && pid==0x0003) {
|
|
mapping[btn_off+3] = JOY_A; // Circle (usually select in PSx)
|
|
mapping[btn_off+1] = JOY_B; // Cross (usually cancel in PSx)
|
|
mapping[btn_off+2] = JOY_X; // Triangle
|
|
mapping[btn_off+4] = JOY_Y; // Square
|
|
mapping[btn_off+5] = JOY_L;
|
|
mapping[btn_off+6] = JOY_R;
|
|
mapping[btn_off+7] = JOY_L2;
|
|
mapping[btn_off+8] = JOY_R2;
|
|
mapping[btn_off+9] = JOY_SELECT;
|
|
mapping[btn_off+10] = JOY_START;
|
|
use_default=0;
|
|
}
|
|
|
|
//mapping for NEOGEO-daptor
|
|
if(vid==VID_DAPTOR && pid==0xF421) {
|
|
mapping[btn_off+1] = JOY_B; // red button "A" on pad (inverted order with NES/SNES
|
|
mapping[btn_off+2] = JOY_A; // yellow button "B" on pad (inverted order with NES/SNES
|
|
mapping[btn_off+3] = JOY_Y | JOY_L; // green button, "C" on pad (mapped to Y and L in SNES convention)
|
|
mapping[btn_off+4] = JOY_X | JOY_R; // blue button "D"
|
|
mapping[btn_off+5] = JOY_START;
|
|
mapping[btn_off+6] = JOY_SELECT;
|
|
use_default=0;
|
|
}
|
|
|
|
//mapping for 8bitdo SFC30
|
|
if(vid==0x1235 && (pid==0xab11 || pid==0xab21)) {
|
|
mapping[btn_off+1] = JOY_A;
|
|
mapping[btn_off+2] = JOY_B;
|
|
//mapping[btn_off+3] // physical button #3 not used
|
|
mapping[btn_off+4] = JOY_X;
|
|
mapping[btn_off+5] = JOY_Y;
|
|
//mapping[btn_off+6] // physical button #6 not used
|
|
mapping[btn_off+7] = JOY_L | JOY_L2; // also bind to buttons for flippers
|
|
mapping[btn_off+8] = JOY_R | JOY_R2; // also bind to buttons for flippers
|
|
//9 and 10 not used
|
|
mapping[btn_off+11] = JOY_SELECT;
|
|
mapping[btn_off+12] = JOY_START;
|
|
use_default=0;
|
|
}
|
|
|
|
//mapping for 8bitdo FC30
|
|
if(vid==0x1002 && pid==0x9000) {
|
|
mapping[btn_off+1] = JOY_A;
|
|
mapping[btn_off+2] = JOY_B;
|
|
//mapping[btn_off+3] // physical button #3 not used
|
|
mapping[btn_off+4] = JOY_X;
|
|
mapping[btn_off+5] = JOY_Y;
|
|
//mapping[btn_off+6] // physical button #6 not used
|
|
mapping[btn_off+7] = JOY_L | JOY_L2; // also bind to buttons for flippers
|
|
mapping[btn_off+8] = JOY_R | JOY_R2; // also bind to buttons for flippers
|
|
mapping[btn_off+9] = JOY_L | JOY_L2; // also bind to buttons for flippers
|
|
mapping[btn_off+10] = JOY_R | JOY_R2; // also bind to buttons for flippers
|
|
mapping[btn_off+11] = JOY_SELECT;
|
|
mapping[btn_off+12] = JOY_START;
|
|
use_default=0;
|
|
}
|
|
|
|
// Apply remap information from various config sources if present
|
|
// Priority (low to high):
|
|
// 0 - mist.ini
|
|
// 1 - mistcfg.ini
|
|
// 2 - [corename].cfg
|
|
uint8_t j;
|
|
int tag = 0;
|
|
for(j=0;j<MAX_VIRTUAL_JOYSTICK_REMAP;j++) {
|
|
if(joystick_mappers[j].vid==vid && joystick_mappers[j].pid==pid && joystick_mappers[j].tag >= 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<<i)) vjoy |= mapping[i];
|
|
|
|
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));
|
|
}
|
|
|
|
|
|
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;i<MAX_JOYSTICK_KEYBOARD_MAP;i++) {
|
|
// fill sequentially the available mapping slots, stopping at first empty one
|
|
if(!joy_key_map[i].mask) {
|
|
joy_key_map[i].modifier = 0;
|
|
for(j=0;j<6;j++)
|
|
joy_key_map[i].keys[j] = 0;
|
|
count = 0;
|
|
token = strtok (s, ",");
|
|
while(s) {
|
|
if (count==0) {
|
|
joy_key_map[i].mask = strtol(s, NULL, 16);
|
|
} else {
|
|
scancode = strtol(s, NULL, 16);
|
|
// set as modifier if scancode is on the relevant range (224 to 231)
|
|
if(scancode>223) {
|
|
// 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<MAX_JOYSTICK_KEYBOARD_MAP;i++) {
|
|
if(vjoy & joy_key_map[i].mask) {
|
|
has_mapping = 1;
|
|
//iprintf("joy2key:%d\n", joy_key_map[i].mask);
|
|
if (joy_key_map[i].modifier) {
|
|
modifier |= joy_key_map[i].modifier;
|
|
mapped_hit=1;
|
|
//iprintf("joy2key hit (modifier):%d\n", joy_key_map[i].modifier);
|
|
}
|
|
// only override up to 6 keys,
|
|
// and preserve overrides from further up this function
|
|
k = 0;
|
|
for (j=0; j<6; j++) {
|
|
if(buf[j]!=0) k=j+1; //next index to assign
|
|
}
|
|
for (j=0; j<6; j++) {
|
|
if (k>=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);
|
|
}
|