Browse Source
Initial game controller support. Actions are based on the Switch branch but the controller code itself is implemented differently, allowing for easy remapping and minimizing changes to the Source/ directory. Many subtle and not so subtle controller bugs have been fixed in this implementation, including: 1. Smoother & more responsive movement with the joysticks. 2. Consistent controls for all the menus in the game (stores, quest log, etc). 3. Cursor appearance / disappearance at appropriate times. Low-level controls are abstracted and 3 SDL interfaces are supported: game controller, joystick, and keyboard. See SourceX/controls/ for more details on this. Wishlist for the future: 1. Primary button and use button should attack continously. This is hard as it requires checking the cooldowns / attack speed. 2. Quick spell menu navigation is very buggy. It is also buggy in the switch branch. I haven't had a change to investigate.pull/420/head
32 changed files with 1784 additions and 259 deletions
@ -0,0 +1,20 @@
|
||||
# Controls handling |
||||
|
||||
DevilutionX supports mouse & keyboard and gamepad input. |
||||
|
||||
This directory currently mostly handles gamepad input. |
||||
|
||||
Low-level gamepad handling is abstracted and 3 implementations are provided: |
||||
|
||||
1. SDL2 controller API. |
||||
|
||||
2. SDL 1&2 joystick API. |
||||
|
||||
This can be used in SDL1 joystick platforms and for mapping additional |
||||
buttons not defined by SDL2 controller mappings (e.g. additional Nintendo |
||||
Switch arrows). |
||||
|
||||
3. Keyboard keys acting as controller buttons. |
||||
|
||||
This can be used for testing, or on devices where this is the |
||||
only or the easiest API to use (e.g. RetroFW). |
||||
@ -0,0 +1,65 @@
|
||||
#include "controls/controller.h" |
||||
|
||||
#include "controls/devices/kbcontroller.h" |
||||
#include "controls/devices/joystick.h" |
||||
#include "controls/devices/game_controller.h" |
||||
|
||||
namespace dvl { |
||||
|
||||
ControllerButtonEvent ToControllerButtonEvent(const SDL_Event &event) |
||||
{ |
||||
ControllerButtonEvent result{ ControllerButton::NONE, false }; |
||||
switch (event.type) { |
||||
#ifndef USE_SDL1 |
||||
case SDL_CONTROLLERAXISMOTION: |
||||
result.up = event.caxis.value == 0; |
||||
break; |
||||
case SDL_CONTROLLERBUTTONUP: |
||||
#endif |
||||
case SDL_JOYBUTTONUP: |
||||
case SDL_KEYUP: |
||||
result.up = true; |
||||
break; |
||||
default: |
||||
break; |
||||
} |
||||
|
||||
#if HAS_KBCTRL == 1 |
||||
result.button = KbCtrlToControllerButton(event); |
||||
if (result.button != ControllerButton::NONE) |
||||
return result; |
||||
#endif |
||||
|
||||
#ifndef USE_SDL1 |
||||
result.button = GameControllerToControllerButton(event); |
||||
if (result.button != ControllerButton::NONE) |
||||
return result; |
||||
#endif |
||||
|
||||
result.button = JoyButtonToControllerButton(event); |
||||
|
||||
return result; |
||||
} |
||||
|
||||
bool IsControllerButtonPressed(ControllerButton button) |
||||
{ |
||||
bool result = false; |
||||
#ifndef USE_SDL1 |
||||
result = result || IsGameControllerButtonPressed(button); |
||||
#endif |
||||
#if HAS_KBCTRL == 1 |
||||
result = result || IsKbCtrlButtonPressed(button); |
||||
#endif |
||||
result = result || IsJoystickButtonPressed(button); |
||||
return result; |
||||
} |
||||
|
||||
void InitController() |
||||
{ |
||||
InitJoystick(); |
||||
#ifndef USE_SDL1 |
||||
InitGameController(); |
||||
#endif |
||||
} |
||||
|
||||
} // namespace dvl
|
||||
@ -0,0 +1,18 @@
|
||||
#pragma once |
||||
|
||||
#include "controls/controller_buttons.h" |
||||
|
||||
namespace dvl { |
||||
|
||||
struct ControllerButtonEvent { |
||||
ControllerButton button; |
||||
bool up; |
||||
}; |
||||
|
||||
ControllerButtonEvent ToControllerButtonEvent(const SDL_Event &event); |
||||
|
||||
bool IsControllerButtonPressed(ControllerButton button); |
||||
|
||||
void InitController(); |
||||
|
||||
} // namespace dvl
|
||||
@ -0,0 +1,30 @@
|
||||
#pragma once |
||||
// Unifies joystick, gamepad, and keyboard controller APIs.
|
||||
|
||||
#include "devilution.h" |
||||
|
||||
namespace dvl { |
||||
|
||||
// NOTE: A, B, X, Y refer to physical positions on an XBox 360 controller.
|
||||
// A<->B and X<->Y are reversed on a Nintendo controller.
|
||||
enum class ControllerButton { |
||||
NONE = 0, |
||||
AXIS_TRIGGERLEFT, // ZL (aka L2)
|
||||
AXIS_TRIGGERRIGHT, // ZR (aka R2)
|
||||
BUTTON_A, // Bottom button
|
||||
BUTTON_B, // Right button
|
||||
BUTTON_X, // Left button
|
||||
BUTTON_Y, // TOP button
|
||||
BUTTON_LEFTSTICK, |
||||
BUTTON_RIGHTSTICK, |
||||
BUTTON_LEFTSHOULDER, |
||||
BUTTON_RIGHTSHOULDER, |
||||
BUTTON_START, |
||||
BUTTON_BACK, |
||||
BUTTON_DPAD_UP, |
||||
BUTTON_DPAD_DOWN, |
||||
BUTTON_DPAD_LEFT, |
||||
BUTTON_DPAD_RIGHT |
||||
}; |
||||
|
||||
} // namespace dvl
|
||||
@ -0,0 +1,91 @@
|
||||
#include "controls/controller_motion.h" |
||||
|
||||
#include "controls/devices/game_controller.h" |
||||
|
||||
namespace dvl { |
||||
|
||||
namespace { |
||||
|
||||
void ScaleJoystickAxes(float *x, float *y, float deadzone) |
||||
{ |
||||
//radial and scaled dead_zone
|
||||
//http://www.third-helix.com/2013/04/12/doing-thumbstick-dead-zones-right.html
|
||||
//input values go from -32767.0...+32767.0, output values are from -1.0 to 1.0;
|
||||
|
||||
if (deadzone == 0) { |
||||
return; |
||||
} |
||||
if (deadzone >= 1.0) { |
||||
*x = 0; |
||||
*y = 0; |
||||
return; |
||||
} |
||||
|
||||
const float maximum = 32767.0f; |
||||
float analog_x = *x; |
||||
float analog_y = *y; |
||||
float dead_zone = deadzone * maximum; |
||||
|
||||
float magnitude = sqrtf(analog_x * analog_x + analog_y * analog_y); |
||||
if (magnitude >= dead_zone) { |
||||
// find scaled axis values with magnitudes between zero and maximum
|
||||
float scalingFactor = 1.0 / magnitude * (magnitude - dead_zone) / (maximum - dead_zone); |
||||
analog_x = (analog_x * scalingFactor); |
||||
analog_y = (analog_y * scalingFactor); |
||||
|
||||
// clamp to ensure results will never exceed the max_axis value
|
||||
float clamping_factor = 1.0f; |
||||
float abs_analog_x = fabs(analog_x); |
||||
float abs_analog_y = fabs(analog_y); |
||||
if (abs_analog_x > 1.0 || abs_analog_y > 1.0) { |
||||
if (abs_analog_x > abs_analog_y) { |
||||
clamping_factor = 1 / abs_analog_x; |
||||
} else { |
||||
clamping_factor = 1 / abs_analog_y; |
||||
} |
||||
} |
||||
*x = (clamping_factor * analog_x); |
||||
*y = (clamping_factor * analog_y); |
||||
} else { |
||||
*x = 0; |
||||
*y = 0; |
||||
} |
||||
} |
||||
|
||||
} // namespace
|
||||
|
||||
float leftStickX, leftStickY, rightStickX, rightStickY; |
||||
float leftStickXUnscaled, leftStickYUnscaled, rightStickXUnscaled, rightStickYUnscaled; |
||||
bool leftStickNeedsScaling, rightStickNeedsScaling; |
||||
|
||||
void ScaleJoysticks() |
||||
{ |
||||
constexpr float rightDeadzone = 0.07; |
||||
constexpr float leftDeadzone = 0.07; |
||||
|
||||
if (leftStickNeedsScaling) { |
||||
leftStickX = leftStickXUnscaled; |
||||
leftStickY = leftStickYUnscaled; |
||||
ScaleJoystickAxes(&leftStickX, &leftStickY, leftDeadzone); |
||||
leftStickNeedsScaling = false; |
||||
} |
||||
|
||||
if (rightStickNeedsScaling) { |
||||
rightStickX = rightStickXUnscaled; |
||||
rightStickY = rightStickYUnscaled; |
||||
ScaleJoystickAxes(&rightStickX, &rightStickY, rightDeadzone); |
||||
rightStickNeedsScaling = false; |
||||
} |
||||
} |
||||
|
||||
// Updates motion state for mouse and joystick sticks.
|
||||
bool ProcessControllerMotion(const SDL_Event &event) |
||||
{ |
||||
#ifndef USE_SDL1 |
||||
if (ProcessGameControllerAxisMotion(event)) |
||||
return true; |
||||
#endif |
||||
return false; |
||||
} |
||||
|
||||
} // namespace dvl
|
||||
@ -0,0 +1,23 @@
|
||||
#pragma once |
||||
|
||||
// Processes and stores mouse and joystick motion.
|
||||
|
||||
#include "devilution.h" |
||||
|
||||
namespace dvl { |
||||
|
||||
// Raw axis values.
|
||||
extern float leftStickXUnscaled, leftStickYUnscaled, rightStickXUnscaled, rightStickYUnscaled; |
||||
|
||||
// Axis values scaled to [-1, 1] range and clamped to a deadzone.
|
||||
extern float leftStickX, leftStickY, rightStickX, rightStickY; |
||||
|
||||
// Whether stick positions have been updated and need rescaling.
|
||||
extern bool leftStickNeedsScaling, rightStickNeedsScaling; |
||||
|
||||
void ScaleJoysticks(); |
||||
|
||||
// Updates motion state for mouse and joystick sticks.
|
||||
bool ProcessControllerMotion(const SDL_Event &event); |
||||
|
||||
} // namespace dvl
|
||||
@ -0,0 +1,159 @@
|
||||
#include "controls/devices/game_controller.h" |
||||
|
||||
#ifndef USE_SDL1 |
||||
#include "controls/controller_motion.h" |
||||
#include "controls/devices/joystick.h" |
||||
#include "stubs.h" |
||||
|
||||
namespace dvl { |
||||
|
||||
static SDL_GameController *current_game_controller = nullptr; |
||||
|
||||
ControllerButton GameControllerToControllerButton(const SDL_Event &event) |
||||
{ |
||||
switch (event.type) { |
||||
case SDL_CONTROLLERAXISMOTION: |
||||
switch (event.caxis.axis) { |
||||
case SDL_CONTROLLER_AXIS_TRIGGERLEFT: |
||||
return ControllerButton::AXIS_TRIGGERLEFT; |
||||
break; |
||||
case SDL_CONTROLLER_AXIS_TRIGGERRIGHT: |
||||
return ControllerButton::AXIS_TRIGGERRIGHT; |
||||
break; |
||||
} |
||||
break; |
||||
case SDL_CONTROLLERBUTTONDOWN: |
||||
case SDL_CONTROLLERBUTTONUP: |
||||
switch (event.cbutton.button) { |
||||
case SDL_CONTROLLER_BUTTON_A: |
||||
return ControllerButton::BUTTON_A; |
||||
case SDL_CONTROLLER_BUTTON_B: |
||||
return ControllerButton::BUTTON_B; |
||||
case SDL_CONTROLLER_BUTTON_X: |
||||
return ControllerButton::BUTTON_X; |
||||
case SDL_CONTROLLER_BUTTON_Y: |
||||
return ControllerButton::BUTTON_Y; |
||||
case SDL_CONTROLLER_BUTTON_LEFTSTICK: |
||||
return ControllerButton::BUTTON_LEFTSTICK; |
||||
case SDL_CONTROLLER_BUTTON_RIGHTSTICK: |
||||
return ControllerButton::BUTTON_RIGHTSTICK; |
||||
case SDL_CONTROLLER_BUTTON_LEFTSHOULDER: |
||||
return ControllerButton::BUTTON_LEFTSHOULDER; |
||||
case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER: |
||||
return ControllerButton::BUTTON_RIGHTSHOULDER; |
||||
case SDL_CONTROLLER_BUTTON_START: |
||||
return ControllerButton::BUTTON_START; |
||||
case SDL_CONTROLLER_BUTTON_BACK: |
||||
return ControllerButton::BUTTON_BACK; |
||||
case SDL_CONTROLLER_BUTTON_DPAD_UP: |
||||
return ControllerButton::BUTTON_DPAD_UP; |
||||
case SDL_CONTROLLER_BUTTON_DPAD_DOWN: |
||||
return ControllerButton::BUTTON_DPAD_DOWN; |
||||
case SDL_CONTROLLER_BUTTON_DPAD_LEFT: |
||||
return ControllerButton::BUTTON_DPAD_LEFT; |
||||
case SDL_CONTROLLER_BUTTON_DPAD_RIGHT: |
||||
return ControllerButton::BUTTON_DPAD_RIGHT; |
||||
default: |
||||
break; |
||||
} |
||||
default: |
||||
break; |
||||
} |
||||
return ControllerButton::NONE; |
||||
} |
||||
|
||||
namespace { |
||||
|
||||
SDL_GameControllerButton ControllerButtonToGameControllerButton(ControllerButton button) |
||||
{ |
||||
if (button == ControllerButton::AXIS_TRIGGERLEFT || button == ControllerButton::AXIS_TRIGGERRIGHT) |
||||
UNIMPLEMENTED(); |
||||
switch (button) { |
||||
case ControllerButton::BUTTON_A: |
||||
return SDL_CONTROLLER_BUTTON_A; |
||||
case ControllerButton::BUTTON_B: |
||||
return SDL_CONTROLLER_BUTTON_B; |
||||
case ControllerButton::BUTTON_X: |
||||
return SDL_CONTROLLER_BUTTON_X; |
||||
case ControllerButton::BUTTON_Y: |
||||
return SDL_CONTROLLER_BUTTON_Y; |
||||
case ControllerButton::BUTTON_BACK: |
||||
return SDL_CONTROLLER_BUTTON_BACK; |
||||
case ControllerButton::BUTTON_START: |
||||
return SDL_CONTROLLER_BUTTON_START; |
||||
case ControllerButton::BUTTON_LEFTSTICK: |
||||
return SDL_CONTROLLER_BUTTON_LEFTSTICK; |
||||
case ControllerButton::BUTTON_RIGHTSTICK: |
||||
return SDL_CONTROLLER_BUTTON_RIGHTSTICK; |
||||
case ControllerButton::BUTTON_LEFTSHOULDER: |
||||
return SDL_CONTROLLER_BUTTON_LEFTSHOULDER; |
||||
case ControllerButton::BUTTON_RIGHTSHOULDER: |
||||
return SDL_CONTROLLER_BUTTON_RIGHTSHOULDER; |
||||
case ControllerButton::BUTTON_DPAD_UP: |
||||
return SDL_CONTROLLER_BUTTON_DPAD_UP; |
||||
case ControllerButton::BUTTON_DPAD_DOWN: |
||||
return SDL_CONTROLLER_BUTTON_DPAD_DOWN; |
||||
case ControllerButton::BUTTON_DPAD_LEFT: |
||||
return SDL_CONTROLLER_BUTTON_DPAD_LEFT; |
||||
case ControllerButton::BUTTON_DPAD_RIGHT: |
||||
return SDL_CONTROLLER_BUTTON_DPAD_RIGHT; |
||||
default: |
||||
return SDL_CONTROLLER_BUTTON_INVALID; |
||||
} |
||||
} |
||||
|
||||
} // namespace
|
||||
|
||||
bool IsGameControllerButtonPressed(ControllerButton button) |
||||
{ |
||||
if (current_game_controller == nullptr) |
||||
return false; |
||||
const SDL_GameControllerButton gc_button = ControllerButtonToGameControllerButton(button); |
||||
return gc_button != SDL_CONTROLLER_BUTTON_INVALID && SDL_GameControllerGetButton(current_game_controller, gc_button); |
||||
} |
||||
|
||||
bool ProcessGameControllerAxisMotion(const SDL_Event &event) |
||||
{ |
||||
if (event.type != SDL_CONTROLLERAXISMOTION) |
||||
return false; |
||||
switch (event.caxis.axis) { |
||||
case SDL_CONTROLLER_AXIS_LEFTX: |
||||
leftStickXUnscaled = event.caxis.value; |
||||
leftStickNeedsScaling = true; |
||||
break; |
||||
case SDL_CONTROLLER_AXIS_LEFTY: |
||||
leftStickYUnscaled = -event.caxis.value; |
||||
leftStickNeedsScaling = true; |
||||
break; |
||||
case SDL_CONTROLLER_AXIS_RIGHTX: |
||||
rightStickXUnscaled = event.caxis.value; |
||||
rightStickNeedsScaling = true; |
||||
break; |
||||
case SDL_CONTROLLER_AXIS_RIGHTY: |
||||
rightStickYUnscaled = -event.caxis.value; |
||||
rightStickNeedsScaling = true; |
||||
break; |
||||
default: |
||||
return false; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
SDL_GameController *CurrentGameController() |
||||
{ |
||||
return current_game_controller; |
||||
} |
||||
|
||||
void InitGameController() |
||||
{ |
||||
if (CurrentJoystickIndex() == -1) |
||||
return; |
||||
const SDL_JoystickGUID guid = SDL_JoystickGetGUID(CurrentJoystick()); |
||||
SDL_Log("Opening gamepad %d: %s", CurrentJoystickIndex(), SDL_GameControllerMappingForGUID(guid)); |
||||
current_game_controller = SDL_GameControllerOpen(CurrentJoystickIndex()); |
||||
if (current_game_controller == nullptr) |
||||
SDL_Log(SDL_GetError()); |
||||
} |
||||
|
||||
} // namespace dvl
|
||||
#endif |
||||
@ -0,0 +1,22 @@
|
||||
|
||||
#pragma once |
||||
|
||||
#include <SDL.h> |
||||
#include "controls/controller_buttons.h" |
||||
|
||||
#ifndef USE_SDL1 |
||||
namespace dvl { |
||||
|
||||
ControllerButton GameControllerToControllerButton(const SDL_Event &event); |
||||
|
||||
bool IsGameControllerButtonPressed(ControllerButton button); |
||||
|
||||
bool ProcessGameControllerAxisMotion(const SDL_Event &event); |
||||
|
||||
SDL_GameController *CurrentGameController(); |
||||
|
||||
// Must be called after InitJoystick().
|
||||
void InitGameController(); |
||||
|
||||
} // namespace dvl
|
||||
#endif |
||||
@ -0,0 +1,193 @@
|
||||
|
||||
#include "controls/devices/joystick.h" |
||||
|
||||
#include "stubs.h" |
||||
|
||||
#ifdef SWITCH |
||||
#define JOY_BUTTON_DPAD_LEFT 16 |
||||
#define JOY_BUTTON_DPAD_UP 17 |
||||
#define JOY_BUTTON_DPAD_RIGHT 18 |
||||
#define JOY_BUTTON_DPAD_DOWN 19 |
||||
#endif |
||||
|
||||
namespace dvl { |
||||
|
||||
ControllerButton JoyButtonToControllerButton(const SDL_Event &event) |
||||
{ |
||||
switch (event.type) { |
||||
case SDL_JOYBUTTONDOWN: |
||||
case SDL_JOYBUTTONUP: |
||||
switch (event.jbutton.button) { |
||||
#ifdef JOY_BUTTON_A |
||||
case JOY_BUTTON_A: |
||||
return ControllerButton::BUTTON_A; |
||||
#endif |
||||
#ifdef JOY_BUTTON_B |
||||
case JOY_BUTTON_B: |
||||
return ControllerButton::BUTTON_B; |
||||
#endif |
||||
#ifdef JOY_BUTTON_X |
||||
case JOY_BUTTON_X: |
||||
return ControllerButton::BUTTON_X; |
||||
#endif |
||||
#ifdef JOY_BUTTON_Y |
||||
case JOY_BUTTON_Y: |
||||
return ControllerButton::BUTTON_Y; |
||||
#endif |
||||
#ifdef JOY_BUTTON_LEFTSTICK |
||||
case JOY_BUTTON_LEFTSTICK: |
||||
return ControllerButton::BUTTON_LEFTSTICK; |
||||
#endif |
||||
#ifdef JOY_BUTTON_RIGHTSTICK |
||||
case JOY_BUTTON_RIGHTSTICK: |
||||
return ControllerButton::BUTTON_RIGHTSTICK; |
||||
#endif |
||||
#ifdef JOY_BUTTON_LEFTSHOULDER |
||||
case JOY_BUTTON_LEFTSHOULDER: |
||||
return ControllerButton::BUTTON_LEFTSHOULDER; |
||||
#endif |
||||
#ifdef JOY_BUTTON_RIGHTSHOULDER |
||||
case JOY_BUTTON_RIGHTSHOULDER: |
||||
return ControllerButton::BUTTON_RIGHTSHOULDER; |
||||
#endif |
||||
#ifdef JOY_BUTTON_START |
||||
case JOY_BUTTON_START: |
||||
return ControllerButton::BUTTON_START; |
||||
#endif |
||||
#ifdef JOY_BUTTON_BACK |
||||
case JOY_BUTTON_BACK: |
||||
return ControllerButton::BUTTON_BACK; |
||||
#endif |
||||
#ifdef JOY_BUTTON_DPAD_LEFT |
||||
case JOY_BUTTON_DPAD_LEFT: |
||||
return ControllerButton::BUTTON_DPAD_LEFT; |
||||
#endif |
||||
#ifdef JOY_BUTTON_DPAD_UP |
||||
case JOY_BUTTON_DPAD_UP: |
||||
return ControllerButton::BUTTON_DPAD_UP; |
||||
#endif |
||||
#ifdef JOY_BUTTON_DPAD_RIGHT |
||||
case JOY_BUTTON_DPAD_RIGHT: |
||||
return ControllerButton::BUTTON_DPAD_RIGHT; |
||||
#endif |
||||
#ifdef JOY_BUTTON_DPAD_DOWN |
||||
case JOY_BUTTON_DPAD_DOWN: |
||||
return ControllerButton::BUTTON_DPAD_DOWN; |
||||
#endif |
||||
default: |
||||
break; |
||||
} |
||||
break; |
||||
} |
||||
return ControllerButton::NONE; |
||||
} |
||||
|
||||
int JoyButtonToControllerButton(ControllerButton button) { |
||||
if (button == ControllerButton::AXIS_TRIGGERLEFT || button == ControllerButton::AXIS_TRIGGERRIGHT) |
||||
UNIMPLEMENTED(); |
||||
switch (button) { |
||||
#ifdef JOY_BUTTON_A |
||||
case ControllerButton::BUTTON_A: |
||||
return JOY_BUTTON_A; |
||||
#endif |
||||
#ifdef JOY_BUTTON_B |
||||
case ControllerButton::BUTTON_B: |
||||
return JOY_BUTTON_B; |
||||
#endif |
||||
#ifdef JOY_BUTTON_X |
||||
case ControllerButton::BUTTON_X: |
||||
return JOY_BUTTON_X; |
||||
#endif |
||||
#ifdef JOY_BUTTON_Y |
||||
case ControllerButton::BUTTON_Y: |
||||
return JOY_BUTTON_Y; |
||||
#endif |
||||
#ifdef JOY_BUTTON_BACK |
||||
case ControllerButton::BUTTON_BACK: |
||||
return JOY_BUTTON_BACK; |
||||
#endif |
||||
#ifdef JOY_BUTTON_START |
||||
case ControllerButton::BUTTON_START: |
||||
return JOY_BUTTON_START; |
||||
#endif |
||||
#ifdef JOY_BUTTON_LEFTSTICK |
||||
case ControllerButton::BUTTON_LEFTSTICK: |
||||
return JOY_BUTTON_LEFTSTICK; |
||||
#endif |
||||
#ifdef JOY_BUTTON_RIGHTSTICK |
||||
case ControllerButton::BUTTON_RIGHTSTICK: |
||||
return JOY_BUTTON_RIGHTSTICK; |
||||
#endif |
||||
#ifdef JOY_BUTTON_LEFTSHOULDER |
||||
case ControllerButton::BUTTON_LEFTSHOULDER: |
||||
return JOY_BUTTON_LEFTSHOULDER; |
||||
#endif |
||||
#ifdef JOY_BUTTON_RIGHTSHOULDER |
||||
case ControllerButton::BUTTON_RIGHTSHOULDER: |
||||
return JOY_BUTTON_RIGHTSHOULDER; |
||||
#endif |
||||
#ifdef JOY_BUTTON_DPAD_UP |
||||
case ControllerButton::BUTTON_DPAD_UP: |
||||
return JOY_BUTTON_DPAD_UP; |
||||
#endif |
||||
#ifdef JOY_BUTTON_DPAD_DOWN |
||||
case ControllerButton::BUTTON_DPAD_DOWN: |
||||
return JOY_BUTTON_DPAD_DOWN; |
||||
#endif |
||||
#ifdef JOY_BUTTON_DPAD_LEFT |
||||
case ControllerButton::BUTTON_DPAD_LEFT: |
||||
return JOY_BUTTON_DPAD_LEFT; |
||||
#endif |
||||
#ifdef JOY_BUTTON_DPAD_RIGHT |
||||
case ControllerButton::BUTTON_DPAD_RIGHT: |
||||
return JOY_BUTTON_DPAD_RIGHT; |
||||
#endif |
||||
default: |
||||
return -1; |
||||
} |
||||
} |
||||
|
||||
bool IsJoystickButtonPressed(ControllerButton button) { |
||||
if (CurrentJoystick() == nullptr) |
||||
return false; |
||||
const int joy_button = JoyButtonToControllerButton(button); |
||||
return joy_button != -1 && SDL_JoystickGetButton(CurrentJoystick(), joy_button); |
||||
} |
||||
|
||||
static SDL_Joystick *current_joystick = nullptr; |
||||
|
||||
SDL_Joystick *CurrentJoystick() |
||||
{ |
||||
return current_joystick; |
||||
} |
||||
|
||||
static int current_joystick_index = -1; |
||||
|
||||
int CurrentJoystickIndex() |
||||
{ |
||||
return current_joystick_index; |
||||
} |
||||
|
||||
void InitJoystick() |
||||
{ |
||||
if (SDL_NumJoysticks() == 0) |
||||
return; |
||||
|
||||
// Get the first available controller.
|
||||
for (int i = 0; i < SDL_NumJoysticks(); ++i) { |
||||
#ifndef USE_SDL1 |
||||
if (!SDL_IsGameController(i)) |
||||
continue; |
||||
#endif |
||||
SDL_Log("Initializing joystick %d: %s", i, SDL_JoystickNameForIndex(i)); |
||||
current_joystick = SDL_JoystickOpen(i); |
||||
if (current_joystick == nullptr) { |
||||
SDL_Log(SDL_GetError()); |
||||
continue; |
||||
} |
||||
current_joystick_index = i; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
} // namespace dvl
|
||||
@ -0,0 +1,19 @@
|
||||
#pragma once |
||||
|
||||
// Joystick mappings for SDL1 and additional buttons on SDL2.
|
||||
|
||||
#include <SDL.h> |
||||
#include "controls/controller_buttons.h" |
||||
|
||||
namespace dvl { |
||||
|
||||
ControllerButton JoyButtonToControllerButton(const SDL_Event &event); |
||||
|
||||
bool IsJoystickButtonPressed(ControllerButton button); |
||||
|
||||
SDL_Joystick *CurrentJoystick(); |
||||
int CurrentJoystickIndex(); |
||||
|
||||
void InitJoystick(); |
||||
|
||||
} // namespace dvl
|
||||
@ -0,0 +1,202 @@
|
||||
#include "controls/devices/kbcontroller.h" |
||||
|
||||
#if defined(RETROFW) |
||||
#define HAS_KBCTRL 1 |
||||
|
||||
#define KBCTRL_BUTTON_DPAD_LEFT SDLK_LEFT |
||||
#define KBCTRL_BUTTON_DPAD_RIGHT SDLK_RIGHT |
||||
#define KBCTRL_BUTTON_DPAD_UP SDLK_UP |
||||
#define KBCTRL_BUTTON_DPAD_DOWN SDLK_DOWN |
||||
|
||||
#define KBCTRL_BUTTON_B SDLK_LCTRL |
||||
#define KBCTRL_BUTTON_A SDLK_LALT |
||||
#define KBCTRL_BUTTON_Y SDLK_SPACE |
||||
#define KBCTRL_BUTTON_X SDLK_LSHIFT |
||||
#define KBCTRL_BUTTON_RIGHTSHOULDER SDLK_BACKSPACE |
||||
#define KBCTRL_BUTTON_LEFTSHOULDER SDLK_TAB |
||||
#define KBCTRL_BUTTON_START SDLK_RETURN |
||||
#define KBCTRL_BUTTON_BACK SDLK_ESCAPE |
||||
#define KBCTRL_MODIFIER_KEY SDLK_END // The suspend key on RG300
|
||||
#endif |
||||
|
||||
#if HAS_KBCTRL == 1 |
||||
|
||||
#include "sdl2_to_1_2_backports.h" |
||||
#include "sdl_compat.h" |
||||
#include "stubs.h" |
||||
|
||||
namespace dvl { |
||||
|
||||
namespace { |
||||
|
||||
bool IsModifierKey() |
||||
{ |
||||
#ifdef KBCTRL_MODIFIER_KEY |
||||
return SDLC_GetKeyboardState(nullptr)[KBCTRL_MODIFIER_KEY]; |
||||
#else |
||||
return false; |
||||
#endif |
||||
} |
||||
|
||||
} // namespace
|
||||
|
||||
ControllerButton KbCtrlToControllerButton(const SDL_Event &event) |
||||
{ |
||||
switch (event.type) { |
||||
case SDL_KEYDOWN: |
||||
case SDL_KEYUP: |
||||
switch (event.key.keysym.sym) { |
||||
#ifdef KBCTRL_BUTTON_A |
||||
case KBCTRL_BUTTON_A: |
||||
return ControllerButton::BUTTON_A; |
||||
#endif |
||||
#ifdef KBCTRL_BUTTON_B |
||||
case KBCTRL_BUTTON_B: |
||||
return ControllerButton::BUTTON_B; |
||||
#endif |
||||
#ifdef KBCTRL_BUTTON_X |
||||
case KBCTRL_BUTTON_X: |
||||
if (IsModifierKey()) |
||||
return ControllerButton::BUTTON_LEFTSTICK; |
||||
return ControllerButton::BUTTON_X; |
||||
#endif |
||||
#ifdef KBCTRL_BUTTON_Y |
||||
case KBCTRL_BUTTON_Y: |
||||
if (IsModifierKey()) |
||||
return ControllerButton::BUTTON_RIGHTSTICK; |
||||
return ControllerButton::BUTTON_Y; |
||||
#endif |
||||
#ifdef KBCTRL_BUTTON_LEFTSTICK |
||||
case KBCTRL_BUTTON_LEFTSTICK: |
||||
return ControllerButton::BUTTON_LEFTSTICK; |
||||
#endif |
||||
#ifdef KBCTRL_BUTTON_RIGHTSTICK |
||||
case KBCTRL_BUTTON_RIGHTSTICK: |
||||
return ControllerButton::BUTTON_RIGHTSTICK; |
||||
#endif |
||||
#ifdef KBCTRL_BUTTON_LEFTSHOULDER |
||||
case KBCTRL_BUTTON_LEFTSHOULDER: |
||||
if (IsModifierKey()) |
||||
return ControllerButton::AXIS_TRIGGERLEFT; |
||||
return ControllerButton::BUTTON_LEFTSHOULDER; |
||||
#endif |
||||
#ifdef KBCTRL_BUTTON_RIGHTSHOULDER |
||||
case KBCTRL_BUTTON_RIGHTSHOULDER: |
||||
if (IsModifierKey()) |
||||
return ControllerButton::AXIS_TRIGGERRIGHT; |
||||
return ControllerButton::BUTTON_RIGHTSHOULDER; |
||||
#endif |
||||
#ifdef KBCTRL_BUTTON_START |
||||
case KBCTRL_BUTTON_START: |
||||
return ControllerButton::BUTTON_START; |
||||
#endif |
||||
#ifdef KBCTRL_BUTTON_BACK |
||||
case KBCTRL_BUTTON_BACK: |
||||
return ControllerButton::BUTTON_BACK; |
||||
#endif |
||||
#ifdef KBCTRL_BUTTON_DPAD_UP |
||||
case KBCTRL_BUTTON_DPAD_UP: |
||||
return ControllerButton::BUTTON_DPAD_UP; |
||||
#endif |
||||
#ifdef KBCTRL_BUTTON_DPAD_DOWN |
||||
case KBCTRL_BUTTON_DPAD_DOWN: |
||||
return ControllerButton::BUTTON_DPAD_DOWN; |
||||
#endif |
||||
#ifdef KBCTRL_BUTTON_DPAD_LEFT |
||||
case KBCTRL_BUTTON_DPAD_LEFT: |
||||
return ControllerButton::BUTTON_DPAD_LEFT; |
||||
#endif |
||||
#ifdef KBCTRL_BUTTON_DPAD_RIGHT |
||||
case KBCTRL_BUTTON_DPAD_RIGHT: |
||||
return ControllerButton::BUTTON_DPAD_RIGHT; |
||||
#endif |
||||
default: |
||||
return ControllerButton::NONE; |
||||
} |
||||
} |
||||
} |
||||
|
||||
namespace { |
||||
|
||||
int ControllerButtonToKbCtrlKeyCode(ControllerButton button) |
||||
{ |
||||
if (button == ControllerButton::AXIS_TRIGGERLEFT || button == ControllerButton::AXIS_TRIGGERRIGHT) |
||||
UNIMPLEMENTED(); |
||||
switch (button) { |
||||
#ifdef KBCTRL_BUTTON_A |
||||
case ControllerButton::BUTTON_A: |
||||
return KBCTRL_BUTTON_A; |
||||
#endif |
||||
#ifdef KBCTRL_BUTTON_B |
||||
case ControllerButton::BUTTON_B: |
||||
return KBCTRL_BUTTON_B; |
||||
#endif |
||||
#ifdef KBCTRL_BUTTON_X |
||||
case ControllerButton::BUTTON_X: |
||||
return KBCTRL_BUTTON_X; |
||||
#endif |
||||
#ifdef KBCTRL_BUTTON_Y |
||||
case ControllerButton::BUTTON_Y: |
||||
return KBCTRL_BUTTON_Y; |
||||
#endif |
||||
#ifdef KBCTRL_BUTTON_BACK |
||||
case ControllerButton::BUTTON_BACK: |
||||
return KBCTRL_BUTTON_BACK; |
||||
#endif |
||||
#ifdef KBCTRL_BUTTON_START |
||||
case ControllerButton::BUTTON_START: |
||||
return KBCTRL_BUTTON_START; |
||||
#endif |
||||
#ifdef KBCTRL_BUTTON_LEFTSTICK |
||||
case ControllerButton::BUTTON_LEFTSTICK: |
||||
return KBCTRL_BUTTON_LEFTSTICK; |
||||
#endif |
||||
#ifdef KBCTRL_BUTTON_RIGHTSTICK |
||||
case ControllerButton::BUTTON_RIGHTSTICK: |
||||
return KBCTRL_BUTTON_RIGHTSTICK; |
||||
#endif |
||||
#ifdef KBCTRL_BUTTON_LEFTSHOULDER |
||||
case ControllerButton::BUTTON_LEFTSHOULDER: |
||||
return KBCTRL_BUTTON_LEFTSHOULDER; |
||||
#endif |
||||
#ifdef KBCTRL_BUTTON_RIGHTSHOULDER |
||||
case ControllerButton::BUTTON_RIGHTSHOULDER: |
||||
return KBCTRL_BUTTON_RIGHTSHOULDER; |
||||
#endif |
||||
#ifdef KBCTRL_BUTTON_DPAD_UP |
||||
case ControllerButton::BUTTON_DPAD_UP: |
||||
return KBCTRL_BUTTON_DPAD_UP; |
||||
#endif |
||||
#ifdef KBCTRL_BUTTON_DPAD_DOWN |
||||
case ControllerButton::BUTTON_DPAD_DOWN: |
||||
return KBCTRL_BUTTON_DPAD_DOWN; |
||||
#endif |
||||
#ifdef KBCTRL_BUTTON_DPAD_LEFT |
||||
case ControllerButton::BUTTON_DPAD_LEFT: |
||||
return KBCTRL_BUTTON_DPAD_LEFT; |
||||
#endif |
||||
#ifdef KBCTRL_BUTTON_DPAD_RIGHT |
||||
case ControllerButton::BUTTON_DPAD_RIGHT: |
||||
return KBCTRL_BUTTON_DPAD_RIGHT; |
||||
#endif |
||||
default: |
||||
return -1; |
||||
} |
||||
} |
||||
|
||||
} // namespace
|
||||
|
||||
bool IsKbCtrlButtonPressed(ControllerButton button) |
||||
{ |
||||
int key_code = ControllerButtonToKbCtrlKeyCode(button); |
||||
if (key_code == -1) |
||||
return false; |
||||
#ifndef USE_SDL1 |
||||
return SDL_GetKeyboardState(nullptr)[SDL_GetScancodeFromKey(key_code)]; |
||||
#else |
||||
return SDL_GetKeyState(nullptr)[key_code]; |
||||
#endif |
||||
} |
||||
|
||||
} // namespace dvl
|
||||
#endif |
||||
@ -0,0 +1,23 @@
|
||||
#pragma once |
||||
|
||||
// Keyboard keys acting like gamepad buttons
|
||||
#ifndef HAS_KBCTRL |
||||
#define HAS_KBCTRL 0 |
||||
#endif |
||||
|
||||
#if defined(RETROFW) |
||||
#define HAS_KBCTRL 1 |
||||
#endif |
||||
|
||||
#if HAS_KBCTRL == 1 |
||||
#include <SDL.h> |
||||
#include "controls/controller_buttons.h" |
||||
|
||||
namespace dvl { |
||||
|
||||
ControllerButton KbCtrlToControllerButton(const SDL_Event &event); |
||||
|
||||
bool IsKbCtrlButtonPressed(ControllerButton button); |
||||
|
||||
} // namespace dvl
|
||||
#endif |
||||
@ -0,0 +1,156 @@
|
||||
#include "controls/game_controls.h" |
||||
|
||||
#include <cstdint> |
||||
|
||||
#include "controls/controller.h" |
||||
#include "controls/controller_motion.h" |
||||
#include "controls/devices/game_controller.h" |
||||
#include "controls/devices/joystick.h" |
||||
#include "controls/menu_controls.h" |
||||
#include "controls/plrctrls.h" |
||||
|
||||
namespace dvl { |
||||
|
||||
namespace { |
||||
|
||||
DWORD translate_controller_button_to_key(ControllerButton controller_button) |
||||
{ |
||||
switch (controller_button) { |
||||
case ControllerButton::BUTTON_A: // Bottom button
|
||||
return questlog ? DVL_VK_SPACE : DVL_VK_ESCAPE; |
||||
case ControllerButton::BUTTON_B: // Right button
|
||||
return sgpCurrentMenu || stextflag || questlog ? DVL_VK_RETURN : DVL_VK_SPACE; |
||||
case ControllerButton::BUTTON_X: // Left button
|
||||
return 'X'; |
||||
case ControllerButton::BUTTON_Y: // Top button
|
||||
return DVL_VK_RETURN; |
||||
case ControllerButton::BUTTON_LEFTSTICK: |
||||
return 'Q'; // Quest log
|
||||
case ControllerButton::BUTTON_START: |
||||
return DVL_VK_ESCAPE; |
||||
case ControllerButton::BUTTON_BACK: |
||||
return DVL_VK_TAB; // Map
|
||||
case ControllerButton::BUTTON_DPAD_LEFT: |
||||
return DVL_VK_LEFT; |
||||
case ControllerButton::BUTTON_DPAD_RIGHT: |
||||
return DVL_VK_RIGHT; |
||||
case ControllerButton::BUTTON_DPAD_UP: |
||||
return DVL_VK_UP; |
||||
case ControllerButton::BUTTON_DPAD_DOWN: |
||||
return DVL_VK_DOWN; |
||||
default: |
||||
return 0; |
||||
} |
||||
} |
||||
|
||||
} // namespace
|
||||
|
||||
bool GetGameAction(const SDL_Event &event, GameAction *action) |
||||
{ |
||||
const ControllerButtonEvent ctrl_event = ToControllerButtonEvent(event); |
||||
switch (ctrl_event.button) { |
||||
case ControllerButton::AXIS_TRIGGERLEFT: // ZL (aka L2)
|
||||
if (!ctrl_event.up) |
||||
*action = GameAction(GameActionType::USE_HEALTH_POTION); |
||||
return true; |
||||
case ControllerButton::AXIS_TRIGGERRIGHT: // ZR (aka R2)
|
||||
if (!ctrl_event.up) |
||||
*action = GameAction(GameActionType::USE_MANA_POTION); |
||||
return true; |
||||
case ControllerButton::BUTTON_B: // Right button
|
||||
if (InGameMenu()) |
||||
break; // Map to keyboard key
|
||||
if (!ctrl_event.up) |
||||
*action = GameAction(GameActionType::PRIMARY_ACTION); |
||||
return true; |
||||
case ControllerButton::BUTTON_Y: // Top button
|
||||
if (InGameMenu()) |
||||
break; // Map to keyboard key
|
||||
if (!ctrl_event.up) |
||||
*action = GameAction(GameActionType::SECONDARY_ACTION); |
||||
return true; |
||||
case ControllerButton::BUTTON_A: // Bottom button
|
||||
if (InGameMenu()) |
||||
break; // Map to keyboard key
|
||||
if (!ctrl_event.up) |
||||
*action = GameAction(GameActionType::TOGGLE_QUICK_SPELL_MENU); |
||||
return true; |
||||
case ControllerButton::BUTTON_LEFTSHOULDER: |
||||
if (!stextflag && !ctrl_event.up) |
||||
*action = GameAction(GameActionType::TOGGLE_CHARACTER_INFO); |
||||
return true; |
||||
case ControllerButton::BUTTON_RIGHTSHOULDER: |
||||
if (!stextflag && !ctrl_event.up) |
||||
*action = GameAction(GameActionType::TOGGLE_INVENTORY); |
||||
return true; |
||||
case ControllerButton::BUTTON_DPAD_UP: |
||||
case ControllerButton::BUTTON_DPAD_DOWN: |
||||
case ControllerButton::BUTTON_DPAD_LEFT: |
||||
case ControllerButton::BUTTON_DPAD_RIGHT: |
||||
if (InGameMenu()) |
||||
break; |
||||
// The rest is handled in charMovement() on every game_logic() call.
|
||||
return true; |
||||
case ControllerButton::BUTTON_RIGHTSTICK: |
||||
*action = GameActionSendMouseLeftClick { ctrl_event.up }; |
||||
return true; |
||||
default: |
||||
break; |
||||
} |
||||
|
||||
// By default, map to a keyboard key.
|
||||
if (ctrl_event.button != ControllerButton::NONE) { |
||||
*action = GameActionSendKey{ translate_controller_button_to_key(ctrl_event.button), |
||||
ctrl_event.up }; |
||||
return true; |
||||
} |
||||
|
||||
#ifndef USE_SDL1 |
||||
// Ignore unhandled joystick events if gamepad is active.
|
||||
// We receive the same events as gamepad events.
|
||||
if (CurrentGameController() != nullptr && event.type >= SDL_JOYAXISMOTION && event.type <= SDL_JOYBUTTONUP) { |
||||
return true; |
||||
} |
||||
#endif |
||||
|
||||
return false; |
||||
} |
||||
|
||||
bool ShouldSkipMovie(const SDL_Event &event) |
||||
{ |
||||
if (GetMenuAction(event) != MenuAction::NONE) |
||||
return true; |
||||
switch (event.type) { |
||||
case SDL_MOUSEBUTTONDOWN: |
||||
case SDL_MOUSEBUTTONUP: |
||||
return event.button.button == SDL_BUTTON_LEFT; |
||||
case SDL_KEYDOWN: |
||||
case SDL_KEYUP: |
||||
return true; |
||||
default: |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
MoveDirection GetMoveDirection() |
||||
{ |
||||
const float stickX = leftStickX; |
||||
const float stickY = leftStickY; |
||||
MoveDirection result{ MoveDirectionX::NONE, MoveDirectionY::NONE }; |
||||
|
||||
if (stickY >= 0.5 || IsControllerButtonPressed(ControllerButton::BUTTON_DPAD_UP)) { |
||||
result.y = MoveDirectionY::UP; |
||||
} else if (stickY <= -0.5 || IsControllerButtonPressed(ControllerButton::BUTTON_DPAD_DOWN)) { |
||||
result.y = MoveDirectionY::DOWN; |
||||
} |
||||
|
||||
if (stickX <= -0.5 || IsControllerButtonPressed(ControllerButton::BUTTON_DPAD_LEFT)) { |
||||
result.x = MoveDirectionX::LEFT; |
||||
} else if (stickX >= 0.5 || IsControllerButtonPressed(ControllerButton::BUTTON_DPAD_RIGHT)) { |
||||
result.x = MoveDirectionX::RIGHT; |
||||
} |
||||
|
||||
return result; |
||||
} |
||||
|
||||
} // namespace dvl
|
||||
@ -0,0 +1,79 @@
|
||||
#pragma once |
||||
|
||||
#include "devilution.h" |
||||
|
||||
namespace dvl { |
||||
|
||||
enum class GameActionType { |
||||
NONE = 0, |
||||
USE_HEALTH_POTION, |
||||
USE_MANA_POTION, |
||||
PRIMARY_ACTION, // Talk to towners, click on inv items, attack, etc.
|
||||
SECONDARY_ACTION, // Open chests, doors, pickup items.
|
||||
TOGGLE_INVENTORY, |
||||
TOGGLE_CHARACTER_INFO, |
||||
TOGGLE_QUICK_SPELL_MENU, |
||||
SEND_KEY, |
||||
SEND_MOUSE_LEFT_CLICK |
||||
}; |
||||
|
||||
struct GameActionSendKey { |
||||
DWORD vk_code; |
||||
bool up; |
||||
}; |
||||
|
||||
struct GameActionSendMouseLeftClick { |
||||
bool up; |
||||
}; |
||||
|
||||
struct GameAction { |
||||
GameActionType type; |
||||
|
||||
GameAction() |
||||
: type(GameActionType::NONE) |
||||
{ |
||||
} |
||||
|
||||
explicit GameAction(GameActionType type) |
||||
: type(type) |
||||
{ |
||||
} |
||||
|
||||
GameAction(GameActionSendKey send_key) |
||||
: type(GameActionType::SEND_KEY) |
||||
, send_key(send_key) |
||||
{ |
||||
} |
||||
|
||||
GameAction(GameActionSendMouseLeftClick send_mouse_left_click) |
||||
: type(GameActionType::SEND_MOUSE_LEFT_CLICK) |
||||
, send_mouse_left_click(send_mouse_left_click) |
||||
{ |
||||
} |
||||
|
||||
union { |
||||
GameActionSendKey send_key; |
||||
GameActionSendMouseLeftClick send_mouse_left_click; |
||||
}; |
||||
}; |
||||
|
||||
bool GetGameAction(const SDL_Event &event, GameAction *action); |
||||
bool ShouldSkipMovie(const SDL_Event &event); |
||||
|
||||
enum class MoveDirectionX { |
||||
NONE = 0, |
||||
LEFT, |
||||
RIGHT |
||||
}; |
||||
enum class MoveDirectionY { |
||||
NONE = 0, |
||||
UP, |
||||
DOWN |
||||
}; |
||||
struct MoveDirection { |
||||
MoveDirectionX x; |
||||
MoveDirectionY y; |
||||
}; |
||||
MoveDirection GetMoveDirection(); |
||||
|
||||
} // namespace dvl
|
||||
@ -0,0 +1,74 @@
|
||||
#include "controls/menu_controls.h" |
||||
|
||||
#include "controls/controller.h" |
||||
|
||||
namespace dvl { |
||||
|
||||
MenuAction GetMenuAction(const SDL_Event &event) |
||||
{ |
||||
const ControllerButtonEvent ctrl_event = ToControllerButtonEvent(event); |
||||
if (!ctrl_event.up) { |
||||
switch (ctrl_event.button) { |
||||
case ControllerButton::BUTTON_B: // Right button
|
||||
case ControllerButton::BUTTON_START: |
||||
return MenuAction::SELECT; |
||||
case ControllerButton::BUTTON_BACK: |
||||
case ControllerButton::BUTTON_A: // Bottom button
|
||||
return MenuAction::BACK; |
||||
case ControllerButton::BUTTON_X: // Left button
|
||||
return MenuAction::DELETE; |
||||
case ControllerButton::BUTTON_DPAD_UP: |
||||
return MenuAction::UP; |
||||
case ControllerButton::BUTTON_DPAD_DOWN: |
||||
return MenuAction::DOWN; |
||||
case ControllerButton::BUTTON_DPAD_LEFT: |
||||
return MenuAction::LEFT; |
||||
case ControllerButton::BUTTON_DPAD_RIGHT: |
||||
return MenuAction::RIGHT; |
||||
case ControllerButton::BUTTON_LEFTSHOULDER: |
||||
return MenuAction::PAGE_UP; |
||||
case ControllerButton::BUTTON_RIGHTSHOULDER: |
||||
return MenuAction::PAGE_DOWN; |
||||
default: |
||||
break; |
||||
} |
||||
} |
||||
|
||||
#if HAS_KBCTRL == 0 |
||||
if (event.type == SDL_KEYDOWN) { |
||||
switch (event.key.keysym.sym) { |
||||
case SDLK_UP: |
||||
return MenuAction::UP; |
||||
case SDLK_DOWN: |
||||
return MenuAction::DOWN; |
||||
case SDLK_TAB: |
||||
if (SDL_GetModState() & KMOD_SHIFT) |
||||
return MenuAction::UP; |
||||
else |
||||
return MenuAction::DOWN; |
||||
case SDLK_PAGEUP: |
||||
return MenuAction::PAGE_UP; |
||||
case SDLK_PAGEDOWN: |
||||
return MenuAction::PAGE_DOWN; |
||||
case SDLK_RETURN: |
||||
case SDLK_KP_ENTER: |
||||
case SDLK_SPACE: |
||||
return MenuAction::SELECT; |
||||
case SDLK_DELETE: |
||||
return MenuAction::DELETE; |
||||
case SDLK_LEFT: |
||||
return MenuAction::LEFT; |
||||
case SDLK_RIGHT: |
||||
return MenuAction::RIGHT; |
||||
case SDLK_ESCAPE: |
||||
return MenuAction::BACK; |
||||
default: |
||||
break; |
||||
} |
||||
} |
||||
#endif |
||||
|
||||
return MenuAction::NONE; |
||||
} // namespace dvl
|
||||
|
||||
} // namespace dvl
|
||||
@ -0,0 +1,24 @@
|
||||
#pragma once |
||||
|
||||
#include "devilution.h" |
||||
|
||||
namespace dvl { |
||||
|
||||
enum class MenuAction { |
||||
NONE = 0, |
||||
SELECT, |
||||
BACK, |
||||
DELETE, |
||||
|
||||
UP, |
||||
DOWN, |
||||
LEFT, |
||||
RIGHT, |
||||
|
||||
PAGE_UP, |
||||
PAGE_DOWN, |
||||
}; |
||||
|
||||
MenuAction GetMenuAction(const SDL_Event &event); |
||||
|
||||
} // namespace dvl
|
||||
@ -1,29 +1,35 @@
|
||||
#pragma once |
||||
// Controller actions implementation
|
||||
|
||||
#include "devilution.h" |
||||
|
||||
namespace dvl { |
||||
|
||||
// Run on every game logic iteration.
|
||||
void plrctrls_game_logic(); |
||||
|
||||
// Runs before the start of event loop drain, even if there are no events.
|
||||
void plrctrls_event_loop(); |
||||
|
||||
// Moves the map if active, the cursor otherwise.
|
||||
void HandleRightStickMotion(); |
||||
|
||||
// Whether we're in a dialog menu that the game handles natively with keyboard controls.
|
||||
bool InGameMenu(); |
||||
|
||||
void checkTownersNearby(bool interact); |
||||
void checkItemsNearby(bool interact); |
||||
void keyboardExpansion(int vikey); |
||||
void charMovement(); |
||||
void movements(int key); |
||||
bool checkMonstersNearby(bool attack); |
||||
extern bool newCurHidden; |
||||
void invMove(int key); |
||||
void HideCursor(); |
||||
void useBeltPotion(bool mana); |
||||
|
||||
// Talk to towners, click on inv items, attack, etc.
|
||||
void performPrimaryAction(); |
||||
|
||||
// Open chests, doors, pickup items.
|
||||
void performSecondaryAction(); |
||||
|
||||
typedef struct coords { |
||||
int x; |
||||
int y; |
||||
} coords; |
||||
extern coords speedspellscoords[50]; |
||||
extern int speedspellcount; |
||||
extern const InvXY InvRect[73]; // wasn't made public, so I'll add this here from inv.cpp
|
||||
|
||||
extern DWORD talkwait; |
||||
extern DWORD talktick; |
||||
extern DWORD castwait; |
||||
|
||||
#define INV_TOP 240; |
||||
#define INV_LEFT 350; |
||||
#define INV_HEIGHT 320; |
||||
#define DISPLAY_HEIGHT 360; |
||||
#define DISPLAY_WIDTH 640; |
||||
} // namespace dvl
|
||||
|
||||
Loading…
Reference in new issue