mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-08-04 08:22:32 +00:00
Mouse polling, CMakeLists, and basic framework
This commit is contained in:
parent
7a95c27b2c
commit
1884b39eb8
@ -724,6 +724,8 @@ set(IMGUI src/imgui/imgui_config.h
|
||||
|
||||
set(INPUT src/input/controller.cpp
|
||||
src/input/controller.h
|
||||
src/input/input_handler.cpp
|
||||
src/input/input_handler.h
|
||||
)
|
||||
|
||||
set(EMULATOR src/emulator.cpp
|
||||
|
@ -1,7 +1,383 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
namespace InputHandler {
|
||||
#include "input_handler.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <SDL3/SDL_events.h>
|
||||
#include <SDL3/SDL_timer.h>
|
||||
|
||||
#include "common/config.h"
|
||||
#include "common/io_file.h"
|
||||
#include "common/path_util.h"
|
||||
#include "common/version.h"
|
||||
#include "common/elf_info.h"
|
||||
#include "input/controller.h"
|
||||
|
||||
namespace Input {
|
||||
/*
|
||||
Project structure:
|
||||
n to m connection between inputs and outputs
|
||||
Keyup and keydown events update a dynamic list* of u32 'flags' (what is currently in the list is 'pressed')
|
||||
On every event, after flag updates, we check for every input binding -> controller output pair if all their flags are 'on'
|
||||
If not, disable; if so, enable them.
|
||||
For axes, we gather their data into a struct cumulatively from all inputs,
|
||||
then after we checked all of those, we update them all at once.
|
||||
Wheel inputs generate a timer that doesn't turn off their outputs automatically, but push a userevent to do so.
|
||||
|
||||
What structs are needed?
|
||||
InputBinding(key1, key2, key3)
|
||||
ControllerOutput(button, axis) - we only need a const array of these, and one of the attr-s is always 0
|
||||
BindingConnection(inputBinding (member), controllerOutput (ref to the array element))
|
||||
*/
|
||||
|
||||
// Flags and values for varying purposes
|
||||
// todo: can we change these?
|
||||
int mouse_joystick_binding = 0;
|
||||
float mouse_deadzone_offset = 0.5, mouse_speed = 1, mouse_speed_offset = 0.1250;
|
||||
Uint32 mouse_polling_id = 0;
|
||||
bool mouse_enabled = false, leftjoystick_halfmode = false, rightjoystick_halfmode = false;
|
||||
|
||||
std::string_view getDefaultKeyboardConfig() {
|
||||
static std::string_view default_config =
|
||||
R"(## SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
## SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#This is the default keybinding config
|
||||
#To change per-game configs, modify the CUSAXXXXX.ini files
|
||||
#To change the default config that applies to new games without already existing configs, modify default.ini
|
||||
#If you don't like certain mappings, delete, change or comment them out.
|
||||
#You can add any amount of KBM keybinds to a single controller input,
|
||||
#but you can use each KBM keybind for one controller input.
|
||||
|
||||
#Keybinds used by the emulator (these are unchangeable):
|
||||
#F11 : fullscreen
|
||||
#F10 : FPS counter
|
||||
#F9 : toggle mouse-to-joystick input
|
||||
# (it overwrites everything else to that joystick, so this is required)
|
||||
#F8 : reparse keyboard input(this)
|
||||
|
||||
#This is a mapping for Bloodborne, inspired by other Souls titles on PC.
|
||||
|
||||
#Specifies which joystick the mouse movement controls.
|
||||
mouse_to_joystick = right;
|
||||
|
||||
#Use healing item, change status in inventory
|
||||
triangle = f;
|
||||
#Dodge, back in inventory
|
||||
circle = space;
|
||||
#Interact, select item in inventory
|
||||
cross = e;
|
||||
#Use quick item, remove item in inventory
|
||||
square = r;
|
||||
|
||||
#Emergency extra bullets
|
||||
up = w, lalt;
|
||||
up = mousewheelup;
|
||||
#Change quick item
|
||||
down = s, lalt;
|
||||
down = mousewheeldown;
|
||||
#Change weapon in left hand
|
||||
left = a, lalt;
|
||||
left = mousewheelleft;
|
||||
#Change weapon in right hand
|
||||
right = d, lalt;
|
||||
right = mousewheelright;
|
||||
#Change into 'inventory mode', so you don't have to hold lalt every time you go into menus
|
||||
modkey_toggle = i, lalt;
|
||||
|
||||
#Menu
|
||||
options = escape;
|
||||
#Gestures
|
||||
touchpad = g;
|
||||
|
||||
#Transform
|
||||
l1 = rightbutton, lshift;
|
||||
#Shoot
|
||||
r1 = leftbutton;
|
||||
#Light attack
|
||||
l2 = rightbutton;
|
||||
#Heavy attack
|
||||
r2 = leftbutton, lshift;
|
||||
#Does nothing
|
||||
l3 = x;
|
||||
#Center cam, lock on
|
||||
r3 = q;
|
||||
r3 = middlebutton;
|
||||
|
||||
#Axis mappings
|
||||
#Move
|
||||
axis_left_x_minus = a;
|
||||
axis_left_x_plus = d;
|
||||
axis_left_y_minus = w;
|
||||
axis_left_y_plus = s;
|
||||
#Change to 'walk mode' by holding the following key:
|
||||
leftjoystick_halfmode = lctrl;
|
||||
)";
|
||||
return default_config;
|
||||
}
|
||||
|
||||
void parseInputConfig(const std::string game_id = "") {
|
||||
// Read configuration file of the game, and if it doesn't exist, generate it from default
|
||||
// If that doesn't exist either, generate that from getDefaultConfig() and try again
|
||||
// If even the folder is missing, we start with that.
|
||||
|
||||
// maybe extract this?
|
||||
const auto config_dir = Common::FS::GetUserPath(Common::FS::PathType::UserDir) / "kbmConfig";
|
||||
const auto config_file = config_dir / (game_id + ".ini");
|
||||
const auto default_config_file = config_dir / "default.ini";
|
||||
|
||||
// Ensure the config directory exists
|
||||
if (!std::filesystem::exists(config_dir)) {
|
||||
std::filesystem::create_directories(config_dir);
|
||||
}
|
||||
|
||||
// Try loading the game-specific config file
|
||||
if (!std::filesystem::exists(config_file)) {
|
||||
// If game-specific config doesn't exist, check for the default config
|
||||
if (!std::filesystem::exists(default_config_file)) {
|
||||
// If the default config is also missing, create it from getDefaultConfig()
|
||||
const auto default_config = getDefaultKeyboardConfig();
|
||||
std::ofstream default_config_stream(default_config_file);
|
||||
if (default_config_stream) {
|
||||
default_config_stream << default_config;
|
||||
}
|
||||
}
|
||||
|
||||
// If default config now exists, copy it to the game-specific config file
|
||||
if (std::filesystem::exists(default_config_file) && !game_id.empty()) {
|
||||
std::filesystem::copy(default_config_file, config_file);
|
||||
}
|
||||
}
|
||||
// if we just called the function to generate the directory and the default .ini
|
||||
if (game_id.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// we reset these here so in case the user fucks up or doesn't include this we can fall back to
|
||||
// default
|
||||
mouse_deadzone_offset = 0.5;
|
||||
mouse_speed = 1;
|
||||
mouse_speed_offset = 0.125;
|
||||
//old_button_map.clear();
|
||||
//old_axis_map.clear();
|
||||
//old_key_to_modkey_toggle_map.clear();
|
||||
int lineCount = 0;
|
||||
|
||||
std::ifstream file(config_file);
|
||||
std::string line = "";
|
||||
while (std::getline(file, line)) {
|
||||
lineCount++;
|
||||
// strip the ; and whitespace
|
||||
line.erase(std::remove(line.begin(), line.end(), ' '), line.end());
|
||||
if (line[line.length() - 1] == ';') {
|
||||
line = line.substr(0, line.length() - 1);
|
||||
}
|
||||
// Ignore comment lines
|
||||
if (line.empty() || line[0] == '#') {
|
||||
continue;
|
||||
}
|
||||
// Split the line by '='
|
||||
std::size_t equal_pos = line.find('=');
|
||||
if (equal_pos == std::string::npos) {
|
||||
std::cerr << "Invalid line format at line: " << lineCount << " data: " << line
|
||||
<< std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string before_equals = line.substr(0, equal_pos);
|
||||
std::string after_equals = line.substr(equal_pos + 1);
|
||||
std::size_t comma_pos = after_equals.find(',');
|
||||
|
||||
// new data type construcor here
|
||||
// todo
|
||||
|
||||
// special check for mouse to joystick input
|
||||
if (before_equals == "mouse_to_joystick") {
|
||||
if (after_equals == "left") {
|
||||
mouse_joystick_binding = 1;
|
||||
} else if (after_equals == "right") {
|
||||
mouse_joystick_binding = 2;
|
||||
} else {
|
||||
mouse_joystick_binding = 0; // default to 'none' or invalid
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// mod key toggle
|
||||
if (before_equals == "modkey_toggle") {
|
||||
if (comma_pos != std::string::npos) {
|
||||
// handle key-to-key toggling (separate list?)
|
||||
// todo
|
||||
}
|
||||
std::cerr << "Invalid line format at line: " << lineCount << " data: " << line
|
||||
<< std::endl;
|
||||
continue;
|
||||
}
|
||||
// todo
|
||||
/* og parsing
|
||||
// first we parse the binding, and if its wrong, we skip to the next line
|
||||
if (comma_pos != std::string::npos) {
|
||||
// Handle key + modifier
|
||||
std::string key = after_equals.substr(0, comma_pos);
|
||||
std::string mod = after_equals.substr(comma_pos + 1);
|
||||
|
||||
auto key_it = string_to_keyboard_key_map.find(key);
|
||||
auto mod_it = string_to_keyboard_mod_key_map.find(mod);
|
||||
|
||||
if (key_it != string_to_keyboard_key_map.end() &&
|
||||
mod_it != string_to_keyboard_mod_key_map.end()) {
|
||||
binding.key = key_it->second;
|
||||
binding.modifier = mod_it->second;
|
||||
} else if (before_equals == "mouse_movement_params") {
|
||||
// handle mouse movement params
|
||||
float p1 = 0.5, p2 = 1, p3 = 0.125;
|
||||
std::size_t second_comma_pos = after_equals.find(',');
|
||||
try {
|
||||
p1 = std::stof(key);
|
||||
p2 = std::stof(mod.substr(0, second_comma_pos));
|
||||
p3 = std::stof(mod.substr(second_comma_pos + 1));
|
||||
mouse_deadzone_offset = p1;
|
||||
mouse_speed = p2;
|
||||
mouse_speed_offset = p3;
|
||||
} catch (...) {
|
||||
// fallback to default values
|
||||
mouse_deadzone_offset = 0.5;
|
||||
mouse_speed = 1;
|
||||
mouse_speed_offset = 0.125;
|
||||
std::cerr << "Parsing error while parsing kbm inputs at line " << lineCount
|
||||
<< " line data: " << line << "\n";
|
||||
}
|
||||
continue;
|
||||
} else {
|
||||
std::cerr << "Syntax error while parsing kbm inputs at line " << lineCount
|
||||
<< " line data: " << line << "\n";
|
||||
continue; // skip
|
||||
}
|
||||
} else {
|
||||
// Just a key without modifier
|
||||
auto key_it = string_to_keyboard_key_map.find(after_equals);
|
||||
if (key_it != string_to_keyboard_key_map.end()) {
|
||||
binding.key = key_it->second;
|
||||
} else {
|
||||
std::cerr << "Syntax error while parsing kbm inputs at line " << lineCount
|
||||
<< " line data: " << line << "\n";
|
||||
continue; // skip
|
||||
}
|
||||
}
|
||||
|
||||
// Check for axis mapping (example: axis_left_x_plus)
|
||||
auto axis_it = string_to_axis_map.find(before_equals);
|
||||
auto button_it = string_to_cbutton_map.find(before_equals);
|
||||
if (axis_it != string_to_axis_map.end()) {
|
||||
old_axis_map[binding] = axis_it->second;
|
||||
} else if (button_it != string_to_cbutton_map.end()) {
|
||||
old_button_map[binding] = button_it->second;
|
||||
} else {
|
||||
std::cerr << "Syntax error while parsing kbm inputs at line " << lineCount
|
||||
<< " line data: " << line << "\n";
|
||||
}
|
||||
*/
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
|
||||
// todo: add an init for this
|
||||
GameController* ControllerOutput::controller = nullptr;
|
||||
void ControllerOutput::setControllerOutputController(GameController* c) {
|
||||
ControllerOutput::controller = c;
|
||||
}
|
||||
|
||||
void ControllerOutput::update(bool pressed, int axis_direction) {
|
||||
float touchpad_x = 0;
|
||||
Input::Axis axis = Input::Axis::AxisMax;
|
||||
if(button != 0){
|
||||
switch (button) {
|
||||
case OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L2:
|
||||
case OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R2:
|
||||
axis = (button == OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R2) ? Input::Axis::TriggerRight
|
||||
: Input::Axis::TriggerLeft;
|
||||
controller->Axis(0, axis, Input::GetAxis(0, 0x80, pressed ? 255 : 0));
|
||||
break;
|
||||
case OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TOUCH_PAD:
|
||||
touchpad_x = Config::getBackButtonBehavior() == "left" ? 0.25f
|
||||
: Config::getBackButtonBehavior() == "right" ? 0.75f
|
||||
: 0.5f;
|
||||
controller->SetTouchpadState(0, true, touchpad_x, 0.5f);
|
||||
controller->CheckButton(0, button, pressed);
|
||||
break;
|
||||
default: // is a normal key
|
||||
controller->CheckButton(0, button, pressed);
|
||||
break;
|
||||
}
|
||||
} else if (axis != Axis::AxisMax) {
|
||||
float multiplier = 1.0;
|
||||
switch (axis) {
|
||||
case Input::Axis::LeftX:
|
||||
case Input::Axis::LeftY:
|
||||
multiplier = leftjoystick_halfmode ? 0.5 : 1.0;
|
||||
break;
|
||||
case Input::Axis::RightX:
|
||||
case Input::Axis::RightY:
|
||||
multiplier = rightjoystick_halfmode ? 0.5 : 1.0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
int output_value = (pressed ? axis_value : 0) * multiplier;
|
||||
int ax = Input::GetAxis(-0x80, 0x80, output_value);
|
||||
controller->Axis(0, axis, ax);
|
||||
} else {
|
||||
LOG_ERROR(Input, "Controller output with no values detected!");
|
||||
}
|
||||
}
|
||||
|
||||
void updateMouse(GameController* controller) {
|
||||
if (!mouse_enabled)
|
||||
return;
|
||||
Axis axis_x, axis_y;
|
||||
switch (mouse_joystick_binding) {
|
||||
case 1:
|
||||
axis_x = Axis::LeftX;
|
||||
axis_y = Axis::LeftY;
|
||||
break;
|
||||
case 2:
|
||||
axis_x = Axis::RightX;
|
||||
axis_y = Axis::RightY;
|
||||
break;
|
||||
case 0:
|
||||
default:
|
||||
return; // no update needed
|
||||
}
|
||||
|
||||
float d_x = 0, d_y = 0;
|
||||
SDL_GetRelativeMouseState(&d_x, &d_y);
|
||||
|
||||
float output_speed =
|
||||
SDL_clamp((sqrt(d_x * d_x + d_y * d_y) + mouse_speed_offset * 128) * mouse_speed,
|
||||
mouse_deadzone_offset * 128, 128.0);
|
||||
|
||||
float angle = atan2(d_y, d_x);
|
||||
float a_x = cos(angle) * output_speed, a_y = sin(angle) * output_speed;
|
||||
|
||||
if (d_x != 0 && d_y != 0) {
|
||||
controller->Axis(0, axis_x, Input::GetAxis(-0x80, 0x80, a_x));
|
||||
controller->Axis(0, axis_y, Input::GetAxis(-0x80, 0x80, a_y));
|
||||
} else {
|
||||
controller->Axis(0, axis_x, Input::GetAxis(-0x80, 0x80, 0));
|
||||
controller->Axis(0, axis_y, Input::GetAxis(-0x80, 0x80, 0));
|
||||
}
|
||||
}
|
||||
|
||||
Uint32 mousePolling(void* param, Uint32 id, Uint32 interval) {
|
||||
auto* data = (GameController*)param;
|
||||
updateMouse(data);
|
||||
return interval;
|
||||
}
|
||||
|
||||
}
|
@ -3,7 +3,284 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace InputHandler {
|
||||
#include "array"
|
||||
#include "map"
|
||||
#include "string"
|
||||
#include "common/types.h"
|
||||
#include "core/libraries/pad/pad.h"
|
||||
#include "input/controller.h"
|
||||
|
||||
#include <SDL3/SDL_events.h>
|
||||
#include <SDL3/SDL_timer.h>
|
||||
|
||||
// +1 and +2 is taken
|
||||
#define SDL_MOUSE_WHEEL_UP SDL_EVENT_MOUSE_WHEEL + 3
|
||||
#define SDL_MOUSE_WHEEL_DOWN SDL_EVENT_MOUSE_WHEEL + 4
|
||||
#define SDL_MOUSE_WHEEL_LEFT SDL_EVENT_MOUSE_WHEEL + 5
|
||||
#define SDL_MOUSE_WHEEL_RIGHT SDL_EVENT_MOUSE_WHEEL + 7
|
||||
|
||||
#define LEFTJOYSTICK_HALFMODE 0x00010000
|
||||
#define RIGHTJOYSTICK_HALFMODE 0x00020000
|
||||
|
||||
namespace Input {
|
||||
using Input::Axis;
|
||||
using Libraries::Pad::OrbisPadButtonDataOffset;
|
||||
|
||||
struct AxisMapping {
|
||||
Axis axis;
|
||||
int value; // Value to set for key press (+127 or -127 for movement)
|
||||
};
|
||||
|
||||
// i strongly suggest you collapse these maps
|
||||
const std::map<std::string, u32> string_to_cbutton_map = {
|
||||
{"triangle", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TRIANGLE},
|
||||
{"circle", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_CIRCLE},
|
||||
{"cross", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_CROSS},
|
||||
{"square", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_SQUARE},
|
||||
{"l1", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L1},
|
||||
{"l2", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L2},
|
||||
{"r1", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R1},
|
||||
{"r2", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R2},
|
||||
{"l3", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L3},
|
||||
{"r3", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R3},
|
||||
{"options", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_OPTIONS},
|
||||
{"touchpad", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TOUCH_PAD},
|
||||
{"up", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_UP},
|
||||
{"down", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_DOWN},
|
||||
{"left", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_LEFT},
|
||||
{"right", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_RIGHT},
|
||||
{"leftjoystick_halfmode", LEFTJOYSTICK_HALFMODE},
|
||||
{"rightjoystick_halfmode", RIGHTJOYSTICK_HALFMODE},
|
||||
};
|
||||
const std::map<std::string, AxisMapping> string_to_axis_map = {
|
||||
{"axis_left_x_plus", {Input::Axis::LeftX, 127}},
|
||||
{"axis_left_x_minus", {Input::Axis::LeftX, -127}},
|
||||
{"axis_left_y_plus", {Input::Axis::LeftY, 127}},
|
||||
{"axis_left_y_minus", {Input::Axis::LeftY, -127}},
|
||||
{"axis_right_x_plus", {Input::Axis::RightX, 127}},
|
||||
{"axis_right_x_minus", {Input::Axis::RightX, -127}},
|
||||
{"axis_right_y_plus", {Input::Axis::RightY, 127}},
|
||||
{"axis_right_y_minus", {Input::Axis::RightY, -127}},
|
||||
};
|
||||
const std::map<std::string, u32> string_to_keyboard_key_map = {
|
||||
{"a", SDLK_A},
|
||||
{"b", SDLK_B},
|
||||
{"c", SDLK_C},
|
||||
{"d", SDLK_D},
|
||||
{"e", SDLK_E},
|
||||
{"f", SDLK_F},
|
||||
{"g", SDLK_G},
|
||||
{"h", SDLK_H},
|
||||
{"i", SDLK_I},
|
||||
{"j", SDLK_J},
|
||||
{"k", SDLK_K},
|
||||
{"l", SDLK_L},
|
||||
{"m", SDLK_M},
|
||||
{"n", SDLK_N},
|
||||
{"o", SDLK_O},
|
||||
{"p", SDLK_P},
|
||||
{"q", SDLK_Q},
|
||||
{"r", SDLK_R},
|
||||
{"s", SDLK_S},
|
||||
{"t", SDLK_T},
|
||||
{"u", SDLK_U},
|
||||
{"v", SDLK_V},
|
||||
{"w", SDLK_W},
|
||||
{"x", SDLK_X},
|
||||
{"y", SDLK_Y},
|
||||
{"z", SDLK_Z},
|
||||
{"0", SDLK_0},
|
||||
{"1", SDLK_1},
|
||||
{"2", SDLK_2},
|
||||
{"3", SDLK_3},
|
||||
{"4", SDLK_4},
|
||||
{"5", SDLK_5},
|
||||
{"6", SDLK_6},
|
||||
{"7", SDLK_7},
|
||||
{"8", SDLK_8},
|
||||
{"9", SDLK_9},
|
||||
{"kp0", SDLK_KP_0},
|
||||
{"kp1", SDLK_KP_1},
|
||||
{"kp2", SDLK_KP_2},
|
||||
{"kp3", SDLK_KP_3},
|
||||
{"kp4", SDLK_KP_4},
|
||||
{"kp5", SDLK_KP_5},
|
||||
{"kp6", SDLK_KP_6},
|
||||
{"kp7", SDLK_KP_7},
|
||||
{"kp8", SDLK_KP_8},
|
||||
{"kp9", SDLK_KP_9},
|
||||
{"comma", SDLK_COMMA},
|
||||
{"period", SDLK_PERIOD},
|
||||
{"question", SDLK_QUESTION},
|
||||
{"semicolon", SDLK_SEMICOLON},
|
||||
{"minus", SDLK_MINUS},
|
||||
{"underscore", SDLK_UNDERSCORE},
|
||||
{"lparenthesis", SDLK_LEFTPAREN},
|
||||
{"rparenthesis", SDLK_RIGHTPAREN},
|
||||
{"lbracket", SDLK_LEFTBRACKET},
|
||||
{"rbracket", SDLK_RIGHTBRACKET},
|
||||
{"lbrace", SDLK_LEFTBRACE},
|
||||
{"rbrace", SDLK_RIGHTBRACE},
|
||||
{"backslash", SDLK_BACKSLASH},
|
||||
{"dash", SDLK_SLASH},
|
||||
{"enter", SDLK_RETURN},
|
||||
{"space", SDLK_SPACE},
|
||||
{"tab", SDLK_TAB},
|
||||
{"backspace", SDLK_BACKSPACE},
|
||||
{"escape", SDLK_ESCAPE},
|
||||
{"left", SDLK_LEFT},
|
||||
{"right", SDLK_RIGHT},
|
||||
{"up", SDLK_UP},
|
||||
{"down", SDLK_DOWN},
|
||||
{"lctrl", SDLK_LCTRL},
|
||||
{"rctrl", SDLK_RCTRL},
|
||||
{"lshift", SDLK_LSHIFT},
|
||||
{"rshift", SDLK_RSHIFT},
|
||||
{"lalt", SDLK_LALT},
|
||||
{"ralt", SDLK_RALT},
|
||||
{"lmeta", SDLK_LGUI},
|
||||
{"rmeta", SDLK_RGUI},
|
||||
{"lwin", SDLK_LGUI},
|
||||
{"rwin", SDLK_RGUI},
|
||||
{"home", SDLK_HOME},
|
||||
{"end", SDLK_END},
|
||||
{"pgup", SDLK_PAGEUP},
|
||||
{"pgdown", SDLK_PAGEDOWN},
|
||||
{"leftbutton", SDL_BUTTON_LEFT},
|
||||
{"rightbutton", SDL_BUTTON_RIGHT},
|
||||
{"middlebutton", SDL_BUTTON_MIDDLE},
|
||||
{"sidebuttonback", SDL_BUTTON_X1},
|
||||
{"sidebuttonforward", SDL_BUTTON_X2},
|
||||
{"mousewheelup", SDL_MOUSE_WHEEL_UP},
|
||||
{"mousewheeldown", SDL_MOUSE_WHEEL_DOWN},
|
||||
{"mousewheelleft", SDL_MOUSE_WHEEL_LEFT},
|
||||
{"mousewheelright", SDL_MOUSE_WHEEL_RIGHT},
|
||||
{"kpperiod", SDLK_KP_PERIOD},
|
||||
{"kpcomma", SDLK_KP_COMMA},
|
||||
{"kpdivide", SDLK_KP_DIVIDE},
|
||||
{"kpmultiply", SDLK_KP_MULTIPLY},
|
||||
{"kpminus", SDLK_KP_MINUS},
|
||||
{"kpplus", SDLK_KP_PLUS},
|
||||
{"kpenter", SDLK_KP_ENTER},
|
||||
{"kpequals", SDLK_KP_EQUALS},
|
||||
{"capslock", SDLK_CAPSLOCK},
|
||||
};
|
||||
|
||||
// i wrapped it in a function so I can collapse it
|
||||
std::string_view getDefaultKeyboardConfig();
|
||||
|
||||
void parseInputConfig(const std::string game_id);
|
||||
|
||||
class InputBinding {
|
||||
public:
|
||||
u32 key1, key2, key3;
|
||||
int axis_value;
|
||||
InputBinding(int v, u32 k1 = SDLK_UNKNOWN, u32 k2 = SDLK_UNKNOWN, u32 k3 = SDLK_UNKNOWN) {
|
||||
// we format the keys so comaring them will be very fast, because we will only have to compare 3 sorted elements,
|
||||
// where the only possible duplicate item is 0
|
||||
|
||||
// duplicate entries get changed to one original, one null
|
||||
if(k1 == k2 && k1 != SDLK_UNKNOWN) { k2 = 0; }
|
||||
if(k1 == k3 && k1 != SDLK_UNKNOWN) { k3 = 0; }
|
||||
if(k3 == k2 && k2 != SDLK_UNKNOWN) { k2 = 0; }
|
||||
// this sorts them
|
||||
if (k1 <= k2 && k1 <= k3) {
|
||||
key1 = k1;
|
||||
if (k2 <= k3) { key2 = k2; key3 = k3; }
|
||||
else { key2 = k3; key3 = k2; }
|
||||
} else if (k2 <= k1 && k2 <= k3) {
|
||||
key1 = k2;
|
||||
if (k1 <= k3) { key2 = k1; key3 = k3; }
|
||||
else { key2 = k3; key3 = k1; }
|
||||
} else {
|
||||
key1 = k3;
|
||||
if (k1 <= k2) { key2 = k1; key3 = k2; }
|
||||
else { key2 = k2; key3 = k1; }
|
||||
}
|
||||
}
|
||||
|
||||
inline bool operator==(const InputBinding& o) {
|
||||
// 0 = SDLK_UNKNOWN aka unused slot
|
||||
return (key3 == o.key3 || key3 == 0 || o.key3 == 0) &&
|
||||
(key2 == o.key2 || key2 == 0 || o.key2 == 0) &&
|
||||
(key1 == o.key1 || key1 == 0 || o.key1 == 0);
|
||||
// it is already very fast,
|
||||
// but reverse order makes it check the actual keys first instead of possible 0-s,
|
||||
// potenially skipping the later expressions of the three-way AND
|
||||
}
|
||||
|
||||
static u32 getInputIDFromEvent(const SDL_Event& e) {
|
||||
switch(e.type) {
|
||||
case SDL_EVENT_KEY_DOWN:
|
||||
case SDL_EVENT_KEY_UP:
|
||||
return e.key.key;
|
||||
case SDL_EVENT_MOUSE_BUTTON_DOWN:
|
||||
case SDL_EVENT_MOUSE_BUTTON_UP:
|
||||
return (u32)e.button.button;
|
||||
default:
|
||||
// todo: add the rest (wheel)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
class ControllerOutput {
|
||||
static GameController* controller;
|
||||
public:
|
||||
static void setControllerOutputController(GameController* c);
|
||||
|
||||
std::string name;
|
||||
u32 button;
|
||||
Input::Axis axis;
|
||||
int axis_value;
|
||||
bool active;
|
||||
ControllerOutput(const std::string& n, u32 b, Axis a = Axis::AxisMax, int v = 0, bool ac = false) {
|
||||
name = n;
|
||||
button = b;
|
||||
axis = a;
|
||||
axis_value = v;
|
||||
active = ac;
|
||||
}
|
||||
ControllerOutput(const ControllerOutput& o);
|
||||
void update(bool pressed, int axis_direction = 0);
|
||||
};
|
||||
class InputData {
|
||||
InputBinding binding;
|
||||
int axis_value;
|
||||
bool flag;
|
||||
InputData(InputBinding b, int v = 0) : binding(b), axis_value(v), flag(false) {}
|
||||
|
||||
};
|
||||
|
||||
// todo
|
||||
// don't forget to change the number too
|
||||
const std::array<ControllerOutput, 4> input_state = {
|
||||
// buttons and axes rolled into one
|
||||
ControllerOutput("up", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_UP),
|
||||
ControllerOutput("down", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_DOWN),
|
||||
// etc.
|
||||
ControllerOutput("axis_left_x_plus", 0, Axis::LeftX, 127),
|
||||
ControllerOutput("axis_left_x_minus", 0, Axis::LeftX, -127),
|
||||
// etc.
|
||||
};
|
||||
|
||||
|
||||
extern std::map<InputData, ControllerOutput&> new_binding_map;
|
||||
extern u32 pressed_keys[];
|
||||
|
||||
// Check if the 3 key input is currently active.
|
||||
bool checkForInputDown(InputBinding i);
|
||||
|
||||
// Add/remove the input that generated the event to/from the held keys container.
|
||||
void updatePressedKeys(u32 button, bool is_pressed);
|
||||
|
||||
|
||||
void updateMouse(GameController* controller);
|
||||
|
||||
// Polls the mouse for changes, and simulates joystick movement from it.
|
||||
Uint32 mousePolling(void* param, Uint32 id, Uint32 interval);
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
@ -12,6 +12,7 @@
|
||||
#include "core/libraries/pad/pad.h"
|
||||
#include "imgui/renderer/imgui_core.h"
|
||||
#include "input/controller.h"
|
||||
#include "input/input_handler.h"
|
||||
#include "sdl_window.h"
|
||||
#include "video_core/renderdoc.h"
|
||||
|
||||
@ -76,6 +77,8 @@ WindowSDL::WindowSDL(s32 width_, s32 height_, Input::GameController* controller_
|
||||
window_info.type = WindowSystemType::Metal;
|
||||
window_info.render_surface = SDL_Metal_GetLayer(SDL_Metal_CreateView(window));
|
||||
#endif
|
||||
// input handler init-s
|
||||
Input::ControllerOutput::setControllerOutputController(controller);
|
||||
}
|
||||
|
||||
WindowSDL::~WindowSDL() = default;
|
||||
@ -103,9 +106,10 @@ void WindowSDL::waitEvent() {
|
||||
is_shown = event.type == SDL_EVENT_WINDOW_EXPOSED;
|
||||
onResize();
|
||||
break;
|
||||
|
||||
case SDL_EVENT_KEY_DOWN:
|
||||
case SDL_EVENT_KEY_UP:
|
||||
onKeyPress(&event);
|
||||
onKeyboardMouseInput(&event);
|
||||
break;
|
||||
case SDL_EVENT_GAMEPAD_BUTTON_DOWN:
|
||||
case SDL_EVENT_GAMEPAD_BUTTON_UP:
|
||||
@ -127,6 +131,8 @@ void WindowSDL::waitEvent() {
|
||||
|
||||
void WindowSDL::initTimers() {
|
||||
SDL_AddTimer(100, &PollController, controller);
|
||||
// todo: add back mouse polling here
|
||||
SDL_AddTimer(33, Input::mousePolling, (void*)controller);
|
||||
}
|
||||
|
||||
void WindowSDL::onResize() {
|
||||
@ -134,9 +140,18 @@ void WindowSDL::onResize() {
|
||||
ImGui::Core::OnResize();
|
||||
}
|
||||
|
||||
void WindowSDL::onKeyPress(const SDL_Event* event) {
|
||||
void WindowSDL::onKeyboardMouseInput(const SDL_Event* event) {
|
||||
using Libraries::Pad::OrbisPadButtonDataOffset;
|
||||
|
||||
// get the event's id, if it's keyup or keydown
|
||||
|
||||
// add/remove it from the list
|
||||
|
||||
// update bindings and buttons
|
||||
|
||||
// update axes
|
||||
|
||||
/* og function
|
||||
#ifdef __APPLE__
|
||||
// Use keys that are more friendly for keyboards without a keypad.
|
||||
// Once there are key binding options this won't be necessary.
|
||||
@ -323,6 +338,7 @@ void WindowSDL::onKeyPress(const SDL_Event* event) {
|
||||
if (axis != Input::Axis::AxisMax) {
|
||||
controller->Axis(0, axis, ax);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
void WindowSDL::onGamepadEvent(const SDL_Event* event) {
|
||||
|
@ -72,7 +72,7 @@ public:
|
||||
|
||||
private:
|
||||
void onResize();
|
||||
void onKeyPress(const SDL_Event* event);
|
||||
void onKeyboardMouseInput(const SDL_Event* event);
|
||||
void onGamepadEvent(const SDL_Event* event);
|
||||
|
||||
int sdlGamepadToOrbisButton(u8 button);
|
||||
|
Loading…
Reference in New Issue
Block a user