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 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 +#include +#include + +template +class SimpleBimap +{ + private: + typedef typename std::map MapA; + typedef typename std::map 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(b, NULL)).first; + T2* ptr_b = const_cast(&(iter_a->first)); + + // insert second pair (a, pointer_to_b) + typename MapB::iterator iter_b = map_b.insert(std::pair(a, ptr_b)).first; + + // update pointer in map_a to point to a + T1* ptr_a = const_cast(&(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 -#include -#include -#include "linux-dist/evdev.h" -#include "linux-dist/main.h" -#include "cfg/ini.h" -#include -#include -#include - -#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(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(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 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", "").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 -#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 +#include +#include +#include +#include + +#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 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 +#include +#include +#include +#include + +#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 -#include -#include -#include -#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 #include "hw/sh4/dyna/blockmanager.h" #include +#include "proxy.h" #if defined(TARGET_EMSCRIPTEN) #include @@ -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::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(code, is_inverted)); + } +} + +void InputMapping::load(FILE* fd) +{ + ConfigFile mf; + mf.parse(fd); + + this->name = mf.get("emulator", "mapping_name", "").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 +#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 buttons; + SimpleBimap axes; + std::map 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 + +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(full_filepath, mapping)); + } + } + std::map::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 + +class InputMappingStore +{ + private: + std::map 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(port, handler)); + } +} + +void InputHandlerProxy::handle(u32 port) +{ + std::pair 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 +#include "types.h" +#include "handler.h" + +class InputHandlerProxy +{ + typedef std::multimap 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;