diff --git a/core/input/gamepad_device.cpp b/core/input/gamepad_device.cpp index 6708173f1..fbdbd5500 100644 --- a/core/input/gamepad_device.cpp +++ b/core/input/gamepad_device.cpp @@ -199,8 +199,5 @@ void GamepadDevice::save_mapping() { if (input_mapper == NULL) return; - std::string filename = make_mapping_filename(); - if (!input_mapper->is_dirty()) - return; input_mapper->save(make_mapping_filename().c_str()); } diff --git a/core/input/mapping.cpp b/core/input/mapping.cpp index 674e469f4..bfbb30d76 100644 --- a/core/input/mapping.cpp +++ b/core/input/mapping.cpp @@ -171,7 +171,8 @@ InputMapping *InputMapping::LoadMapping(const char *name) bool InputMapping::save(const char *name) { - if (!is_dirty()) + loaded_mappings[name] = this; + if (!dirty) return true; std::string path = get_writable_config_path("/mappings/"); diff --git a/core/input/mapping.h b/core/input/mapping.h index d30ee4896..da7473d1f 100644 --- a/core/input/mapping.h +++ b/core/input/mapping.h @@ -25,6 +25,14 @@ class InputMapping { public: + InputMapping() {} + InputMapping(const InputMapping& other) { + name = other.name; + buttons = other.buttons; + axes = other.axes; + axes_inverted = other.axes_inverted; + } + std::string name; DreamcastKey get_button_id(u32 code) @@ -65,7 +73,7 @@ public: static InputMapping *LoadMapping(const char *name); protected: - bool dirty; + bool dirty = false; private: std::map buttons; @@ -88,6 +96,5 @@ public: set_axis(DC_AXIS_RT, DC_AXIS_RT, false); set_axis(DC_AXIS_X2, DC_AXIS_X2, false); set_axis(DC_AXIS_Y2, DC_AXIS_Y2, false); - dirty = false; } }; diff --git a/core/linux-dist/evdev.cpp b/core/linux-dist/evdev.cpp index 684fee15b..4712e8034 100644 --- a/core/linux-dist/evdev.cpp +++ b/core/linux-dist/evdev.cpp @@ -1,721 +1,222 @@ +#if defined(USE_EVDEV) + #include #include #include -#include "linux-dist/evdev.h" -#include "linux-dist/main.h" -#include "hw/maple/maple_devs.h" -#include "cfg/cfg.h" -#include "cfg/ini.h" -#include "rend/gui.h" -#include "input/gamepad.h" -#include -#include -#include +#ifdef USE_UDEV +#include +#endif +#include "evdev.h" +#include "evdev_gamepad.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; +#define EVDEV_DEVICE_STRING "/dev/input/event%d" - /* evdev input */ - static EvdevController evdev_controllers[4] = { - { -1, NULL }, - { -1, NULL }, - { -1, NULL }, - { -1, NULL } - }; +static int maple_port = 0; - void dc_stop(void); - bool dc_loadstate(void); - bool dc_savestate(void); - - void load_libevdev() +static void input_evdev_add_device(const char *devnode) +{ + int fd = open(devnode, O_RDWR); + if (fd >= 0) { - if (libevdev_tried) - return; - - libevdev_tried = true; - void* lib_handle = dlopen("libevdev.so.2", RTLD_NOW); - if (!lib_handle) // libevdev.so.2 not found, fallback to libevdev.so - 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; + new EvdevGamepadDevice(maple_port, devnode, fd); + if (maple_port < 3) + maple_port++; } +} - s8 EvdevAxisData::convert(s32 value) +static void input_evdev_remove_device(const char *devnode) +{ + EvdevGamepadDevice *gamepad = EvdevGamepadDevice::GetControllerForDevnode(devnode); + if (gamepad != NULL) { - return (((value - min) * 255) / range); + maple_port = gamepad->maple_port(); // Reuse the maple port for the next device connected + delete gamepad; } +} - 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; - } - } +#ifdef USE_UDEV +static struct udev* udev; +static struct udev_monitor* udev_monitor; - 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); - this->rumble_effect_id = -1; - } +static bool is_joystick(struct udev_device *udev_device) +{ + const char* devnode = udev_device_get_devnode(udev_device); + if (devnode == NULL || strncmp("/dev/input/event", devnode, 16)) + return false; - MapleDeviceType GetMapleDeviceType(int value, int port) - { - switch (value) - { - case 0: - #if defined(_DEBUG) || defined(DEBUG) - printf("Maple Device: None\n"); - #endif - return MDT_None; - case 1: - #if defined(_DEBUG) || defined(DEBUG) - printf("Maple Device: VMU\n"); - #endif - return MDT_SegaVMU; - case 2: - #if defined(_DEBUG) || defined(DEBUG) - printf("Maple Device: Microphone\n"); - #endif - return MDT_Microphone; - case 3: - #if defined(_DEBUG) || defined(DEBUG) - printf("Maple Device: PuruPuruPack\n"); - #endif - return MDT_PurupuruPack; - default: - MapleDeviceType result = MDT_None; - string result_type = "None"; - - // Controller in port 0 (player1) defaults to VMU for Maple device, all other to None - if (port == 0) - { - result_type = "VMU"; - result = MDT_SegaVMU; - } - - printf("Unsupported configuration (%d) for Maple Device, using %s\n", value, result_type.c_str()); - return result; - } - } - - 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); - } - } - else - { - 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); - } - } - } - - //if (code < 0) - // printf("WARNING: %s/%s not configured!\n", section.c_str(), dc_key.c_str()); - - return code; - } - - EvdevControllerMapping load_mapping(FILE* fd) - { - ConfigFile mf; - mf.parse(fd); - - EvdevControllerMapping mapping = { - mf.get("emulator", "mapping_name", ""), - 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, "emulator", "btn_menu"), - load_keycode(&mf, "emulator", "btn_loadstate"), - load_keycode(&mf, "emulator", "btn_savestate"), - 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), - mf.get_int("dreamcast", "maple_device1", -1), - mf.get_int("dreamcast", "maple_device2", -1) - }; - return mapping; - } - - bool input_evdev_button_assigned(EvdevControllerMapping* mapping, int button) - { - // Don't check unassigned buttons - if (button == -1) - return false; - - return ((mapping->Btn_A == button) - || (mapping->Btn_B == button) - || (mapping->Btn_C == button) - || (mapping->Btn_D == button) - || (mapping->Btn_X == button) - || (mapping->Btn_Y == button) - || (mapping->Btn_Z == button) - || (mapping->Btn_Start == button) - || (mapping->Btn_Escape == button) - || (mapping->Btn_Menu == button) - || (mapping->Btn_LoadState == button) - || (mapping->Btn_SaveState == button) - || (mapping->Btn_DPad_Left == button) - || (mapping->Btn_DPad_Right == button) - || (mapping->Btn_DPad_Up == button) - || (mapping->Btn_DPad_Down == button) - || (mapping->Btn_DPad2_Left == button) - || (mapping->Btn_DPad2_Right == button) - || (mapping->Btn_DPad2_Up == button) - || (mapping->Btn_DPad2_Down == button) - || (mapping->Btn_Trigger_Left == button) - || (mapping->Btn_Trigger_Right == button)); - } - - bool input_evdev_button_duplicate_button(EvdevControllerMapping* mapping1, EvdevControllerMapping* mapping2) - { - return (input_evdev_button_assigned(mapping1, mapping2->Btn_A) - || input_evdev_button_assigned(mapping1, mapping2->Btn_B) - || input_evdev_button_assigned(mapping1, mapping2->Btn_C) - || input_evdev_button_assigned(mapping1, mapping2->Btn_D) - || input_evdev_button_assigned(mapping1, mapping2->Btn_X) - || input_evdev_button_assigned(mapping1, mapping2->Btn_Y) - || input_evdev_button_assigned(mapping1, mapping2->Btn_Z) - || input_evdev_button_assigned(mapping1, mapping2->Btn_Start) - || input_evdev_button_assigned(mapping1, mapping2->Btn_Escape) - || input_evdev_button_assigned(mapping1, mapping2->Btn_Menu) - || input_evdev_button_assigned(mapping1, mapping2->Btn_LoadState) - || input_evdev_button_assigned(mapping1, mapping2->Btn_SaveState) - || input_evdev_button_assigned(mapping1, mapping2->Btn_DPad_Left) - || input_evdev_button_assigned(mapping1, mapping2->Btn_DPad_Right) - || input_evdev_button_assigned(mapping1, mapping2->Btn_DPad_Up) - || input_evdev_button_assigned(mapping1, mapping2->Btn_DPad_Down) - || input_evdev_button_assigned(mapping1, mapping2->Btn_DPad2_Left) - || input_evdev_button_assigned(mapping1, mapping2->Btn_DPad2_Right) - || input_evdev_button_assigned(mapping1, mapping2->Btn_DPad2_Up) - || input_evdev_button_assigned(mapping1, mapping2->Btn_DPad2_Down) - || input_evdev_button_assigned(mapping1, mapping2->Btn_Trigger_Left) - || input_evdev_button_assigned(mapping1, mapping2->Btn_Trigger_Right)); - } - - 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_RDWR); - - 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) - { - // custom mapping defined in config, use that - mapping_fname = custom_mapping_fname; - //printf("evdev: user defined custom mapping found (%s)\n", custom_mapping_fname); - } - else - { - #if defined(TARGET_PANDORA) - mapping_fname = "controller_pandora.cfg"; - #elif defined(TARGET_GCW0) - mapping_fname = "controller_gcwz.cfg"; - #else - // check if a config file name .cfg exists in the /mappings/ directory - char* name_cfg = (char*)malloc(strlen(name)+4); - strcpy(name_cfg, name); - strcat(name_cfg, ".cfg"); - - size_t size_needed = snprintf(NULL, 0, EVDEV_MAPPING_PATH, name_cfg) + 1; - char* mapping_path = (char*)malloc(size_needed); - sprintf(mapping_path, EVDEV_MAPPING_PATH, name_cfg); - - string dir = get_readonly_data_path(mapping_path); - free(mapping_path); - if (file_exists(dir)) { - //printf("evdev: found a named mapping for the device (%s)\n", name_cfg); - mapping_fname = name_cfg; - } - else { - free(name_cfg); - - 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.find(string(mapping_fname))->second; - printf("evdev: Using '%s' mapping\n", controller->mapping->name.c_str()); - controller->init(); - - return 0; - } - } - else - { - perror(device); - return -1; - } - } - - void input_evdev_init() - { - int evdev_device_id[4] = { -1, -1, -1, -1 }; - size_t size_needed; - int port, i; - - char* evdev_device; - - for (port = 0; port < 4; port++) - { - size_needed = snprintf(NULL, 0, EVDEV_DEVICE_CONFIG_KEY, port+1) + 1; - char* 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)); - free(evdev_config_key); - - // Check if the same device is already in use on another port - if (evdev_device_id[port] < 0) - { - printf("evdev: Controller %d disabled by config.\n", port + 1); - } - else - { - 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); - - string tmp; - const char* mapping = (cfgExists("input", evdev_config_key) == 2 ? (tmp = cfgLoadStr("input", evdev_config_key, "")).c_str() : NULL); - free(evdev_config_key); - - int err = input_evdev_init(&evdev_controllers[port], evdev_device, mapping); - - free(evdev_device); - - // If there was an error initializing the controller, don't proceed any further - if (err == 0) - { - for (i = 0; i < port; i++) - { - // If the controller could not be loaded, skip this one as it can't interfere - if (evdev_controllers[i].fd < 0) - continue; - - if (evdev_device_id[port] == evdev_device_id[i]) - { - // Multiple controllers with the same device, check for multiple button assignments - if (input_evdev_button_duplicate_button(evdev_controllers[i].mapping, evdev_controllers[port].mapping)) - { - printf("WARNING: One or more button(s) of this device is also used in the configuration of input device %d (mapping: %s)\n", i, - evdev_controllers[i].mapping->name.c_str()); - } - } - } - } - } - } - } - - void input_evdev_close() - { - for (int port = 0; port < 4 ; port++) - { - if (evdev_controllers[port].fd >= 0) - { - close(evdev_controllers[port].fd); - } - } - } - - bool input_evdev_handle(u32 port) - { - EvdevController* controller = &evdev_controllers[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) { - dc_stop(); - } else if (ie.code == controller->mapping->Btn_Menu && port == 0) { - gui_open_settings(); - } else if (ie.code == controller->mapping->Btn_LoadState) { - dc_loadstate(); - } else if (ie.code == controller->mapping->Btn_SaveState) { - dc_savestate(); - } 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; - } - } + if (udev_device_get_property_value(udev_device, "ID_INPUT_JOYSTICK")) return true; - } + if (udev_device_get_property_value(udev_device, "ID_INPUT_ACCELEROMETER") + || udev_device_get_property_value(udev_device, "ID_INPUT_KEY") + || udev_device_get_property_value(udev_device, "ID_INPUT_KEYBOARD") + || udev_device_get_property_value(udev_device, "ID_INPUT_MOUSE") + || udev_device_get_property_value(udev_device, "ID_INPUT_TABLET") + || udev_device_get_property_value(udev_device, "ID_INPUT_TOUCHPAD") + || udev_device_get_property_value(udev_device, "ID_INPUT_TOUCHSCREEN")) + return false; - void input_evdev_rumble(u32 port, u16 pow_strong, u16 pow_weak) + // On some platforms (older udev), ID_INPUT_ properties are not present, instead + // the system makes use of the ID_CLASS property to identify the device class + const char* id_class = udev_device_get_property_value(udev_device, "ID_CLASS"); + if (id_class == NULL) + return false; + if (strstr(id_class, "joystick") != NULL) + return true; + if (strstr(id_class, "accelerometer") != NULL + || strstr(id_class, "key") != NULL + || strstr(id_class, "keyboard") != NULL + || strstr(id_class, "mouse") != NULL + || strstr(id_class, "tablet") != NULL + || strstr(id_class, "touchpad") != NULL + || strstr(id_class, "touchscreen") != NULL) + return false; + + return false; // Not sure here. Could it still be a joystick after all? +} + +static void get_udev_events() +{ + if (udev == NULL) { - EvdevController* controller = &evdev_controllers[port]; - - if (controller->fd < 0 || controller->rumble_effect_id == -2) + udev = udev_new(); + // Create the monitor before doing the enumeration + udev_monitor = udev_monitor_new_from_netlink(udev, "udev"); + if (udev_monitor == NULL) { - // Either the controller is not used or previous rumble effect failed - printf("RUMBLE: %s\n", "Skipped!"); - return; - } - printf("RUMBLE: %u / %u (%d)\n", pow_strong, pow_weak, controller->rumble_effect_id); - struct ff_effect effect; - effect.type = FF_RUMBLE; - effect.id = controller->rumble_effect_id; - effect.u.rumble.strong_magnitude = pow_strong; - effect.u.rumble.weak_magnitude = pow_weak; - effect.replay.length = 0; - effect.replay.delay = 0; - if (ioctl(controller->fd, EVIOCSFF, &effect) == -1) - { - perror("evdev: Force feedback error"); - controller->rumble_effect_id = -2; + perror("Controller hot-plugging disabled"); } else { - controller->rumble_effect_id = effect.id; - - // Let's play the effect - input_event play; - play.type = EV_FF; - play.code = effect.id; - play.value = 1; - if (write(controller->fd, (const void*) &play, sizeof(play)) == -1) + udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "input", NULL); + udev_monitor_enable_receiving(udev_monitor); + } + // Enumerate all joystick devices + struct udev_enumerate* enumerator = udev_enumerate_new(udev); + if (udev_enumerate_add_match_subsystem(enumerator, "input") != 0) { + perror("udev_enumerate_add_match_subsystem"); + udev_monitor_unref(udev_monitor); + udev_unref(udev); + udev = NULL; + return; + } + if (udev_enumerate_scan_devices(enumerator) != 0) { + perror("udev_enumerate_scan_devices"); + udev_monitor_unref(udev_monitor); + udev_enumerate_unref(enumerator); + udev_unref(udev); + udev = NULL; + return; + } + udev_list_entry* devices = udev_enumerate_get_list_entry(enumerator); + udev_list_entry* device; + udev_list_entry_foreach(device, devices) { + const char* syspath = udev_list_entry_get_name(device); + udev_device* udev_device = udev_device_new_from_syspath(udev, syspath); + if (udev_device != NULL) { - perror("evdev: Force feedback error"); - controller->rumble_effect_id = -2; + if (is_joystick(udev_device)) + { + const char* devnode = udev_device_get_devnode(udev_device); + input_evdev_add_device(devnode); + } + udev_device_unref(udev_device); } } + udev_enumerate_unref(enumerator); + } + if (udev_monitor != NULL) + { + int monitor_fd = udev_monitor_get_fd(udev_monitor); + fd_set set; + FD_ZERO(&set); + FD_SET(monitor_fd, &set); + timeval timeout = {0, 0}; + + if (select(monitor_fd + 1, &set, NULL, NULL, &timeout) > 0 && FD_ISSET(monitor_fd, &set)) + { + // event detected + udev_device* udev_device = udev_monitor_receive_device(udev_monitor); + if (udev_device != NULL) + { + if (is_joystick(udev_device)) + { + const char* devnode = udev_device_get_devnode(udev_device); + const char* action = udev_device_get_action(udev_device); + if (action != NULL && devnode != NULL) + { + if (strstr(action, "add") != NULL) + { + //printf("udev monitor: device added %s\n", devnode); + input_evdev_add_device(devnode); + } + else if (strstr(action, "remove") != NULL) + { + //printf("udev monitor: device removed %s\n", devnode); + input_evdev_remove_device(devnode); + } + } + } + udev_device_unref(udev_device); + } + } + } +} + +static void udev_term() +{ + if (udev_monitor != NULL) + { + udev_monitor_unref(udev_monitor); + udev_monitor = NULL; + } + if (udev != NULL) + { + udev_unref(udev); + udev = NULL; + } +} +#endif // USE_UDEV + +void input_evdev_init() +{ + maple_port = 0; +#ifdef USE_UDEV + get_udev_events(); +#else + char buf[32]; + for (int port = 0; port < 100; port++) + { + sprintf(buf, EVDEV_DEVICE_STRING, port); + input_evdev_add_device(buf); } #endif +} + +void input_evdev_close() +{ +#ifdef USE_UDEV + udev_term(); +#endif + EvdevGamepadDevice::CloseDevices(); +} + +// FIXME this shouldn't be done by port. Need something like: handle_events() then get_port(0), get_port(2), ... +bool input_evdev_handle(u32 port) +{ +#ifdef USE_UDEV + get_udev_events(); +#endif + EvdevGamepadDevice::PollDevices(); + return true; +} + +void input_evdev_rumble(u32 port, u16 pow_strong, u16 pow_weak) +{ + EvdevGamepadDevice *dev = EvdevGamepadDevice::GetControllerForPort(port); + if (dev != NULL) + dev->Rumble(pow_strong, pow_weak); +} + + +#endif // USE_EVDEV diff --git a/core/linux-dist/evdev.h b/core/linux-dist/evdev.h index a4e91f32b..61b6de252 100644 --- a/core/linux-dist/evdev.h +++ b/core/linux-dist/evdev.h @@ -1,81 +1,6 @@ #pragma once -#include #include "types.h" -struct EvdevControllerMapping -{ - const string 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_Menu; - const int Btn_LoadState; - const int Btn_SaveState; - 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; - const int Maple_Device1; - const int Maple_Device2; -}; - -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; - int rumble_effect_id; - 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 void input_evdev_init(); extern void input_evdev_close(); extern bool input_evdev_handle(u32 port); diff --git a/core/rend/gui.cpp b/core/rend/gui.cpp index c4bb43995..be3ad901d 100644 --- a/core/rend/gui.cpp +++ b/core/rend/gui.cpp @@ -186,16 +186,16 @@ static void ImGui_Impl_NewFrame() io.NavInputs[ImGuiNavInput_DpadUp] = (kcode[0] & DC_DPAD_UP) == 0; io.NavInputs[ImGuiNavInput_DpadDown] = (kcode[0] & DC_DPAD_DOWN) == 0; io.NavInputs[ImGuiNavInput_LStickLeft] = joyx[0] < 0 ? -(float)joyx[0] / 128 : 0.f; - if (io.NavInputs[ImGuiNavInput_LStickLeft] < 0.05f) + if (io.NavInputs[ImGuiNavInput_LStickLeft] < 0.1f) io.NavInputs[ImGuiNavInput_LStickLeft] = 0.f; io.NavInputs[ImGuiNavInput_LStickRight] = joyx[0] > 0 ? (float)joyx[0] / 128 : 0.f; - if (io.NavInputs[ImGuiNavInput_LStickRight] < 0.05f) + if (io.NavInputs[ImGuiNavInput_LStickRight] < 0.1f) io.NavInputs[ImGuiNavInput_LStickRight] = 0.f; io.NavInputs[ImGuiNavInput_LStickUp] = joyy[0] < 0 ? -(float)joyy[0] / 128.f : 0.f; - if (io.NavInputs[ImGuiNavInput_LStickUp] < 0.05f) + if (io.NavInputs[ImGuiNavInput_LStickUp] < 0.1f) io.NavInputs[ImGuiNavInput_LStickUp] = 0.f; io.NavInputs[ImGuiNavInput_LStickDown] = joyy[0] > 0 ? (float)joyy[0] / 128.f : 0.f; - if (io.NavInputs[ImGuiNavInput_LStickDown] < 0.05f) + if (io.NavInputs[ImGuiNavInput_LStickDown] < 0.1f) io.NavInputs[ImGuiNavInput_LStickDown] = 0.f; } diff --git a/core/sdl/sdl_gamepad.h b/core/sdl/sdl_gamepad.h index bcccfc3c8..89c618733 100644 --- a/core/sdl/sdl_gamepad.h +++ b/core/sdl/sdl_gamepad.h @@ -1,6 +1,5 @@ #include "../input/gamepad_device.h" #include "sdl.h" -#include "rend/gui.h" class DefaultInputMapping : public InputMapping { diff --git a/shell/linux/Makefile b/shell/linux/Makefile index 4de634d57..766bd1f7d 100644 --- a/shell/linux/Makefile +++ b/shell/linux/Makefile @@ -7,6 +7,7 @@ USE_OSS := 1 #USE_PULSEAUDIO := 1 #USE_LIBAO := 1 USE_EVDEV := 1 +USE_UDEV := 1 PLATFORM_EXT := elf CXX=${CC_PREFIX}g++ @@ -27,6 +28,7 @@ CXXFLAGS := ifneq (, $(filter $(shell uname -s), FreeBSD OpenBSD NetBSD DragonFly)) CFLAGS += -DTARGET_BSD + undefine USE_UDEV else USE_ALSA := 1 # USE_JOYSTICK := 1 @@ -253,6 +255,7 @@ endif undefine USE_ALSA undefine USE_OSS undefine USE_EVDEV + undefine USE_UDEV undefine FOR_LINUX undefine WEBUI NO_NIXPROF := 1 @@ -326,6 +329,10 @@ endif ifdef USE_EVDEV CXXFLAGS += -D USE_EVDEV +ifdef USE_UDEV + CXXFLAGS += -D USE_UDEV + LIBS += -ludev +endif endif ifdef USE_JOYSTICK