/* RetroArch - A frontend for libretro. * Copyright (C) 2010-2014 - Hans-Kristian Arntzen * Copyright (C) 2011-2017 - Daniel De Matteis * Copyright (C) 2016-2017 - Andrés Suárez * * RetroArch is free software: you can redistribute it and/or modify it under the terms * of the GNU General Public License as published by the Free Software Found- * ation, either version 3 of the License, or (at your option) any later version. * * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along with RetroArch. * If not, see . */ #include #include #include #ifdef _WIN32 #include #else #include #endif #include #include #include #include #ifdef HAVE_MENU #include "../menu/menu_driver.h" #endif #ifdef HAVE_CONFIG_H #include "../config.h" #endif #include "input_mapper.h" #ifdef HAVE_OVERLAY #include "input_overlay.h" #endif #include "../configuration.h" #include "../msg_hash.h" #include "../verbosity.h" #define MAPPER_GET_KEY(state, key) (((state)->keys[(key) / 32] >> ((key) % 32)) & 1) #define MAPPER_SET_KEY(state, key) (state)->keys[(key) / 32] |= 1 << ((key) % 32) struct input_mapper { /* Left X, Left Y, Right X, Right Y */ int16_t analog_value[MAX_USERS][8]; /* the whole keyboard state */ uint32_t keys[RETROK_LAST / 32 + 1]; /* This is a bitmask of (1 << key_bind_id). */ input_bits_t buttons[MAX_USERS]; }; static bool input_mapper_button_pressed(input_mapper_t *handle, unsigned port, unsigned id) { return BIT256_GET(handle->buttons[port], id); } input_mapper_t *input_mapper_new(void) { input_mapper_t* handle = (input_mapper_t*) calloc(1, sizeof(*handle)); if (!handle) return NULL; return handle; } void input_mapper_free(input_mapper_t *handle) { if (!handle) return; free (handle); } void input_mapper_poll(input_mapper_t *handle) { unsigned i, j; input_bits_t current_input; settings_t *settings = config_get_ptr(); unsigned max_users = *(input_driver_get_uint(INPUT_ACTION_MAX_USERS)); bool key_event[RARCH_CUSTOM_BIND_LIST_END] = { false }; #ifdef HAVE_OVERLAY bool poll_overlay = input_overlay_is_alive(overlay_ptr) ? true : false; #endif #ifdef HAVE_MENU if (menu_driver_is_alive()) return; #endif memset(handle->keys, 0, sizeof(handle->keys)); for (i = 0; i < max_users; i++) { unsigned device = settings->uints.input_libretro_device[i]; device &= RETRO_DEVICE_MASK; switch (device) { /* keyboard to gamepad remapping */ case RETRO_DEVICE_KEYBOARD: BIT256_CLEAR_ALL_PTR(¤t_input); input_get_state_for_port(settings, i, ¤t_input); for (j = 0; j < RARCH_CUSTOM_BIND_LIST_END; j++) { unsigned remap_button = settings->uints.input_keymapper_ids[i][j]; bool remap_valid = remap_button != RETROK_UNKNOWN; if (remap_valid) { unsigned current_button_value = BIT256_GET(current_input, j); #ifdef HAVE_OVERLAY if (poll_overlay && i == 0) current_button_value |= input_overlay_key_pressed(overlay_ptr, j); #endif if ((current_button_value == 1) && (j != remap_button)) { MAPPER_SET_KEY (handle, remap_button); input_keyboard_event(true, remap_button, 0, 0, RETRO_DEVICE_KEYBOARD); key_event[j] = true; } /* key_event tracks if a key is pressed for ANY PLAYER, so we must check if the key was used by any player before releasing */ else if (!key_event[j]) { input_keyboard_event(false, remap_button, 0, 0, RETRO_DEVICE_KEYBOARD); } } } break; /* gamepad remapping */ case RETRO_DEVICE_JOYPAD: case RETRO_DEVICE_ANALOG: /* this loop iterates on all users and all buttons, * and checks if a pressed button is assigned to any * other button than the default one, then it sets * the bit on the mapper input bitmap, later on the * original input is cleared in input_state */ BIT256_CLEAR_ALL(handle->buttons[i]); BIT256_CLEAR_ALL_PTR(¤t_input); for (j = 0; j < 8; j++) handle->analog_value[i][j] = 0; input_get_state_for_port(settings, i, ¤t_input); for (j = 0; j < RARCH_FIRST_CUSTOM_BIND; j++) { bool remap_valid; unsigned remap_button; unsigned current_button_value = BIT256_GET(current_input, j); #ifdef HAVE_OVERLAY if (poll_overlay && i == 0) current_button_value |= input_overlay_key_pressed(overlay_ptr, j); #endif remap_button = settings->uints.input_remap_ids[i][j]; remap_valid = (current_button_value == 1) && (j != remap_button) && (remap_button != RARCH_UNMAPPED); if (remap_valid) { if (remap_button < RARCH_FIRST_CUSTOM_BIND) { BIT256_SET(handle->buttons[i], remap_button); } else if (remap_button >= RARCH_FIRST_CUSTOM_BIND) { int invert = 1; if (remap_button % 2 != 0) invert = -1; handle->analog_value[i][ remap_button - RARCH_FIRST_CUSTOM_BIND] = (current_input.analog_buttons[j] ? current_input.analog_buttons[j] : 32767) * invert; } } } for (j = 0; j < 8; j++) { unsigned k = j + RARCH_FIRST_CUSTOM_BIND; int16_t current_axis_value = current_input.analogs[j]; unsigned remap_axis = settings->uints.input_remap_ids[i][k]; if ( (abs(current_axis_value) > 0 && (k != remap_axis) && (remap_axis != RARCH_UNMAPPED) )) { if (remap_axis < RARCH_FIRST_CUSTOM_BIND && abs(current_axis_value) > *input_driver_get_float(INPUT_ACTION_AXIS_THRESHOLD) * 32767) { BIT256_SET(handle->buttons[i], remap_axis); } else { int invert = 1; unsigned remap_axis_bind = remap_axis - RARCH_FIRST_CUSTOM_BIND; if ( (k % 2 == 0 && remap_axis % 2 != 0) || (k % 2 != 0 && remap_axis % 2 == 0) ) invert = -1; if (remap_axis_bind < sizeof(handle->analog_value[i])) { handle->analog_value[i][ remap_axis_bind] = current_axis_value * invert; } #if 0 RARCH_LOG("axis %d(%d) remapped to axis %d val %d\n", j, k, remap_axis - RARCH_FIRST_CUSTOM_BIND, current_axis_value); #endif } } } break; default: break; } } } void input_mapper_state( input_mapper_t *handle, int16_t *ret, unsigned port, unsigned device, unsigned idx, unsigned id) { if (!handle) return; switch (device) { case RETRO_DEVICE_JOYPAD: if (input_mapper_button_pressed(handle, port, id)) *ret = 1; break; case RETRO_DEVICE_ANALOG: if (idx < 2 && id < 2) { int val = 0; unsigned offset = 0 + (idx * 4) + (id * 2); int val1 = handle->analog_value[port][offset]; int val2 = handle->analog_value[port][offset+1]; if (val1) val = val1; else if (val2) val = val2; if (val1 || val2) *ret |= val; } break; case RETRO_DEVICE_KEYBOARD: if (id < RETROK_LAST) if (MAPPER_GET_KEY(handle, id)) *ret |= 1; break; default: break; } return; }