summaryrefslogtreecommitdiff
path: root/pcr/reicast-git/generalize-mappings.patch
diff options
context:
space:
mode:
authorcoadde [Márcio Alexandre Silva Delgado] <coadde@parabola.nu>2015-10-07 03:14:31 -0300
committercoadde [Márcio Alexandre Silva Delgado] <coadde@parabola.nu>2015-10-07 03:18:49 -0300
commit7b54c0078640584b82d93ad445537a9b069dfeb0 (patch)
tree25e3ac69ae0e24d4c57837e9b6a5944405e3272f /pcr/reicast-git/generalize-mappings.patch
parentb35d45f979dc2c511e94d5ad33bba43425fa45a0 (diff)
pcr/reicast-git: update pkg
Diffstat (limited to 'pcr/reicast-git/generalize-mappings.patch')
-rw-r--r--pcr/reicast-git/generalize-mappings.patch1979
1 files changed, 1979 insertions, 0 deletions
diff --git a/pcr/reicast-git/generalize-mappings.patch b/pcr/reicast-git/generalize-mappings.patch
new file mode 100644
index 000000000..a47681f39
--- /dev/null
+++ b/pcr/reicast-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;