diff options
Diffstat (limited to 'pcr/reicast-multilib-git/generalize-mappings.patch')
-rw-r--r-- | pcr/reicast-multilib-git/generalize-mappings.patch | 1979 |
1 files changed, 1979 insertions, 0 deletions
diff --git a/pcr/reicast-multilib-git/generalize-mappings.patch b/pcr/reicast-multilib-git/generalize-mappings.patch new file mode 100644 index 000000000..a47681f39 --- /dev/null +++ b/pcr/reicast-multilib-git/generalize-mappings.patch @@ -0,0 +1,1979 @@ +diff -Nur a/core/linux-dist/bimap.h b/core/linux-dist/bimap.h +--- a/core/linux-dist/bimap.h 1969-12-31 21:00:00.000000000 -0300 ++++ b/core/linux-dist/bimap.h 2015-10-06 21:55:43.966475140 -0300 +@@ -0,0 +1,67 @@ ++/* SimpleBimap ++ * ++ * A basic implementation of a bidirectional map that not only allows ++ * you to get a mapped value from a key, but also the other way around. ++ * Deleting elements and other fancy (and not-so-fancy) stuff is not ++ * supported. ++ * ++ * Usage example: ++ * SimpleBimap<std::string, std::string> bimap; ++ * bimap.insert("foo", "bar"); ++ * printf("foo -> %s\n", bimap.get_by_key("foo")->c_str()); ++ * printf("bar <- %s\n", bimap.get_by_value("bar")->c_str()); ++ * if(bimap.get_by_key("somekey") == NULL) ++ * puts("somekey not found"); ++ * ++ * The above example's output: ++ * foo -> bar ++ * bar <- foo ++ * somekey not found ++ */ ++#include <cstddef> ++#include <utility> ++#include <map> ++ ++template<typename T1, typename T2> ++class SimpleBimap ++{ ++ private: ++ typedef typename std::map<T2, T1*> MapA; ++ typedef typename std::map<T1, T2*> MapB; ++ MapA map_a; ++ MapB map_b; ++ public: ++ void insert(const T1& a, const T2& b) ++ { ++ // create first pair ++ typename MapA::iterator iter_a = map_a.insert(std::pair<T2, T1*>(b, NULL)).first; ++ T2* ptr_b = const_cast<T2*>(&(iter_a->first)); ++ ++ // insert second pair (a, pointer_to_b) ++ typename MapB::iterator iter_b = map_b.insert(std::pair<T1, T2*>(a, ptr_b)).first; ++ ++ // update pointer in map_a to point to a ++ T1* ptr_a = const_cast<T1*>(&(iter_b->first)); ++ iter_a->second = ptr_a; ++ } ++ ++ const T2* get_by_key(const T1 &a) ++ { ++ typename MapB::iterator it = this->map_b.find(a); ++ if(it != this->map_b.end()) ++ { ++ return (it->second); ++ } ++ return NULL; ++ } ++ ++ const T1* get_by_value(const T2 &b) ++ { ++ typename MapA::iterator it = this->map_a.find(b); ++ if(it != this->map_a.end()) ++ { ++ return (it->second); ++ } ++ return NULL; ++ } ++}; +\ No newline at end of file +diff -Nur a/core/linux-dist/evdev.cpp b/core/linux-dist/evdev.cpp +--- a/core/linux-dist/evdev.cpp 2015-10-06 21:43:53.042336401 -0300 ++++ b/core/linux-dist/evdev.cpp 1969-12-31 21:00:00.000000000 -0300 +@@ -1,450 +0,0 @@ +-#include <unistd.h> +-#include <fcntl.h> +-#include <linux/input.h> +-#include "linux-dist/evdev.h" +-#include "linux-dist/main.h" +-#include "cfg/ini.h" +-#include <vector> +-#include <map> +-#include <dlfcn.h> +- +-#if defined(USE_EVDEV) +- bool libevdev_tried = false; +- bool libevdev_available = false; +- typedef int (*libevdev_func1_t)(int, const char*); +- typedef const char* (*libevdev_func2_t)(int, int); +- libevdev_func1_t libevdev_event_code_from_name; +- libevdev_func2_t libevdev_event_code_get_name; +- +- void load_libevdev() +- { +- if (libevdev_tried) +- { +- return; +- } +- +- libevdev_tried = true; +- void* lib_handle = dlopen("libevdev.so", RTLD_NOW); +- +- bool failed = false; +- +- if (!lib_handle) +- { +- fprintf(stderr, "%s\n", dlerror()); +- failed = true; +- } +- else +- { +- libevdev_event_code_from_name = reinterpret_cast<libevdev_func1_t>(dlsym(lib_handle, "libevdev_event_code_from_name")); +- +- const char* error1 = dlerror(); +- if (error1 != NULL) +- { +- fprintf(stderr, "%s\n", error1); +- failed = true; +- } +- +- libevdev_event_code_get_name = reinterpret_cast<libevdev_func2_t>(dlsym(lib_handle, "libevdev_event_code_get_name")); +- +- const char* error2 = dlerror(); +- if (error2 != NULL) +- { +- fprintf(stderr, "%s\n", error2); +- failed = true; +- } +- } +- +- if(failed) +- { +- puts("WARNING: libevdev is not available. You'll not be able to use button names instead of numeric codes in your controller mappings!\n"); +- return; +- } +- +- libevdev_available = true; +- } +- +- s8 EvdevAxisData::convert(s32 value) +- { +- return (((value - min) * 255) / range); +- } +- +- void EvdevAxisData::init(int fd, int code, bool inverted) +- { +- struct input_absinfo abs; +- if(code < 0 || ioctl(fd, EVIOCGABS(code), &abs)) +- { +- if(code >= 0) +- { +- perror("evdev ioctl"); +- } +- this->range = 255; +- this->min = 0; +- return; +- } +- s32 min = abs.minimum; +- s32 max = abs.maximum; +- printf("evdev: range of axis %d is from %d to %d\n", code, min, max); +- if(inverted) +- { +- this->range = (min - max); +- this->min = max; +- } +- else +- { +- this->range = (max - min); +- this->min = min; +- } +- } +- +- void EvdevController::init() +- { +- this->data_x.init(this->fd, this->mapping->Axis_Analog_X, this->mapping->Axis_Analog_X_Inverted); +- this->data_y.init(this->fd, this->mapping->Axis_Analog_Y, this->mapping->Axis_Analog_Y_Inverted); +- this->data_trigger_left.init(this->fd, this->mapping->Axis_Trigger_Left, this->mapping->Axis_Trigger_Left_Inverted); +- this->data_trigger_right.init(this->fd, this->mapping->Axis_Trigger_Right, this->mapping->Axis_Trigger_Right_Inverted); +- } +- +- std::map<std::string, EvdevControllerMapping> loaded_mappings; +- +- int load_keycode(ConfigFile* cfg, string section, string dc_key) +- { +- int code = -1; +- +- string keycode = cfg->get(section, dc_key, "-1"); +- if (strstr(keycode.c_str(), "KEY_") != NULL || +- strstr(keycode.c_str(), "BTN_") != NULL || +- strstr(keycode.c_str(), "ABS_") != NULL) +- { +- if(libevdev_available) +- { +- int type = ((strstr(keycode.c_str(), "ABS_") != NULL) ? EV_ABS : EV_KEY); +- code = libevdev_event_code_from_name(type, keycode.c_str()); +- } +- if(code < 0) +- { +- printf("evdev: failed to find keycode for '%s'\n", keycode.c_str()); +- } +- else +- { +- printf("%s = %s (%d)\n", dc_key.c_str(), keycode.c_str(), code); +- } +- return code; +- } +- +- code = cfg->get_int(section, dc_key, -1); +- if(code >= 0) +- { +- char* name = NULL; +- if(libevdev_available) +- { +- int type = ((strstr(dc_key.c_str(), "axis_") != NULL) ? EV_ABS : EV_KEY); +- name = (char*)libevdev_event_code_get_name(type, code); +- } +- if (name != NULL) +- { +- printf("%s = %s (%d)\n", dc_key.c_str(), name, code); +- } +- else +- { +- printf("%s = %d\n", dc_key.c_str(), code); +- } +- } +- return code; +- } +- +- EvdevControllerMapping load_mapping(FILE* fd) +- { +- ConfigFile mf; +- mf.parse(fd); +- +- EvdevControllerMapping mapping = { +- mf.get("emulator", "mapping_name", "<Unknown>").c_str(), +- load_keycode(&mf, "dreamcast", "btn_a"), +- load_keycode(&mf, "dreamcast", "btn_b"), +- load_keycode(&mf, "dreamcast", "btn_c"), +- load_keycode(&mf, "dreamcast", "btn_d"), +- load_keycode(&mf, "dreamcast", "btn_x"), +- load_keycode(&mf, "dreamcast", "btn_y"), +- load_keycode(&mf, "dreamcast", "btn_z"), +- load_keycode(&mf, "dreamcast", "btn_start"), +- load_keycode(&mf, "emulator", "btn_escape"), +- load_keycode(&mf, "dreamcast", "btn_dpad1_left"), +- load_keycode(&mf, "dreamcast", "btn_dpad1_right"), +- load_keycode(&mf, "dreamcast", "btn_dpad1_up"), +- load_keycode(&mf, "dreamcast", "btn_dpad1_down"), +- load_keycode(&mf, "dreamcast", "btn_dpad2_left"), +- load_keycode(&mf, "dreamcast", "btn_dpad2_right"), +- load_keycode(&mf, "dreamcast", "btn_dpad2_up"), +- load_keycode(&mf, "dreamcast", "btn_dpad2_down"), +- load_keycode(&mf, "compat", "btn_trigger_left"), +- load_keycode(&mf, "compat", "btn_trigger_right"), +- load_keycode(&mf, "compat", "axis_dpad1_x"), +- load_keycode(&mf, "compat", "axis_dpad1_y"), +- load_keycode(&mf, "compat", "axis_dpad2_x"), +- load_keycode(&mf, "compat", "axis_dpad2_y"), +- load_keycode(&mf, "dreamcast", "axis_x"), +- load_keycode(&mf, "dreamcast", "axis_y"), +- load_keycode(&mf, "dreamcast", "axis_trigger_left"), +- load_keycode(&mf, "dreamcast", "axis_trigger_right"), +- mf.get_bool("compat", "axis_x_inverted", false), +- mf.get_bool("compat", "axis_y_inverted", false), +- mf.get_bool("compat", "axis_trigger_left_inverted", false), +- mf.get_bool("compat", "axis_trigger_right_inverted", false) +- }; +- return mapping; +- } +- +- int input_evdev_init(EvdevController* controller, const char* device, const char* custom_mapping_fname = NULL) +- { +- load_libevdev(); +- +- char name[256] = "Unknown"; +- +- printf("evdev: Trying to open device at '%s'\n", device); +- +- int fd = open(device, O_RDONLY); +- +- if (fd >= 0) +- { +- fcntl(fd, F_SETFL, O_NONBLOCK); +- if(ioctl(fd, EVIOCGNAME(sizeof(name)), name) < 0) +- { +- perror("evdev: ioctl"); +- return -2; +- } +- else +- { +- printf("evdev: Found '%s' at '%s'\n", name, device); +- +- controller->fd = fd; +- +- const char* mapping_fname; +- +- if(custom_mapping_fname != NULL) +- { +- mapping_fname = custom_mapping_fname; +- } +- else +- { +- #if defined(TARGET_PANDORA) +- mapping_fname = "controller_pandora.cfg"; +- #elif defined(TARGET_GCW0) +- mapping_fname = "controller_gcwz.cfg"; +- #else +- if (strcmp(name, "Microsoft X-Box 360 pad") == 0 || +- strcmp(name, "Xbox 360 Wireless Receiver") == 0 || +- strcmp(name, "Xbox 360 Wireless Receiver (XBOX)") == 0) +- { +- mapping_fname = "controller_xpad.cfg"; +- } +- else if (strstr(name, "Xbox Gamepad (userspace driver)") != NULL) +- { +- mapping_fname = "controller_xboxdrv.cfg"; +- } +- else if (strstr(name, "keyboard") != NULL || +- strstr(name, "Keyboard") != NULL) +- { +- mapping_fname = "keyboard.cfg"; +- } +- else +- { +- mapping_fname = "controller_generic.cfg"; +- } +- #endif +- } +- if(loaded_mappings.count(string(mapping_fname)) == 0) +- { +- FILE* mapping_fd = NULL; +- if(mapping_fname[0] == '/') +- { +- // Absolute mapping +- mapping_fd = fopen(mapping_fname, "r"); +- } +- else +- { +- // Mapping from ~/.reicast/mappings/ +- size_t size_needed = snprintf(NULL, 0, EVDEV_MAPPING_PATH, mapping_fname) + 1; +- char* mapping_path = (char*)malloc(size_needed); +- sprintf(mapping_path, EVDEV_MAPPING_PATH, mapping_fname); +- mapping_fd = fopen(get_readonly_data_path(mapping_path).c_str(), "r"); +- free(mapping_path); +- } +- +- if(mapping_fd != NULL) +- { +- printf("evdev: reading mapping file: '%s'\n", mapping_fname); +- loaded_mappings.insert(std::make_pair(string(mapping_fname), load_mapping(mapping_fd))); +- fclose(mapping_fd); +- +- } +- else +- { +- printf("evdev: unable to open mapping file '%s'\n", mapping_fname); +- perror("evdev"); +- return -3; +- } +- } +- controller->mapping = &loaded_mappings[string(mapping_fname)]; +- printf("evdev: Using '%s' mapping\n", controller->mapping->name); +- controller->init(); +- +- return 0; +- } +- } +- else +- { +- perror("evdev: open"); +- return -1; +- } +- } +- +- bool input_evdev_handle(EvdevController* controller, u32 port) +- { +- #define SET_FLAG(field, mask, expr) field =((expr) ? (field & ~mask) : (field | mask)) +- if (controller->fd < 0 || controller->mapping == NULL) +- { +- return false; +- } +- +- input_event ie; +- +- while(read(controller->fd, &ie, sizeof(ie)) == sizeof(ie)) +- { +- switch(ie.type) +- { +- case EV_KEY: +- if (ie.code == controller->mapping->Btn_A) { +- SET_FLAG(kcode[port], DC_BTN_A, ie.value); +- } else if (ie.code == controller->mapping->Btn_B) { +- SET_FLAG(kcode[port], DC_BTN_B, ie.value); +- } else if (ie.code == controller->mapping->Btn_C) { +- SET_FLAG(kcode[port], DC_BTN_C, ie.value); +- } else if (ie.code == controller->mapping->Btn_D) { +- SET_FLAG(kcode[port], DC_BTN_D, ie.value); +- } else if (ie.code == controller->mapping->Btn_X) { +- SET_FLAG(kcode[port], DC_BTN_X, ie.value); +- } else if (ie.code == controller->mapping->Btn_Y) { +- SET_FLAG(kcode[port], DC_BTN_Y, ie.value); +- } else if (ie.code == controller->mapping->Btn_Z) { +- SET_FLAG(kcode[port], DC_BTN_Z, ie.value); +- } else if (ie.code == controller->mapping->Btn_Start) { +- SET_FLAG(kcode[port], DC_BTN_START, ie.value); +- } else if (ie.code == controller->mapping->Btn_Escape) { +- die("death by escape key"); +- } else if (ie.code == controller->mapping->Btn_DPad_Left) { +- SET_FLAG(kcode[port], DC_DPAD_LEFT, ie.value); +- } else if (ie.code == controller->mapping->Btn_DPad_Right) { +- SET_FLAG(kcode[port], DC_DPAD_RIGHT, ie.value); +- } else if (ie.code == controller->mapping->Btn_DPad_Up) { +- SET_FLAG(kcode[port], DC_DPAD_UP, ie.value); +- } else if (ie.code == controller->mapping->Btn_DPad_Down) { +- SET_FLAG(kcode[port], DC_DPAD_DOWN, ie.value); +- } else if (ie.code == controller->mapping->Btn_DPad2_Left) { +- SET_FLAG(kcode[port], DC_DPAD2_LEFT, ie.value); +- } else if (ie.code == controller->mapping->Btn_DPad2_Right) { +- SET_FLAG(kcode[port], DC_DPAD2_RIGHT, ie.value); +- } else if (ie.code == controller->mapping->Btn_DPad2_Up) { +- SET_FLAG(kcode[port], DC_DPAD2_UP, ie.value); +- } else if (ie.code == controller->mapping->Btn_DPad2_Down) { +- SET_FLAG(kcode[port], DC_DPAD2_DOWN, ie.value); +- } else if (ie.code == controller->mapping->Btn_Trigger_Left) { +- lt[port] = (ie.value ? 255 : 0); +- } else if (ie.code == controller->mapping->Btn_Trigger_Right) { +- rt[port] = (ie.value ? 255 : 0); +- } +- break; +- case EV_ABS: +- if (ie.code == controller->mapping->Axis_DPad_X) +- { +- switch(ie.value) +- { +- case -1: +- SET_FLAG(kcode[port], DC_DPAD_LEFT, 1); +- SET_FLAG(kcode[port], DC_DPAD_RIGHT, 0); +- break; +- case 0: +- SET_FLAG(kcode[port], DC_DPAD_LEFT, 0); +- SET_FLAG(kcode[port], DC_DPAD_RIGHT, 0); +- break; +- case 1: +- SET_FLAG(kcode[port], DC_DPAD_LEFT, 0); +- SET_FLAG(kcode[port], DC_DPAD_RIGHT, 1); +- break; +- } +- } +- else if (ie.code == controller->mapping->Axis_DPad_Y) +- { +- switch(ie.value) +- { +- case -1: +- SET_FLAG(kcode[port], DC_DPAD_UP, 1); +- SET_FLAG(kcode[port], DC_DPAD_DOWN, 0); +- break; +- case 0: +- SET_FLAG(kcode[port], DC_DPAD_UP, 0); +- SET_FLAG(kcode[port], DC_DPAD_DOWN, 0); +- break; +- case 1: +- SET_FLAG(kcode[port], DC_DPAD_UP, 0); +- SET_FLAG(kcode[port], DC_DPAD_DOWN, 1); +- break; +- } +- } +- else if (ie.code == controller->mapping->Axis_DPad2_X) +- { +- switch(ie.value) +- { +- case -1: +- SET_FLAG(kcode[port], DC_DPAD2_LEFT, 1); +- SET_FLAG(kcode[port], DC_DPAD2_RIGHT, 0); +- break; +- case 0: +- SET_FLAG(kcode[port], DC_DPAD2_LEFT, 0); +- SET_FLAG(kcode[port], DC_DPAD2_RIGHT, 0); +- break; +- case 1: +- SET_FLAG(kcode[port], DC_DPAD2_LEFT, 0); +- SET_FLAG(kcode[port], DC_DPAD2_RIGHT, 1); +- break; +- } +- } +- else if (ie.code == controller->mapping->Axis_DPad2_X) +- { +- switch(ie.value) +- { +- case -1: +- SET_FLAG(kcode[port], DC_DPAD2_UP, 1); +- SET_FLAG(kcode[port], DC_DPAD2_DOWN, 0); +- break; +- case 0: +- SET_FLAG(kcode[port], DC_DPAD2_UP, 0); +- SET_FLAG(kcode[port], DC_DPAD2_DOWN, 0); +- break; +- case 1: +- SET_FLAG(kcode[port], DC_DPAD2_UP, 0); +- SET_FLAG(kcode[port], DC_DPAD2_DOWN, 1); +- break; +- } +- } +- else if (ie.code == controller->mapping->Axis_Analog_X) +- { +- joyx[port] = (controller->data_x.convert(ie.value) + 128); +- } +- else if (ie.code == controller->mapping->Axis_Analog_Y) +- { +- joyy[port] = (controller->data_y.convert(ie.value) + 128); +- } +- else if (ie.code == controller->mapping->Axis_Trigger_Left) +- { +- lt[port] = controller->data_trigger_left.convert(ie.value); +- } +- else if (ie.code == controller->mapping->Axis_Trigger_Right) +- { +- rt[port] = controller->data_trigger_right.convert(ie.value); +- } +- break; +- } +- } +- } +-#endif +- +diff -Nur a/core/linux-dist/evdev.h b/core/linux-dist/evdev.h +--- a/core/linux-dist/evdev.h 2015-10-06 21:43:53.042336401 -0300 ++++ b/core/linux-dist/evdev.h 1969-12-31 21:00:00.000000000 -0300 +@@ -1,74 +0,0 @@ +-#pragma once +-#include <linux/input.h> +-#include "types.h" +- +-struct EvdevControllerMapping +-{ +- const char* name; +- const int Btn_A; +- const int Btn_B; +- const int Btn_C; +- const int Btn_D; +- const int Btn_X; +- const int Btn_Y; +- const int Btn_Z; +- const int Btn_Start; +- const int Btn_Escape; +- const int Btn_DPad_Left; +- const int Btn_DPad_Right; +- const int Btn_DPad_Up; +- const int Btn_DPad_Down; +- const int Btn_DPad2_Left; +- const int Btn_DPad2_Right; +- const int Btn_DPad2_Up; +- const int Btn_DPad2_Down; +- const int Btn_Trigger_Left; +- const int Btn_Trigger_Right; +- const int Axis_DPad_X; +- const int Axis_DPad_Y; +- const int Axis_DPad2_X; +- const int Axis_DPad2_Y; +- const int Axis_Analog_X; +- const int Axis_Analog_Y; +- const int Axis_Trigger_Left; +- const int Axis_Trigger_Right; +- const bool Axis_Analog_X_Inverted; +- const bool Axis_Analog_Y_Inverted; +- const bool Axis_Trigger_Left_Inverted; +- const bool Axis_Trigger_Right_Inverted; +-}; +- +-struct EvdevAxisData +-{ +- s32 range; // smaller size than 32 bit might cause integer overflows +- s32 min; +- void init(int fd, int code, bool inverted); +- s8 convert(int value); +-}; +- +-struct EvdevController +-{ +- int fd; +- EvdevControllerMapping* mapping; +- EvdevAxisData data_x; +- EvdevAxisData data_y; +- EvdevAxisData data_trigger_left; +- EvdevAxisData data_trigger_right; +- void init(); +-}; +- +-#define EVDEV_DEVICE_CONFIG_KEY "evdev_device_id_%d" +-#define EVDEV_MAPPING_CONFIG_KEY "evdev_mapping_%d" +-#define EVDEV_DEVICE_STRING "/dev/input/event%d" +-#define EVDEV_MAPPING_PATH "/mappings/%s" +- +-#ifdef TARGET_PANDORA +- #define EVDEV_DEFAULT_DEVICE_ID_1 4 +-#else +- #define EVDEV_DEFAULT_DEVICE_ID_1 0 +-#endif +- +-#define EVDEV_DEFAULT_DEVICE_ID(port) (port == 1 ? EVDEV_DEFAULT_DEVICE_ID_1 : -1) +- +-extern int input_evdev_init(EvdevController* controller, const char* device, const char* mapping_fname); +-extern bool input_evdev_handle(EvdevController* controller, u32 port); +diff -Nur a/core/linux-dist/handler.cpp b/core/linux-dist/handler.cpp +--- a/core/linux-dist/handler.cpp 1969-12-31 21:00:00.000000000 -0300 ++++ b/core/linux-dist/handler.cpp 2015-10-06 21:55:43.966475140 -0300 +@@ -0,0 +1,263 @@ ++#include "handler.h" ++ ++#define SET_FLAG(field, mask, expr) field =((expr) ? (field & ~mask) : (field | mask)) ++static InputAxisID axis_ids[] = { DC_AXIS_X, DC_AXIS_Y, DC_AXIS_TRIGGER_LEFT, DC_AXIS_TRIGGER_RIGHT, EMU_AXIS_DPAD1_X, EMU_AXIS_DPAD1_Y, EMU_AXIS_DPAD2_X, EMU_AXIS_DPAD2_Y }; ++ ++InputAxisConverter::InputAxisConverter(bool inverted, InputAxisLimits limits) ++{ ++ this->m_deadzone = limits.deadzone; ++ if(inverted) ++ { ++ this->m_range = (limits.minimum - limits.maximum); ++ this->m_minimum = limits.maximum; ++ } ++ else ++ { ++ this->m_range = (limits.maximum - limits.minimum); ++ this->m_minimum = limits.minimum; ++ } ++} ++ ++s8 InputAxisConverter::convert(s32 value) ++{ ++ // If value is in deadzone, return 0 ++ if (this->m_deadzone && ((value >= 0 && value <= this->m_deadzone) || (value < 0 && value >= -this->m_deadzone))) ++ { ++ return 0; ++ } ++ if (this->m_range) ++ { ++ return (((value - this->m_minimum) * 255) / this->m_range); ++ } ++ return value; ++} ++ ++InputMappingStore InputHandler::s_mappingstore; ++ ++ ++InputHandler::InputHandler() ++{ ++ this->m_initialized = false; ++} ++ ++InputHandler::~InputHandler() ++{ ++ //TODO; ++} ++ ++bool InputHandler::initialize(u32 port, std::string device, std::string custom_mapping_filename) ++{ ++ if(this->m_initialized) ++ { ++ printf("%s: Handler is already initialized!\n", this->get_api_name().c_str()); ++ return true; ++ } ++ ++ this->m_port = port; ++ ++ bool success = this->setup_device(device); ++ ++ if(!success) ++ { ++ printf("%s: Initialization of device '%s' failed!\n", this->get_api_name().c_str(), device.c_str()); ++ return false; ++ } ++ ++ if(custom_mapping_filename.empty()) ++ { ++ this->m_mapping = NULL; ++ } ++ else ++ { ++ this->m_mapping = InputHandler::s_mappingstore.get(custom_mapping_filename, this->get_api_name()); ++ } ++ ++ if(this->m_mapping == NULL) ++ { ++ if(!custom_mapping_filename.empty()) ++ { ++ printf("%s: Loading custom mapping '%s' failed!\n", this->get_api_name().c_str(), custom_mapping_filename.c_str()); ++ } ++ std::string default_mapping_filename = this->get_default_mapping_filename(); ++ if(default_mapping_filename.empty()) ++ { ++ printf("%s: No default mapping available!\n", this->get_api_name().c_str()); ++ } ++ else ++ { ++ printf("%s: Using default mapping '%s'.\n", this->get_api_name().c_str(), default_mapping_filename.c_str()); ++ this->m_mapping = InputHandler::s_mappingstore.get(default_mapping_filename, this->get_api_name()); ++ } ++ } ++ ++ ++ if(this->m_mapping == NULL) ++ { ++ printf("%s: Couldn't load a mapping!\n", this->get_api_name().c_str()); ++ return false; ++ } ++ ++ for(int i = 0; i < 8; i++) ++ { ++ InputAxisID id = axis_ids[i]; ++ const InputAxisCode* code = this->m_mapping->get_axis_code(id); ++ if(code != NULL) ++ { ++ InputAxisLimits limits; ++ this->get_axis_limits(*code, limits); ++ if(limits.minimum != limits.maximum) ++ { ++ bool inverted = this->m_mapping->get_axis_inverted(*code); ++ this->enable_axis_converter(id, inverted, limits); ++ } ++ } ++ } ++ this->m_initialized = true; ++ return true; ++} ++ ++bool InputHandler::is_initialized() ++{ ++ return this->m_initialized; ++} ++ ++std::string InputHandler::get_default_mapping_filename() ++{ ++ return "default.cfg"; ++} ++ ++void InputHandler::get_axis_limits(const InputAxisCode code, InputAxisLimits& limits) ++{ ++ // Default stub, can be overridden in subclasses ++ limits.minimum = 0; ++ limits.maximum = 0; ++ limits.deadzone = 0; ++} ++ ++void InputHandler::handle_button(InputButtonCode code, int value) ++{ ++ if(this->m_mapping == NULL) ++ { ++ return; ++ } ++ const InputButtonID* button_id = this->m_mapping->get_button_id(code); ++ if(button_id == NULL) ++ { ++ printf("Ignoring %d (%d)\n", code, button_id); ++ return; ++ } ++ switch(*button_id) ++ { ++ case EMU_BTN_ESCAPE: ++ if(value) ++ { ++ die("death by escape key"); ++ } ++ break; ++ case EMU_BTN_TRIGGER_LEFT: ++ lt[this->m_port] = (value ? 255 : 0); ++ break; ++ case EMU_BTN_TRIGGER_RIGHT: ++ rt[this->m_port] = (value ? 255 : 0); ++ break; ++ default: ++ SET_FLAG(kcode[this->m_port], *button_id, value); ++ }; ++} ++ ++void InputHandler::handle_axis(InputAxisCode code, int value) ++{ ++ if(this->m_mapping == NULL) ++ { ++ return; ++ } ++ const InputAxisID* axis_id = this->m_mapping->get_axis_id(code); ++ if(axis_id == NULL) ++ { ++ printf("Ignoring %d\n", code); ++ return; ++ } ++ switch(*axis_id) ++ { ++ case EMU_AXIS_DPAD1_X: ++ case EMU_AXIS_DPAD1_Y: ++ case EMU_AXIS_DPAD2_X: ++ case EMU_AXIS_DPAD2_Y: ++ { ++ InputButtonID axis_button_id[2]; ++ switch(*axis_id) ++ { ++ case EMU_AXIS_DPAD1_X: ++ axis_button_id[0] = DC_BTN_DPAD1_LEFT; ++ axis_button_id[1] = DC_BTN_DPAD1_RIGHT; ++ break; ++ case EMU_AXIS_DPAD1_Y: ++ axis_button_id[0] = DC_BTN_DPAD1_UP; ++ axis_button_id[1] = DC_BTN_DPAD1_DOWN; ++ break; ++ case EMU_AXIS_DPAD2_X: ++ axis_button_id[0] = DC_BTN_DPAD2_LEFT; ++ axis_button_id[1] = DC_BTN_DPAD2_RIGHT; ++ break; ++ case EMU_AXIS_DPAD2_Y: ++ axis_button_id[0] = DC_BTN_DPAD2_UP; ++ axis_button_id[1] = DC_BTN_DPAD2_DOWN; ++ } ++ bool axis_button_value[2]; ++ axis_button_value[0] = (value < 0); ++ axis_button_value[1] = (value > 0); ++ SET_FLAG(kcode[this->m_port], axis_button_id[0], axis_button_value[0]); ++ SET_FLAG(kcode[this->m_port], axis_button_id[1], axis_button_value[1]); ++ break; ++ } ++ case DC_AXIS_X: ++ case DC_AXIS_Y: ++ case DC_AXIS_TRIGGER_LEFT: ++ case DC_AXIS_TRIGGER_RIGHT: ++ { ++ InputAxisConverter* converter = this->get_axis_converter(*axis_id); ++ s8 converted_value = ((converter == NULL) ? value : converter->convert(value)); ++ switch(*axis_id) ++ { ++ case DC_AXIS_X: ++ joyx[this->m_port] = (converted_value + 128); ++ break; ++ case DC_AXIS_Y: ++ joyy[this->m_port] = (converted_value + 128); ++ break; ++ case DC_AXIS_TRIGGER_LEFT: ++ lt[this->m_port] = converted_value; ++ break; ++ case DC_AXIS_TRIGGER_RIGHT: ++ rt[this->m_port] = converted_value; ++ break; ++ } ++ } ++ } ++} ++ ++void InputHandler::enable_axis_converter(InputAxisID axis, bool inverted, InputAxisLimits limits) ++{ ++ this->disable_axis_converter(axis); // Delete old axis converter ++ this->m_axis_converters[axis] = new InputAxisConverter(inverted, limits); ++} ++ ++void InputHandler::disable_axis_converter(InputAxisID axis) ++{ ++ InputAxisConverterStore::iterator iter = this->m_axis_converters.find(axis); ++ if(iter != this->m_axis_converters.end()) ++ { ++ delete iter->second; ++ this->m_axis_converters.erase(iter); ++ } ++} ++ ++InputAxisConverter* InputHandler::get_axis_converter(InputAxisID axis) ++{ ++ InputAxisConverterStore::iterator iter = this->m_axis_converters.find(axis); ++ if(iter == this->m_axis_converters.end()) ++ { ++ return NULL; ++ } ++ return iter->second; ++} +\ No newline at end of file +diff -Nur a/core/linux-dist/handler_evdev.cpp b/core/linux-dist/handler_evdev.cpp +--- a/core/linux-dist/handler_evdev.cpp 1969-12-31 21:00:00.000000000 -0300 ++++ b/core/linux-dist/handler_evdev.cpp 2015-10-06 21:55:43.966475140 -0300 +@@ -0,0 +1,132 @@ ++#if defined(USE_EVDEV) ++#include "handler_evdev.h" ++#include <cstring> ++#include <cerrno> ++#include <fcntl.h> ++#include <unistd.h> ++#include <linux/input.h> ++ ++#define EVDEV_DEVICE_STRING "/dev/input/event%s" ++ ++void EvdevInputHandler::get_axis_limits(const InputAxisCode code, InputAxisLimits& limits) ++{ ++ struct input_absinfo abs; ++ if(!this->m_evdev_fd < 0 || code < 0 || ioctl(this->m_evdev_fd, EVIOCGABS(code), &abs)) ++ { ++ if(this->m_evdev_fd >= 0 && code >= 0) ++ { ++ perror("evdev ioctl"); ++ } ++ limits.minimum = 0; ++ limits.maximum = 0; ++ limits.deadzone = 0; ++ return; ++ } ++ limits.minimum = abs.minimum; ++ limits.maximum = abs.maximum; ++ limits.deadzone = abs.flat; ++} ++ ++std::string EvdevInputHandler::get_api_name() ++{ ++ return "evdev"; ++} ++ ++bool EvdevInputHandler::setup_device(std::string device) ++{ ++ size_t size_needed = snprintf(NULL, 0, EVDEV_DEVICE_STRING, device.c_str()) + 1; ++ char* evdev_fname = (char*)malloc(size_needed); ++ sprintf(evdev_fname, EVDEV_DEVICE_STRING, device.c_str()); ++ ++ printf("evdev: Trying to open device '%s'\n", evdev_fname); ++ ++ this->m_evdev_fd = open(evdev_fname, O_RDONLY); ++ ++ char device_name[256] = "Unknown"; ++ ++ if (this->m_evdev_fd < 0) ++ { ++ printf("evdev: Opening device '%s' failed - %s", evdev_fname, strerror(errno)); ++ free(evdev_fname); ++ return false; ++ } ++ ++ fcntl(this->m_evdev_fd, F_SETFL, O_NONBLOCK); ++ ++ // Get device name ++ if(ioctl(this->m_evdev_fd, EVIOCGNAME(sizeof(device_name)), device_name) < 0) ++ { ++ printf("evdev: Getting name of '%s' (ioctl) failed - %s", evdev_fname, strerror(errno)); ++ free(evdev_fname); ++ return false; ++ } ++ ++ printf("evdev: Found '%s' at '%s'\n", device_name, evdev_fname); ++ this->m_evdev_devname = std::string(device_name); ++ ++ free(evdev_fname); ++ ++ return true; ++} ++ ++std::string EvdevInputHandler::get_default_mapping_filename() ++{ ++ if (this->m_evdev_devname.empty()) ++ { ++ return ""; ++ } ++ ++ std::string mapping_filename; ++ #if defined(TARGET_PANDORA) ++ mapping_filename = "controller_pandora.cfg"; ++ #elif defined(TARGET_GCW0) ++ mapping_filename = "controller_gcwz.cfg"; ++ #else ++ if (strstr(this->m_evdev_devname.c_str(), "Microsoft X-Box 360 pad") == NULL || strstr(this->m_evdev_devname.c_str(), "Xbox 360 Wireless Receiver") == NULL) ++ { ++ mapping_filename = "controller_xpad.cfg"; ++ } ++ else if (strstr(this->m_evdev_devname.c_str(), "Xbox Gamepad (userspace driver)") != NULL) ++ { ++ mapping_filename = "controller_xboxdrv.cfg"; ++ } ++ else if (strstr(this->m_evdev_devname.c_str(), "keyboard") != NULL || strstr(this->m_evdev_devname.c_str(), "Keyboard") != NULL) ++ { ++ mapping_filename = "keyboard.cfg"; ++ } ++ else ++ { ++ mapping_filename = "controller_generic.cfg"; ++ } ++ #endif ++ ++ return mapping_filename; ++} ++ ++void EvdevInputHandler::handle() ++{ ++ if (!this->is_initialized()) ++ { ++ return; ++ } ++ ++ input_event ie; ++ while(read(this->m_evdev_fd, &ie, sizeof(ie)) == sizeof(ie)) ++ { ++ //printf("evdev: type = %d - code = %d - value = %d\n", ie.type, ie.code, ie.value); ++ switch(ie.type) ++ { ++ case EV_KEY: ++ { ++ this->handle_button(ie.code, ie.value); ++ break; ++ } ++ case EV_ABS: ++ { ++ this->handle_axis(ie.code, ie.value); ++ break; ++ } ++ } ++ } ++} ++#endif +diff -Nur a/core/linux-dist/handler_evdev.h b/core/linux-dist/handler_evdev.h +--- a/core/linux-dist/handler_evdev.h 1969-12-31 21:00:00.000000000 -0300 ++++ b/core/linux-dist/handler_evdev.h 2015-10-06 21:55:43.966475140 -0300 +@@ -0,0 +1,15 @@ ++#pragma once ++#include "handler.h" ++ ++class EvdevInputHandler : public InputHandler ++{ ++ private: ++ int m_evdev_fd; ++ std::string m_evdev_devname; ++ void get_axis_limits(const InputAxisCode code, InputAxisLimits& limits); ++ public: ++ void handle(); ++ std::string get_api_name(); ++ std::string get_default_mapping_filename(); ++ bool setup_device(std::string device); ++}; +\ No newline at end of file +diff -Nur a/core/linux-dist/handler.h b/core/linux-dist/handler.h +--- a/core/linux-dist/handler.h 1969-12-31 21:00:00.000000000 -0300 ++++ b/core/linux-dist/handler.h 2015-10-06 21:55:43.966475140 -0300 +@@ -0,0 +1,49 @@ ++#pragma once ++#include "types.h" ++#include "mapping.h" ++#include "mappingstore.h" ++ ++struct InputAxisLimits ++{ ++ s32 minimum; ++ s32 maximum; ++ s32 deadzone; ++}; ++ ++class InputAxisConverter ++{ ++ private: ++ s32 m_minimum; ++ s32 m_range; ++ s32 m_deadzone; ++ public: ++ InputAxisConverter(bool inverted, InputAxisLimits limits); ++ s8 convert(s32 value); ++}; ++ ++class InputHandler ++{ ++ typedef std::map<InputAxisID, InputAxisConverter*> InputAxisConverterStore; ++ private: ++ InputAxisConverterStore m_axis_converters; ++ void enable_axis_converter(InputAxisID axis, bool inverted, InputAxisLimits limits); ++ void disable_axis_converter(InputAxisID axis); ++ InputAxisConverter* get_axis_converter(InputAxisID axis); ++ bool m_initialized; ++ protected: ++ static InputMappingStore s_mappingstore; ++ u32 m_port; ++ InputMapping* m_mapping; ++ bool is_initialized(); ++ void handle_button(InputButtonCode code, int value); ++ void handle_axis(InputAxisCode code, int value); ++ virtual void get_axis_limits(const InputAxisCode code, InputAxisLimits& limits); ++ public: ++ InputHandler(); ++ ~InputHandler(); ++ bool initialize(u32 port, std::string device, std::string custom_mapping); ++ virtual std::string get_default_mapping_filename(); ++ virtual void handle() = 0; ++ virtual std::string get_api_name() = 0; ++ virtual bool setup_device(std::string device) = 0; ++}; +\ No newline at end of file +diff -Nur a/core/linux-dist/handler_linuxjs.cpp b/core/linux-dist/handler_linuxjs.cpp +--- a/core/linux-dist/handler_linuxjs.cpp 1969-12-31 21:00:00.000000000 -0300 ++++ b/core/linux-dist/handler_linuxjs.cpp 2015-10-06 21:55:43.966475140 -0300 +@@ -0,0 +1,127 @@ ++#if defined(USE_JOYSTICK) ++#include "handler_linuxjs.h" ++#include <cstring> ++#include <cerrno> ++#include <fcntl.h> ++#include <unistd.h> ++#include <linux/joystick.h> ++ ++#define LINUXJS_DEVICE_STRING "/dev/input/js%s" ++ ++void LinuxJoystickInputHandler::get_axis_limits(const InputAxisCode code, InputAxisLimits& limits) ++{ ++ // The Linux Joystick API's axes always normalized to this minimum/maximum ++ limits.minimum = -32767; ++ limits.maximum = 32767; ++ limits.deadzone = 0; ++} ++ ++std::string LinuxJoystickInputHandler::get_api_name() ++{ ++ return "linuxjs"; ++} ++ ++bool LinuxJoystickInputHandler::setup_device(std::string device) ++{ ++ size_t size_needed = snprintf(NULL, 0, LINUXJS_DEVICE_STRING, device.c_str()) + 1; ++ char* linuxjs_fname = (char*)malloc(size_needed); ++ sprintf(linuxjs_fname, LINUXJS_DEVICE_STRING, device.c_str()); ++ ++ printf("linuxjs: Trying to open device '%s'\n", linuxjs_fname); ++ ++ this->m_linuxjs_fd = open(linuxjs_fname, O_RDONLY); ++ ++ if (this->m_linuxjs_fd < 0) ++ { ++ printf("linuxjs: Opening device '%s' failed - %s", linuxjs_fname, strerror(errno)); ++ free(linuxjs_fname); ++ return false; ++ } ++ ++ fcntl(this->m_linuxjs_fd, F_SETFL, O_NONBLOCK); ++ ++ char device_name[256] = "Unknown"; ++ int button_count = 0; ++ int axis_count = 0; ++ ++ // Get device name ++ if(ioctl(this->m_linuxjs_fd, JSIOCGNAME(sizeof(device_name)), device_name) < 0) ++ { ++ printf("linuxjs: Getting name of '%s' (ioctl) failed - %s", linuxjs_fname, strerror(errno)); ++ free(linuxjs_fname); ++ return false; ++ } ++ ++ // Get number of buttons ++ if(ioctl(this->m_linuxjs_fd, JSIOCGBUTTONS, &button_count) < 0) ++ { ++ printf("linuxjs: Getting button count of '%s' (ioctl) failed - %s", linuxjs_fname, strerror(errno)); ++ free(linuxjs_fname); ++ return false; ++ } ++ ++ // Get number of axes ++ if(ioctl(this->m_linuxjs_fd, JSIOCGAXES, &axis_count) < 0) ++ { ++ printf("linuxjs: Getting axis count of '%s' (ioctl) failed - %s", linuxjs_fname, strerror(errno)); ++ free(linuxjs_fname); ++ return false; ++ } ++ ++ printf("linuxjs: Found '%s' with %d axes and %d buttons at '%s'\n", device_name, axis_count, button_count, linuxjs_fname); ++ this->m_linuxjs_devname = std::string(device_name); ++ ++ free(linuxjs_fname); ++ ++ return true; ++} ++ ++std::string LinuxJoystickInputHandler::get_default_mapping_filename() ++{ ++ if (this->m_linuxjs_devname.empty()) ++ { ++ return ""; ++ } ++ ++ std::string mapping_filename; ++ if (strstr(this->m_linuxjs_devname.c_str(), "Microsoft X-Box 360 pad") != NULL || ++ strstr(this->m_linuxjs_devname.c_str(), "Xbox Gamepad (userspace driver)") != NULL || ++ strstr(this->m_linuxjs_devname.c_str(), "Xbox 360 Wireless Receiver") != NULL) ++ { ++ mapping_filename = "controller_xbox360.cfg"; ++ } ++ else ++ { ++ mapping_filename = "controller_generic.cfg"; ++ } ++ ++ return mapping_filename; ++} ++ ++void LinuxJoystickInputHandler::handle() ++{ ++ if (!this->is_initialized()) ++ { ++ return; ++ } ++ ++ struct js_event je; ++ while(read(this->m_linuxjs_fd, &je, sizeof(je)) == sizeof(je)) ++ { ++ printf("linuxjs: type = %d - code = %d - value = %d\n", je.type, je.number, je.value); ++ switch(je.type) ++ { ++ case JS_EVENT_BUTTON: ++ { ++ this->handle_button(je.number, je.value); ++ break; ++ } ++ case JS_EVENT_AXIS: ++ { ++ this->handle_axis(je.number, je.value); ++ break; ++ } ++ } ++ } ++} ++#endif +\ No newline at end of file +diff -Nur a/core/linux-dist/handler_linuxjs.h b/core/linux-dist/handler_linuxjs.h +--- a/core/linux-dist/handler_linuxjs.h 1969-12-31 21:00:00.000000000 -0300 ++++ b/core/linux-dist/handler_linuxjs.h 2015-10-06 21:55:43.966475140 -0300 +@@ -0,0 +1,15 @@ ++#pragma once ++#include "handler.h" ++ ++class LinuxJoystickInputHandler : public InputHandler ++{ ++ private: ++ int m_linuxjs_fd; ++ std::string m_linuxjs_devname; ++ void get_axis_limits(const InputAxisCode code, InputAxisLimits& limits); ++ public: ++ void handle(); ++ std::string get_api_name(); ++ std::string get_default_mapping_filename(); ++ bool setup_device(std::string device); ++}; +\ No newline at end of file +diff -Nur a/core/linux-dist/joystick.cpp b/core/linux-dist/joystick.cpp +--- a/core/linux-dist/joystick.cpp 2015-10-06 21:43:53.042336401 -0300 ++++ b/core/linux-dist/joystick.cpp 1969-12-31 21:00:00.000000000 -0300 +@@ -1,158 +0,0 @@ +-#include <unistd.h> +-#include <fcntl.h> +-#include <sys/types.h> +-#include <linux/joystick.h> +-#include "linux-dist/joystick.h" +- +-#if defined(USE_JOYSTICK) +- const u32 joystick_map_btn_usb[JOYSTICK_MAP_SIZE] = { DC_BTN_Y, DC_BTN_B, DC_BTN_A, DC_BTN_X, 0, 0, 0, 0, 0, DC_BTN_START }; +- const u32 joystick_map_axis_usb[JOYSTICK_MAP_SIZE] = { DC_AXIS_X, DC_AXIS_Y, 0, 0, 0, 0, 0, 0, 0, 0 }; +- +- const u32 joystick_map_btn_xbox360[JOYSTICK_MAP_SIZE] = { DC_BTN_A, DC_BTN_B, DC_BTN_X, DC_BTN_Y, 0, 0, 0, DC_BTN_START, 0, 0 }; +- const u32 joystick_map_axis_xbox360[JOYSTICK_MAP_SIZE] = { DC_AXIS_X, DC_AXIS_Y, DC_AXIS_LT, 0, 0, DC_AXIS_RT, DC_DPAD_LEFT, DC_DPAD_UP, 0, 0 }; +- +- const u32* joystick_map_btn = joystick_map_btn_usb; +- const u32* joystick_map_axis = joystick_map_axis_usb; +- +- int input_joystick_init(const char* device) +- { +- int axis_count = 0; +- int button_count = 0; +- char name[128] = "Unknown"; +- +- printf("joystick: Trying to open device at '%s'\n", device); +- +- int fd = open(device, O_RDONLY); +- +- if(fd >= 0) +- { +- fcntl(fd, F_SETFL, O_NONBLOCK); +- ioctl(fd, JSIOCGAXES, &axis_count); +- ioctl(fd, JSIOCGBUTTONS, &button_count); +- ioctl(fd, JSIOCGNAME(sizeof(name)), &name); +- +- printf("joystick: Found '%s' with %d axis and %d buttons at '%s'.\n", name, axis_count, button_count, device); +- +- if (strcmp(name, "Microsoft X-Box 360 pad") == 0 || +- strcmp(name, "Xbox Gamepad (userspace driver)") == 0 || +- strcmp(name, "Xbox 360 Wireless Receiver (XBOX)") == 0) +- { +- joystick_map_btn = joystick_map_btn_xbox360; +- joystick_map_axis = joystick_map_axis_xbox360; +- printf("joystick: Using Xbox 360 map\n"); +- } +- } +- else +- { +- perror("joystick open"); +- } +- +- return fd; +- } +- +- bool input_joystick_handle(int fd, u32 port) +- { +- // Joystick must be connected +- if(fd < 0) { +- return false; +- } +- +- struct js_event JE; +- while(read(fd, &JE, sizeof(JE)) == sizeof(JE)) +- if (JE.number < JOYSTICK_MAP_SIZE) +- { +- switch(JE.type & ~JS_EVENT_INIT) +- { +- case JS_EVENT_AXIS: +- { +- u32 mt = joystick_map_axis[JE.number] >> 16; +- u32 mo = joystick_map_axis[JE.number] & 0xFFFF; +- +- //printf("AXIS %d,%d\n",JE.number,JE.value); +- s8 v=(s8)(JE.value/256); //-127 ... + 127 range +- +- if (mt == 0) +- { +- kcode[port] |= mo; +- kcode[port] |= mo*2; +- if (v<-64) +- { +- kcode[port] &= ~mo; +- } +- else if (v>64) +- { +- kcode[port] &= ~(mo*2); +- } +- +- //printf("Mapped to %d %d %d\n",mo,kcode[port]&mo,kcode[port]&(mo*2)); +- } +- else if (mt == 1) +- { +- if (v >= 0) +- { +- v++; //up to 255 +- } +- //printf("AXIS %d,%d Mapped to %d %d %d\n",JE.number,JE.value,mo,v,v+127); +- if (mo == 0) +- { +- lt[port] = (v + 127); +- } +- else if (mo == 1) +- { +- rt[port] = (v + 127); +- } +- } +- else if (mt == 2) +- { +- // printf("AXIS %d,%d Mapped to %d %d [%d]",JE.number,JE.value,mo,v); +- if (mo == 0) +- { +- joyx[port] = v; +- } +- else if (mo == 1) +- { +- joyy[port] = v; +- } +- } +- } +- break; +- +- case JS_EVENT_BUTTON: +- { +- u32 mt = joystick_map_btn[JE.number] >> 16; +- u32 mo = joystick_map_btn[JE.number] & 0xFFFF; +- +- // printf("BUTTON %d,%d\n",JE.number,JE.value); +- +- if (mt == 0) +- { +- // printf("Mapped to %d\n",mo); +- if (JE.value) +- { +- kcode[port] &= ~mo; +- } +- else +- { +- kcode[port] |= mo; +- } +- } +- else if (mt == 1) +- { +- // printf("Mapped to %d %d\n",mo,JE.value?255:0); +- if (mo==0) +- { +- lt[port] = JE.value ? 255 : 0; +- } +- else if (mo==1) +- { +- rt[port] = JE.value ? 255 : 0; +- } +- } +- } +- break; +- } +- } +- +- return true; +- } +-#endif +diff -Nur a/core/linux-dist/joystick.h b/core/linux-dist/joystick.h +--- a/core/linux-dist/joystick.h 2015-10-06 21:43:53.042336401 -0300 ++++ b/core/linux-dist/joystick.h 1969-12-31 21:00:00.000000000 -0300 +@@ -1,10 +0,0 @@ +-#include "types.h" +-#include "linux-dist/main.h" +- +-#pragma once +-#define JOYSTICK_DEVICE_STRING "/dev/input/js%d" +-#define JOYSTICK_DEFAULT_DEVICE_ID -1 +-#define JOYSTICK_MAP_SIZE 32 +- +-extern int input_joystick_init(const char* device); +-extern bool input_joystick_handle(int fd, u32 port); +diff -Nur a/core/linux-dist/main.cpp b/core/linux-dist/main.cpp +--- a/core/linux-dist/main.cpp 2015-10-06 21:43:53.042336401 -0300 ++++ b/core/linux-dist/main.cpp 2015-10-06 21:55:43.966475140 -0300 +@@ -14,6 +14,7 @@ + #include <sys/time.h> + #include "hw/sh4/dyna/blockmanager.h" + #include <unistd.h> ++#include "proxy.h" + + #if defined(TARGET_EMSCRIPTEN) + #include <emscripten.h> +@@ -32,11 +33,11 @@ + #endif + + #if defined(USE_EVDEV) +- #include "linux-dist/evdev.h" ++ #include "linux-dist/handler_evdev.h" + #endif + + #if defined(USE_JOYSTICK) +- #include "linux-dist/joystick.h" ++ #include "linux-dist/handler_linuxjs.h" + #endif + + #ifdef TARGET_PANDORA +@@ -84,82 +85,68 @@ + + void emit_WriteCodeCache(); + +-#if defined(USE_EVDEV) +- /* evdev input */ +- static EvdevController evdev_controllers[4] = { +- { -1, NULL }, +- { -1, NULL }, +- { -1, NULL }, +- { -1, NULL } +- }; +-#endif +- +-#if defined(USE_JOYSTICK) +- /* legacy joystick input */ +- static int joystick_fd = -1; // Joystick file descriptor +-#endif ++static InputHandlerProxy input_handlers; + + void SetupInput() + { + #if defined(USE_EVDEV) +- int evdev_device_id[4] = { -1, -1, -1, -1 }; +- size_t size_needed; +- int port, i; ++ #define EVDEV_DEVICE_CONFIG_KEY "evdev_device_id_%d" ++ #define EVDEV_MAPPING_CONFIG_KEY "evdev_mapping_%d" + +- char* evdev_device; ++ #ifdef TARGET_PANDORA ++ #define EVDEV_DEFAULT_DEVICE_ID_1 "4" ++ #else ++ #define EVDEV_DEFAULT_DEVICE_ID_1 "0" ++ #endif ++ #define EVDEV_DEFAULT_DEVICE_ID(port) (port == 1 ? EVDEV_DEFAULT_DEVICE_ID_1 : "-1") + +- for (port = 0; port < 4; port++) ++ for (int port = 0; port < 4; port++) + { ++ size_t size_needed; ++ char* evdev_config_key; ++ std::string evdev_device; ++ std::string custom_mapping_filename; ++ + size_needed = snprintf(NULL, 0, EVDEV_DEVICE_CONFIG_KEY, port+1) + 1; +- char* evdev_config_key = (char*)malloc(size_needed); ++ evdev_config_key = (char*)malloc(size_needed); + sprintf(evdev_config_key, EVDEV_DEVICE_CONFIG_KEY, port+1); +- evdev_device_id[port] = cfgLoadInt("input", evdev_config_key, EVDEV_DEFAULT_DEVICE_ID(port+1)); ++ evdev_device = cfgLoadStr("input", evdev_config_key, EVDEV_DEFAULT_DEVICE_ID(port+1)); + free(evdev_config_key); + +- // Check if the same device is already in use on another port +- if (evdev_device_id[port] < 0) ++ if(evdev_device.c_str()[0] == '-') + { + printf("evdev: Controller %d disabled by config.\n", port + 1); ++ continue; + } +- else +- { +- for (i = 0; i < port; i++) +- { +- if (evdev_device_id[port] == evdev_device_id[i]) +- { +- die("You can't assign the same device to multiple ports!\n"); +- } +- } +- +- size_needed = snprintf(NULL, 0, EVDEV_DEVICE_STRING, evdev_device_id[port]) + 1; +- evdev_device = (char*)malloc(size_needed); +- sprintf(evdev_device, EVDEV_DEVICE_STRING, evdev_device_id[port]); +- +- size_needed = snprintf(NULL, 0, EVDEV_MAPPING_CONFIG_KEY, port+1) + 1; +- evdev_config_key = (char*)malloc(size_needed); +- sprintf(evdev_config_key, EVDEV_MAPPING_CONFIG_KEY, port+1); +- const char* mapping = (cfgExists("input", evdev_config_key) == 2 ? cfgLoadStr("input", evdev_config_key, "").c_str() : NULL); +- free(evdev_config_key); + +- input_evdev_init(&evdev_controllers[port], evdev_device, mapping); ++ size_needed = snprintf(NULL, 0, EVDEV_MAPPING_CONFIG_KEY, port+1) + 1; ++ evdev_config_key = (char*)malloc(size_needed); ++ sprintf(evdev_config_key, EVDEV_MAPPING_CONFIG_KEY, port+1); ++ custom_mapping_filename = (cfgExists("input", evdev_config_key) == 2 ? cfgLoadStr("input", evdev_config_key, "") : ""); ++ free(evdev_config_key); + +- free(evdev_device); +- } ++ EvdevInputHandler* handler = new EvdevInputHandler(); ++ handler->initialize(port, evdev_device, custom_mapping_filename); ++ input_handlers.add(port, handler); + } + #endif + + #if defined(USE_JOYSTICK) +- int joystick_device_id = cfgLoadInt("input", "joystick_device_id", JOYSTICK_DEFAULT_DEVICE_ID); +- if (joystick_device_id < 0) { +- puts("Legacy Joystick input disabled by config.\n"); ++ #define JOYSTICK_DEFAULT_DEVICE_ID "-1" ++ ++ std::string linuxjs_device; ++ std::string custom_mapping_filename = ""; ++ ++ linuxjs_device = cfgLoadStr("input", "joystick_device_id", JOYSTICK_DEFAULT_DEVICE_ID); ++ if (linuxjs_device.c_str()[0] == '-') ++ { ++ puts("LinuxJoystick input disabled by config.\n"); + } + else + { +- int joystick_device_length = snprintf(NULL, 0, JOYSTICK_DEVICE_STRING, joystick_device_id); +- char* joystick_device = (char*)malloc(joystick_device_length + 1); +- sprintf(joystick_device, JOYSTICK_DEVICE_STRING, joystick_device_id); +- joystick_fd = input_joystick_init(joystick_device); +- free(joystick_device); ++ LinuxJoystickInputHandler* handler = new LinuxJoystickInputHandler(); ++ handler->initialize(0, linuxjs_device, custom_mapping_filename); ++ input_handlers.add(0, handler); + } + #endif + +@@ -178,13 +165,7 @@ + return; + #endif + +- #if defined(USE_JOYSTICK) +- input_joystick_handle(joystick_fd, port); +- #endif +- +- #if defined(USE_EVDEV) +- input_evdev_handle(&evdev_controllers[port], port); +- #endif ++ input_handlers.handle(port); + + #if defined(USE_SDL) + input_sdl_handle(port); +diff -Nur a/core/linux-dist/main.h b/core/linux-dist/main.h +--- a/core/linux-dist/main.h 2015-10-06 21:43:53.042336401 -0300 ++++ b/core/linux-dist/main.h 2015-10-06 21:55:43.966475140 -0300 +@@ -11,25 +11,34 @@ + + enum DreamcastController + { +- DC_BTN_C = 1, +- DC_BTN_B = 1<<1, +- DC_BTN_A = 1<<2, +- DC_BTN_START = 1<<3, +- DC_DPAD_UP = 1<<4, +- DC_DPAD_DOWN = 1<<5, +- DC_DPAD_LEFT = 1<<6, +- DC_DPAD_RIGHT = 1<<7, +- DC_BTN_Z = 1<<8, +- DC_BTN_Y = 1<<9, +- DC_BTN_X = 1<<10, +- DC_BTN_D = 1<<11, +- DC_DPAD2_UP = 1<<12, +- DC_DPAD2_DOWN = 1<<13, +- DC_DPAD2_LEFT = 1<<14, +- DC_DPAD2_RIGHT = 1<<15, ++ EMU_BTN_NONE = 0, ++ EMU_BTN_ESCAPE = 1<<16, ++ EMU_BTN_TRIGGER_LEFT = 1<<17, ++ EMU_BTN_TRIGGER_RIGHT = 1<<18, ++ DC_BTN_C = 1, ++ DC_BTN_B = 1<<1, ++ DC_BTN_A = 1<<2, ++ DC_BTN_START = 1<<3, ++ DC_BTN_DPAD1_UP = 1<<4, ++ DC_BTN_DPAD1_DOWN = 1<<5, ++ DC_BTN_DPAD1_LEFT = 1<<6, ++ DC_BTN_DPAD1_RIGHT = 1<<7, ++ DC_BTN_Z = 1<<8, ++ DC_BTN_Y = 1<<9, ++ DC_BTN_X = 1<<10, ++ DC_BTN_D = 1<<11, ++ DC_BTN_DPAD2_UP = 1<<12, ++ DC_BTN_DPAD2_DOWN = 1<<13, ++ DC_BTN_DPAD2_LEFT = 1<<14, ++ DC_BTN_DPAD2_RIGHT = 1<<15, + +- DC_AXIS_LT = 0X10000, +- DC_AXIS_RT = 0X10001, +- DC_AXIS_X = 0X20000, +- DC_AXIS_Y = 0X20001, ++ EMU_AXIS_NONE = 0X00000, ++ EMU_AXIS_DPAD1_X = 0X00001, ++ EMU_AXIS_DPAD1_Y = 0X00002, ++ EMU_AXIS_DPAD2_X = 0X00003, ++ EMU_AXIS_DPAD2_Y = 0X00004, ++ DC_AXIS_TRIGGER_LEFT = 0X10000, ++ DC_AXIS_TRIGGER_RIGHT = 0X10001, ++ DC_AXIS_X = 0X20000, ++ DC_AXIS_Y = 0X20001, + }; +diff -Nur a/core/linux-dist/mapping.cpp b/core/linux-dist/mapping.cpp +--- a/core/linux-dist/mapping.cpp 1969-12-31 21:00:00.000000000 -0300 ++++ b/core/linux-dist/mapping.cpp 2015-10-06 21:55:43.966475140 -0300 +@@ -0,0 +1,159 @@ ++#include "linux-dist/mapping.h" ++#include "cfg/ini.h" ++ ++struct ButtonMap ++{ ++ InputButtonID id; ++ string section; ++ string option; ++}; ++ ++struct AxisMap ++{ ++ InputAxisID id; ++ string section; ++ string option; ++ string section_inverted; ++ string option_inverted; ++}; ++ ++static ButtonMap button_list[19] = { ++ { DC_BTN_A, "dreamcast", "btn_a" }, ++ { DC_BTN_B, "dreamcast", "btn_b" }, ++ { DC_BTN_C, "dreamcast", "btn_c" }, ++ { DC_BTN_D, "dreamcast", "btn_d" }, ++ { DC_BTN_X, "dreamcast", "btn_x" }, ++ { DC_BTN_Y, "dreamcast", "btn_y" }, ++ { DC_BTN_Z, "dreamcast", "btn_z" }, ++ { DC_BTN_START, "dreamcast", "btn_start" }, ++ { DC_BTN_DPAD1_LEFT, "dreamcast", "btn_dpad1_left" }, ++ { DC_BTN_DPAD1_RIGHT, "dreamcast", "btn_dpad1_right" }, ++ { DC_BTN_DPAD1_UP, "dreamcast", "btn_dpad1_up" }, ++ { DC_BTN_DPAD1_DOWN, "dreamcast", "btn_dpad1_down" }, ++ { DC_BTN_DPAD2_LEFT, "dreamcast", "btn_dpad2_left" }, ++ { DC_BTN_DPAD2_RIGHT, "dreamcast", "btn_dpad2_right" }, ++ { DC_BTN_DPAD2_UP, "dreamcast", "btn_dpad2_up" }, ++ { DC_BTN_DPAD2_DOWN, "dreamcast", "btn_dpad2_down" }, ++ { EMU_BTN_ESCAPE, "emulator", "btn_escape" }, ++ { EMU_BTN_TRIGGER_LEFT, "compat", "btn_trigger_left" }, ++ { EMU_BTN_TRIGGER_RIGHT, "compat", "btn_trigger_right" } ++}; ++ ++static AxisMap axis_list[8] = { ++ { DC_AXIS_X, "dreamcast", "axis_x", "compat", "axis_x_inverted" }, ++ { DC_AXIS_Y, "dreamcast", "axis_y", "compat", "axis_y_inverted" }, ++ { DC_AXIS_TRIGGER_LEFT, "dreamcast", "axis_trigger_left", "compat", "axis_trigger_left_inverted" }, ++ { DC_AXIS_TRIGGER_RIGHT, "dreamcast", "axis_trigger_right", "compat", "axis_trigger_right_inverted" }, ++ { EMU_AXIS_DPAD1_X, "compat", "axis_dpad1_x", "compat", "axis_dpad1_x_inverted" }, ++ { EMU_AXIS_DPAD1_Y, "compat", "axis_dpad1_y", "compat", "axis_dpad1_y_inverted" }, ++ { EMU_AXIS_DPAD2_X, "compat", "axis_dpad2_x", "compat", "axis_dpad2_x_inverted" }, ++ { EMU_AXIS_DPAD2_Y, "compat", "axis_dpad2_y", "compat", "axis_dpad2_y_inverted" } ++}; ++ ++const InputButtonID* InputMapping::get_button_id(InputButtonCode code) ++{ ++ return this->buttons.get_by_value(code); ++} ++ ++const InputButtonCode* InputMapping::get_button_code(InputButtonID id) ++{ ++ return this->buttons.get_by_key(id); ++} ++ ++void InputMapping::set_button(InputButtonID id, InputButtonCode code) ++{ ++ if(id != EMU_BTN_NONE) ++ { ++ this->buttons.insert(id, code); ++ } ++} ++ ++const InputAxisID* InputMapping::get_axis_id(InputAxisCode code) ++{ ++ return this->axes.get_by_value(code); ++} ++ ++const InputAxisCode* InputMapping::get_axis_code(InputAxisID id) ++{ ++ return this->axes.get_by_key(id); ++} ++ ++bool InputMapping::get_axis_inverted(InputAxisCode code) ++{ ++ std::map<InputAxisCode, bool>::iterator it = this->axes_inverted.find('b'); ++ if (it != this->axes_inverted.end()) ++ { ++ return it->second; ++ } ++ return false; ++} ++ ++void InputMapping::set_axis(InputAxisID id, InputAxisCode code, bool is_inverted) ++{ ++ if(id != EMU_AXIS_NONE) ++ { ++ this->axes.insert(id, code); ++ this->axes_inverted.insert(std::pair<InputAxisCode,bool>(code, is_inverted)); ++ } ++} ++ ++void InputMapping::load(FILE* fd) ++{ ++ ConfigFile mf; ++ mf.parse(fd); ++ ++ this->name = mf.get("emulator", "mapping_name", "<Unknown>").c_str(); ++ ++ int i; ++ for(i = 0; i < 19; i++) ++ { ++ InputButtonCode button_code = mf.get_int(button_list[i].section, button_list[i].option, -1); ++ if (button_code >= 0) ++ { ++ this->set_button(button_list[i].id, button_code); ++ } ++ } ++ ++ for(i = 0; i < 8; i++) ++ { ++ InputAxisCode axis_code = mf.get_int(axis_list[i].section, axis_list[i].option, -1); ++ if(axis_code >= 0) ++ { ++ this->set_axis(axis_list[i].id, axis_code, mf.get_bool(axis_list[i].section_inverted, axis_list[i].option_inverted, false)); ++ } ++ } ++} ++ ++void InputMapping::print() ++{ ++ int i; ++ ++ printf("\nMAPPING NAME: %s\n", this->name); ++ ++ puts("MAPPED BUTTONS:"); ++ for(i = 0; i < 19; i++) ++ { ++ const InputButtonCode* button_code = this->get_button_code(button_list[i].id); ++ if(button_code) ++ { ++ printf("%-18s = %d\n", button_list[i].option.c_str(), *button_code); ++ } ++ } ++ ++ puts("MAPPED AXES:"); ++ for(i = 0; i < 8; i++) ++ { ++ const InputAxisCode* axis_code = this->get_axis_code(axis_list[i].id); ++ if(axis_code) ++ { ++ printf("%-18s = %d", axis_list[i].option.c_str(), *axis_code); ++ if(this->get_axis_inverted(*axis_code)) ++ { ++ printf("%s", "(inverted)"); ++ } ++ printf("%s", "\n"); ++ } ++ } ++ puts(""); ++} ++ +diff -Nur a/core/linux-dist/mapping.h b/core/linux-dist/mapping.h +--- a/core/linux-dist/mapping.h 1969-12-31 21:00:00.000000000 -0300 ++++ b/core/linux-dist/mapping.h 2015-10-06 21:55:43.966475140 -0300 +@@ -0,0 +1,32 @@ ++#pragma once ++#include <map> ++#include "linux-dist/main.h" ++#include "linux-dist/bimap.h" ++ ++typedef DreamcastController InputButtonID; ++typedef DreamcastController InputAxisID; ++typedef int InputButtonCode; ++typedef int InputAxisCode; ++ ++class InputMapping ++{ ++ private: ++ SimpleBimap<InputButtonID, InputButtonCode> buttons; ++ SimpleBimap<InputAxisID, InputAxisCode> axes; ++ std::map<InputAxisCode, bool> axes_inverted; ++ ++ public: ++ const char* name; ++ ++ void set_button(InputButtonID id, InputButtonCode code); ++ const InputButtonID* get_button_id(InputButtonCode code); ++ const InputButtonCode* get_button_code(InputButtonID id); ++ ++ void set_axis(InputAxisID id, InputAxisCode code, bool inverted); ++ const InputAxisID* get_axis_id(InputAxisCode code); ++ const InputAxisCode* get_axis_code(InputAxisID id); ++ bool get_axis_inverted(InputAxisCode code); ++ ++ void load(FILE* file); ++ void print(); ++}; +diff -Nur a/core/linux-dist/mappingstore.cpp b/core/linux-dist/mappingstore.cpp +--- a/core/linux-dist/mappingstore.cpp 1969-12-31 21:00:00.000000000 -0300 ++++ b/core/linux-dist/mappingstore.cpp 2015-10-06 21:55:43.966475140 -0300 +@@ -0,0 +1,61 @@ ++#include "mappingstore.h" ++#include <errno.h> ++ ++static std::string get_mapping_path(std::string filepath, std::string subdir) ++{ ++ if (filepath.empty()) ++ { ++ return ""; ++ } ++ ++ std::string new_filepath; ++ if (filepath.at(0) != '/') ++ { ++ // It's not an absolute path ++ std::string mapping_dir = "/mappings/"; ++ if(!subdir.empty()) ++ { ++ mapping_dir.append(subdir); ++ mapping_dir.append("/"); ++ } ++ filepath.insert(0, mapping_dir); ++ new_filepath = get_readonly_data_path(filepath); ++ } ++ else ++ { ++ new_filepath = filepath; ++ } ++ ++ // TODO: Some realpath magic? How portable is it? ++ ++ return new_filepath; ++} ++ ++InputMapping* InputMappingStore::get(std::string filepath, std::string subdir) ++{ ++ std::string full_filepath = get_mapping_path(filepath, subdir); ++ if(!full_filepath.empty()) ++ { ++ if(this->loaded_mappings.count(full_filepath) == 0) ++ { ++ // Mapping has not been loaded yet ++ FILE* fp = fopen(full_filepath.c_str(), "r"); ++ if(fp == NULL) ++ { ++ printf("Unable to open mapping file '%s': %s\n", full_filepath.c_str(), strerror(errno)); ++ } ++ else ++ { ++ InputMapping* mapping = new InputMapping(); ++ mapping->load(fp); ++ this->loaded_mappings.insert(std::pair<std::string, InputMapping*>(full_filepath, mapping)); ++ } ++ } ++ std::map<std::string, InputMapping*>::iterator it = loaded_mappings.find(full_filepath); ++ if(it != loaded_mappings.end()) ++ { ++ return it->second; ++ } ++ } ++ return NULL; ++} +\ No newline at end of file +diff -Nur a/core/linux-dist/mappingstore.h b/core/linux-dist/mappingstore.h +--- a/core/linux-dist/mappingstore.h 1969-12-31 21:00:00.000000000 -0300 ++++ b/core/linux-dist/mappingstore.h 2015-10-06 21:55:43.966475140 -0300 +@@ -0,0 +1,11 @@ ++#pragma once ++#include "mapping.h" ++#include <string> ++ ++class InputMappingStore ++{ ++ private: ++ std::map<std::string, InputMapping*> loaded_mappings; ++ public: ++ InputMapping* get(std::string filepath, std::string subdir = ""); ++}; +diff -Nur a/core/linux-dist/proxy.cpp b/core/linux-dist/proxy.cpp +--- a/core/linux-dist/proxy.cpp 1969-12-31 21:00:00.000000000 -0300 ++++ b/core/linux-dist/proxy.cpp 2015-10-06 21:55:43.966475140 -0300 +@@ -0,0 +1,25 @@ ++#include "proxy.h" ++ ++InputHandlerProxy::~InputHandlerProxy() ++{ ++ //TODO ++} ++ ++void InputHandlerProxy::add(u32 port, InputHandler* handler) ++{ ++ if(handler != NULL) ++ { ++ this->handlers.insert(std::pair<u32, InputHandler*>(port, handler)); ++ } ++} ++ ++void InputHandlerProxy::handle(u32 port) ++{ ++ std::pair <InputHandlerStore::iterator, InputHandlerStore::iterator> range; ++ range = this->handlers.equal_range(port); ++ ++ for (InputHandlerStore::iterator it = range.first; it != range.second; ++it) ++ { ++ it->second->handle(); ++ } ++} +\ No newline at end of file +diff -Nur a/core/linux-dist/proxy.h b/core/linux-dist/proxy.h +--- a/core/linux-dist/proxy.h 1969-12-31 21:00:00.000000000 -0300 ++++ b/core/linux-dist/proxy.h 2015-10-06 21:55:43.966475140 -0300 +@@ -0,0 +1,15 @@ ++#pragma once ++#include <map> ++#include "types.h" ++#include "handler.h" ++ ++class InputHandlerProxy ++{ ++ typedef std::multimap<u32, InputHandler*> InputHandlerStore; ++ private: ++ InputHandlerStore handlers; ++ public: ++ ~InputHandlerProxy(); ++ void add(u32 port, InputHandler* handler); ++ void handle(u32 port); ++}; +\ No newline at end of file +diff -Nur a/core/linux-dist/x11.cpp b/core/linux-dist/x11.cpp +--- a/core/linux-dist/x11.cpp 2015-10-06 21:43:53.042336401 -0300 ++++ b/core/linux-dist/x11.cpp 2015-10-06 21:55:43.966475140 -0300 +@@ -112,11 +112,11 @@ + + void input_x11_init() + { +- x11_keymap[113] = DC_DPAD_LEFT; +- x11_keymap[114] = DC_DPAD_RIGHT; ++ x11_keymap[113] = DC_BTN_DPAD1_LEFT; ++ x11_keymap[114] = DC_BTN_DPAD1_RIGHT; + +- x11_keymap[111] = DC_DPAD_UP; +- x11_keymap[116] = DC_DPAD_DOWN; ++ x11_keymap[111] = DC_BTN_DPAD1_UP; ++ x11_keymap[116] = DC_BTN_DPAD1_DOWN; + + x11_keymap[53] = DC_BTN_X; + x11_keymap[54] = DC_BTN_B; |