/*
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);
}