mirror of
https://github.com/vcmi/vcmi.git
synced 2025-03-29 21:56:54 +02:00
Unified game controller input with keyboard/mouse
This commit is contained in:
parent
9a71614588
commit
1dc27046ef
@ -35,7 +35,6 @@ set(client_SRCS
|
||||
eventsSDL/InputSourceText.cpp
|
||||
eventsSDL/InputSourceTouch.cpp
|
||||
eventsSDL/InputSourceGameController.cpp
|
||||
eventsSDL/GameControllerConfig.cpp
|
||||
|
||||
gui/CGuiHandler.cpp
|
||||
gui/CIntObject.cpp
|
||||
@ -214,8 +213,7 @@ set(client_HEADERS
|
||||
eventsSDL/InputSourceMouse.h
|
||||
eventsSDL/InputSourceText.h
|
||||
eventsSDL/InputSourceTouch.h
|
||||
eventsSDL/InputSourceGameController.h
|
||||
eventsSDL/GameControllerConfig.h
|
||||
eventsSDL/InputSourceGameController.h
|
||||
|
||||
gui/CGuiHandler.h
|
||||
gui/CIntObject.h
|
||||
|
@ -1,212 +0,0 @@
|
||||
/*
|
||||
* GameControllerConfig.cpp, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
#include <SDL.h>
|
||||
|
||||
#include "StdInc.h"
|
||||
#include "GameControllerConfig.h"
|
||||
#include "../gui/CGuiHandler.h"
|
||||
#include "../gui/ShortcutHandler.h"
|
||||
|
||||
|
||||
GameControllerConfig::GameControllerConfig(): leftAxisType(AxisType::NONE), rightAxisType(AxisType::NONE)
|
||||
{
|
||||
load();
|
||||
}
|
||||
|
||||
void GameControllerConfig::load()
|
||||
{
|
||||
const JsonNode config = JsonUtils::assembleFromFiles("config/shortcutsConfig");
|
||||
for(auto const & entry : config["joystick"].Struct())
|
||||
{
|
||||
std::string configName = entry.first;
|
||||
if(configName == "leftaxis")
|
||||
leftAxisType = parseAxis(entry.first, entry.second);
|
||||
else if (configName == "rightaxis")
|
||||
rightAxisType = parseAxis(entry.first, entry.second);
|
||||
else if (configName == "lefttrigger" || configName == "righttrigger")
|
||||
parseTrigger(entry.first, entry.second);
|
||||
else
|
||||
parseButton(entry.first, entry.second);
|
||||
}
|
||||
}
|
||||
|
||||
AxisType GameControllerConfig::parseAxis(const std::string & key, const JsonNode & value)
|
||||
{
|
||||
if(!value.isString())
|
||||
{
|
||||
logGlobal->error("The value of joystick config key %s should be a string!", key);
|
||||
return AxisType::NONE;
|
||||
}
|
||||
|
||||
std::string featureName = value.String();
|
||||
if(featureName == "cursorMotion")
|
||||
return AxisType::CURSOR_MOTION;
|
||||
else if(featureName == "mapScroll")
|
||||
return AxisType::MAP_SCROLL;
|
||||
else if(featureName != "")
|
||||
logGlobal->error("Unknown value %s of joystick config key %s!", featureName, key);
|
||||
return AxisType::NONE;
|
||||
}
|
||||
|
||||
void GameControllerConfig::parseTrigger(const std::string & key, const JsonNode & value)
|
||||
{
|
||||
std::vector<std::string> operations = getOperations(key, value);
|
||||
SDL_GameControllerAxis triggerAxis = key == "lefttrigger" ?
|
||||
SDL_CONTROLLER_AXIS_TRIGGERLEFT : SDL_CONTROLLER_AXIS_TRIGGERRIGHT;
|
||||
std::vector<EShortcut> shortcuts;
|
||||
for(const auto & operation : operations)
|
||||
{
|
||||
if(operation == "mouseLeftClick")
|
||||
{
|
||||
leftClickTriggerSet.insert(triggerAxis);
|
||||
}
|
||||
else if(operation == "mouseRightClick")
|
||||
{
|
||||
rightClickTriggerSet.insert(triggerAxis);
|
||||
}
|
||||
else
|
||||
{
|
||||
EShortcut shortcut = GH.shortcuts().findShortcut(operation);
|
||||
if(shortcut == EShortcut::NONE)
|
||||
logGlobal->error("Shortcut %s in joystick config key %s is invalid.", operation, key);
|
||||
else
|
||||
shortcuts.push_back(shortcut);
|
||||
}
|
||||
}
|
||||
|
||||
if(!shortcuts.empty())
|
||||
triggerShortcutsMap.emplace(triggerAxis, std::move(shortcuts));
|
||||
}
|
||||
|
||||
void GameControllerConfig::parseButton(const std::string & key, const JsonNode & value)
|
||||
{
|
||||
std::vector<std::string> operations = getOperations(key, value);
|
||||
SDL_GameControllerButton button = SDL_GameControllerGetButtonFromString(key.c_str());
|
||||
if(button == SDL_CONTROLLER_BUTTON_INVALID)
|
||||
{
|
||||
logGlobal->error("Joystick config key %s is invalid.", key);
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<EShortcut> shortcuts;
|
||||
for(const auto & operation : operations)
|
||||
{
|
||||
if(operation == "mouseLeftClick")
|
||||
{
|
||||
leftClickButtonSet.insert(button);
|
||||
}
|
||||
else if(operation == "mouseRightClick")
|
||||
{
|
||||
rightClickButtonSet.insert(button);
|
||||
}
|
||||
else
|
||||
{
|
||||
EShortcut shortcut = GH.shortcuts().findShortcut(operation);
|
||||
if(shortcut == EShortcut::NONE)
|
||||
logGlobal->error("Shortcut %s in joystick config key %s is invalid.", operation, key);
|
||||
else
|
||||
shortcuts.push_back(shortcut);
|
||||
}
|
||||
}
|
||||
|
||||
if(!shortcuts.empty())
|
||||
buttonShortcutsMap.emplace(button, std::move(shortcuts));
|
||||
}
|
||||
|
||||
const AxisType & GameControllerConfig::getLeftAxisType()
|
||||
{
|
||||
return leftAxisType;
|
||||
}
|
||||
|
||||
const AxisType & GameControllerConfig::getRightAxisType()
|
||||
{
|
||||
return rightAxisType;
|
||||
}
|
||||
|
||||
std::vector<std::string> GameControllerConfig::getOperations(const std::string & key, const JsonNode & value)
|
||||
{
|
||||
std::vector<std::string> operations;
|
||||
if(value.isString())
|
||||
{
|
||||
operations.push_back(value.String());
|
||||
}
|
||||
else if(value.isVector())
|
||||
{
|
||||
for(auto const & entryVector : value.Vector())
|
||||
{
|
||||
if(!entryVector.isString())
|
||||
logGlobal->error("The vector of joystick config key %s can not contain non-string element.", key);
|
||||
else
|
||||
operations.push_back(entryVector.String());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logGlobal->error("The value of joystick config key %s should be string or string vector.", key);
|
||||
}
|
||||
return operations;
|
||||
}
|
||||
|
||||
bool GameControllerConfig::isLeftClickButton(int buttonValue)
|
||||
{
|
||||
SDL_GameControllerButton button = static_cast<SDL_GameControllerButton>(buttonValue);
|
||||
return leftClickButtonSet.find(button) != leftClickButtonSet.end();
|
||||
}
|
||||
|
||||
bool GameControllerConfig::isRightClickButton(int buttonValue)
|
||||
{
|
||||
SDL_GameControllerButton button = static_cast<SDL_GameControllerButton>(buttonValue);
|
||||
return rightClickButtonSet.find(button) != rightClickButtonSet.end();
|
||||
}
|
||||
|
||||
bool GameControllerConfig::isShortcutsButton(int buttonValue)
|
||||
{
|
||||
SDL_GameControllerButton button = static_cast<SDL_GameControllerButton>(buttonValue);
|
||||
return buttonShortcutsMap.find(button) != buttonShortcutsMap.end();
|
||||
}
|
||||
|
||||
const std::vector<EShortcut> & GameControllerConfig::getButtonShortcuts(int buttonValue)
|
||||
{
|
||||
SDL_GameControllerButton button = static_cast<SDL_GameControllerButton>(buttonValue);
|
||||
auto it = buttonShortcutsMap.find(button);
|
||||
if(it != buttonShortcutsMap.end())
|
||||
return it->second;
|
||||
static std::vector<EShortcut> emptyVec;
|
||||
return emptyVec;
|
||||
}
|
||||
|
||||
bool GameControllerConfig::isLeftClickTrigger(int axisValue)
|
||||
{
|
||||
SDL_GameControllerAxis axis = static_cast<SDL_GameControllerAxis>(axisValue);
|
||||
return leftClickTriggerSet.find(axis) != leftClickTriggerSet.end();
|
||||
}
|
||||
|
||||
bool GameControllerConfig::isRightClickTrigger(int axisValue)
|
||||
{
|
||||
SDL_GameControllerAxis axis = static_cast<SDL_GameControllerAxis>(axisValue);
|
||||
return rightClickTriggerSet.find(axis) != rightClickTriggerSet.end();
|
||||
}
|
||||
|
||||
bool GameControllerConfig::isShortcutsTrigger(int axisValue)
|
||||
{
|
||||
SDL_GameControllerAxis axis = static_cast<SDL_GameControllerAxis>(axisValue);
|
||||
return triggerShortcutsMap.find(axis) != triggerShortcutsMap.end();
|
||||
}
|
||||
|
||||
const std::vector<EShortcut> & GameControllerConfig::getTriggerShortcuts(int axisValue)
|
||||
{
|
||||
SDL_GameControllerAxis axis = static_cast<SDL_GameControllerAxis>(axisValue);
|
||||
auto it = triggerShortcutsMap.find(axis);
|
||||
if(it != triggerShortcutsMap.end())
|
||||
return it->second;
|
||||
static std::vector<EShortcut> emptyVec;
|
||||
return emptyVec;
|
||||
}
|
||||
|
@ -1,59 +0,0 @@
|
||||
/*
|
||||
* GameControllerConfig.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#include "../gui/Shortcut.h"
|
||||
#include "../../lib/json/JsonUtils.h"
|
||||
|
||||
enum AxisType
|
||||
{
|
||||
CURSOR_MOTION,
|
||||
MAP_SCROLL,
|
||||
NONE
|
||||
};
|
||||
|
||||
class GameControllerConfig {
|
||||
using ButtonShortcutsMap = std::map<SDL_GameControllerButton, std::vector<EShortcut> >;
|
||||
using TriggerShortcutsMap = std::map<SDL_GameControllerAxis, std::vector<EShortcut> >;
|
||||
ButtonShortcutsMap buttonShortcutsMap;
|
||||
TriggerShortcutsMap triggerShortcutsMap;
|
||||
std::set<SDL_GameControllerButton> leftClickButtonSet;
|
||||
std::set<SDL_GameControllerButton> rightClickButtonSet;
|
||||
std::set<SDL_GameControllerAxis> leftClickTriggerSet;
|
||||
std::set<SDL_GameControllerAxis> rightClickTriggerSet;
|
||||
AxisType leftAxisType;
|
||||
AxisType rightAxisType;
|
||||
|
||||
void load();
|
||||
std::vector<std::string> getOperations(const std::string & key, const JsonNode & value);
|
||||
AxisType parseAxis(const std::string & key, const JsonNode & value);
|
||||
void parseTrigger(const std::string & key, const JsonNode & value);
|
||||
void parseButton(const std::string & key, const JsonNode & value);
|
||||
|
||||
public:
|
||||
GameControllerConfig();
|
||||
~GameControllerConfig() = default;
|
||||
|
||||
const AxisType & getLeftAxisType();
|
||||
const AxisType & getRightAxisType();
|
||||
|
||||
bool isLeftClickButton(int buttonValue);
|
||||
bool isRightClickButton(int buttonValue);
|
||||
bool isShortcutsButton(int buttonValue);
|
||||
const std::vector<EShortcut> & getButtonShortcuts(int buttonValue);
|
||||
|
||||
bool isLeftClickTrigger(int axisValue);
|
||||
bool isRightClickTrigger(int axisValue);
|
||||
bool isShortcutsTrigger(int axisValue);
|
||||
const std::vector<EShortcut> & getTriggerShortcuts(int axisValue);
|
||||
};
|
@ -18,8 +18,6 @@
|
||||
#include "../gui/EventDispatcher.h"
|
||||
#include "../gui/ShortcutHandler.h"
|
||||
|
||||
|
||||
|
||||
void InputSourceGameController::gameControllerDeleter(SDL_GameController * gameController)
|
||||
{
|
||||
if(gameController)
|
||||
@ -135,76 +133,56 @@ int InputSourceGameController::getRealAxisValue(int value)
|
||||
return (value - base) * AXIS_MAX_ZOOM / (AXIS_MAX_ZOOM - AXIS_DEAD_ZOOM);
|
||||
}
|
||||
|
||||
void InputSourceGameController::dispatchTriggerShortcuts(const std::vector<EShortcut> & shortcutsVector, int axisValue)
|
||||
void InputSourceGameController::dispatchAxisShortcuts(const std::vector<EShortcut> & shortcutsVector, SDL_GameControllerAxis axisID, int axisValue)
|
||||
{
|
||||
if(axisValue >= TRIGGER_PRESS_THRESHOLD)
|
||||
GH.events().dispatchShortcutPressed(shortcutsVector);
|
||||
{
|
||||
if (!pressedAxes.count(axisID))
|
||||
{
|
||||
GH.events().dispatchShortcutPressed(shortcutsVector);
|
||||
pressedAxes.insert(axisID);
|
||||
}
|
||||
}
|
||||
else
|
||||
GH.events().dispatchShortcutReleased(shortcutsVector);
|
||||
}
|
||||
|
||||
void InputSourceGameController::dispatchTriggerLeftClick(int axisValue)
|
||||
{
|
||||
const Point & position = GH.input().getCursorPosition();
|
||||
if(axisValue >= TRIGGER_PRESS_THRESHOLD)
|
||||
GH.events().dispatchMouseLeftButtonPressed(position, 0);
|
||||
else
|
||||
GH.events().dispatchMouseLeftButtonReleased(position, 0);
|
||||
}
|
||||
|
||||
void InputSourceGameController::dispatchTriggerRightClick(int axisValue)
|
||||
{
|
||||
const Point & position = GH.input().getCursorPosition();
|
||||
if(axisValue >= TRIGGER_PRESS_THRESHOLD)
|
||||
GH.events().dispatchShowPopup(position, 0);
|
||||
else
|
||||
GH.events().dispatchClosePopup(position);
|
||||
{
|
||||
if (pressedAxes.count(axisID))
|
||||
{
|
||||
GH.events().dispatchShortcutReleased(shortcutsVector);
|
||||
pressedAxes.erase(axisID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InputSourceGameController::handleEventAxisMotion(const SDL_ControllerAxisEvent & axis)
|
||||
{
|
||||
tryToConvertCursor();
|
||||
if(axis.axis == SDL_CONTROLLER_AXIS_LEFTX)
|
||||
|
||||
SDL_GameControllerAxis axisID = static_cast<SDL_GameControllerAxis>(axis.axis);
|
||||
std::string axisName = SDL_GameControllerGetStringForAxis(axisID);
|
||||
|
||||
auto axisActions = GH.shortcuts().translateJoystickAxis(axisName);
|
||||
auto buttonActions = GH.shortcuts().translateJoystickButton(axisName);
|
||||
|
||||
for (auto const & action : axisActions)
|
||||
{
|
||||
if(config.getLeftAxisType() == AxisType::CURSOR_MOTION)
|
||||
cursorAxisValueX = getRealAxisValue(axis.value);
|
||||
else if(config.getLeftAxisType() == AxisType::MAP_SCROLL)
|
||||
scrollAxisValueX = getRealAxisValue(axis.value);
|
||||
}
|
||||
else if(axis.axis == SDL_CONTROLLER_AXIS_LEFTY)
|
||||
{
|
||||
if(config.getLeftAxisType() == AxisType::CURSOR_MOTION)
|
||||
cursorAxisValueY = getRealAxisValue(axis.value);
|
||||
else if(config.getLeftAxisType() == AxisType::MAP_SCROLL)
|
||||
scrollAxisValueY = getRealAxisValue(axis.value);
|
||||
}
|
||||
if(axis.axis == SDL_CONTROLLER_AXIS_RIGHTX)
|
||||
{
|
||||
if(config.getRightAxisType() == AxisType::CURSOR_MOTION)
|
||||
cursorAxisValueX = getRealAxisValue(axis.value);
|
||||
else if(config.getRightAxisType() == AxisType::MAP_SCROLL)
|
||||
scrollAxisValueX = getRealAxisValue(axis.value);
|
||||
}
|
||||
else if(axis.axis == SDL_CONTROLLER_AXIS_RIGHTY)
|
||||
{
|
||||
if(config.getRightAxisType() == AxisType::CURSOR_MOTION)
|
||||
cursorAxisValueY = getRealAxisValue(axis.value);
|
||||
else if(config.getRightAxisType() == AxisType::MAP_SCROLL)
|
||||
scrollAxisValueY = getRealAxisValue(axis.value);
|
||||
}
|
||||
else if(config.isLeftClickTrigger(axis.axis))
|
||||
{
|
||||
dispatchTriggerLeftClick(axis.value);
|
||||
}
|
||||
else if(config.isRightClickTrigger(axis.axis))
|
||||
{
|
||||
dispatchTriggerRightClick(axis.value);
|
||||
}
|
||||
else if(config.isShortcutsTrigger(axis.axis))
|
||||
{
|
||||
const auto & shortcutsVector = config.getTriggerShortcuts(axis.axis);
|
||||
dispatchTriggerShortcuts(shortcutsVector, axis.value);
|
||||
switch (action)
|
||||
{
|
||||
case EShortcut::MOUSE_CURSOR_X:
|
||||
cursorAxisValueX = getRealAxisValue(axis.value);
|
||||
break;
|
||||
case EShortcut::MOUSE_CURSOR_Y:
|
||||
cursorAxisValueY = getRealAxisValue(axis.value);
|
||||
break;
|
||||
case EShortcut::MOUSE_SWIPE_X:
|
||||
scrollAxisValueX = getRealAxisValue(axis.value);
|
||||
break;
|
||||
case EShortcut::MOUSE_SWIPE_Y:
|
||||
scrollAxisValueY = getRealAxisValue(axis.value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
dispatchAxisShortcuts(buttonActions, axisID, axis.value);
|
||||
}
|
||||
|
||||
void InputSourceGameController::tryToConvertCursor()
|
||||
@ -222,42 +200,16 @@ void InputSourceGameController::tryToConvertCursor()
|
||||
|
||||
void InputSourceGameController::handleEventButtonDown(const SDL_ControllerButtonEvent & button)
|
||||
{
|
||||
const Point & position = GH.input().getCursorPosition();
|
||||
|
||||
if(config.isLeftClickButton(button.button))
|
||||
{
|
||||
GH.events().dispatchMouseLeftButtonPressed(position, 0);
|
||||
}
|
||||
|
||||
if(config.isRightClickButton(button.button))
|
||||
{
|
||||
GH.events().dispatchShowPopup(position, 0);
|
||||
}
|
||||
|
||||
if(config.isShortcutsButton(button.button))
|
||||
{
|
||||
const auto & shortcutsVector = config.getButtonShortcuts(button.button);
|
||||
GH.events().dispatchShortcutPressed(shortcutsVector);
|
||||
}
|
||||
std::string buttonName = SDL_GameControllerGetStringForButton(static_cast<SDL_GameControllerButton>(button.button));
|
||||
const auto & shortcutsVector = GH.shortcuts().translateJoystickButton(buttonName);
|
||||
GH.events().dispatchShortcutPressed(shortcutsVector);
|
||||
}
|
||||
|
||||
void InputSourceGameController::handleEventButtonUp(const SDL_ControllerButtonEvent & button)
|
||||
{
|
||||
const Point & position = GH.input().getCursorPosition();
|
||||
|
||||
if(config.isLeftClickButton(button.button))
|
||||
{
|
||||
GH.events().dispatchMouseLeftButtonReleased(position, 0);
|
||||
}
|
||||
if(config.isRightClickButton(button.button))
|
||||
{
|
||||
GH.events().dispatchClosePopup(position);
|
||||
}
|
||||
if(config.isShortcutsButton(button.button))
|
||||
{
|
||||
const auto & shortcutsVector = config.getButtonShortcuts(button.button);
|
||||
GH.events().dispatchShortcutReleased(shortcutsVector);
|
||||
}
|
||||
std::string buttonName = SDL_GameControllerGetStringForButton(static_cast<SDL_GameControllerButton>(button.button));
|
||||
const auto & shortcutsVector = GH.shortcuts().translateJoystickButton(buttonName);
|
||||
GH.events().dispatchShortcutReleased(shortcutsVector);
|
||||
}
|
||||
|
||||
void InputSourceGameController::doCursorMove(int deltaX, int deltaY)
|
||||
|
@ -10,19 +10,24 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <SDL.h>
|
||||
#include <SDL_events.h>
|
||||
#include <SDL_gamecontroller.h>
|
||||
|
||||
#include "GameControllerConfig.h"
|
||||
#include "../gui/Shortcut.h"
|
||||
#include "../../lib/Point.h"
|
||||
|
||||
constexpr int AXIS_DEAD_ZOOM = 6000;
|
||||
constexpr int AXIS_MAX_ZOOM = 32000;
|
||||
constexpr int AXIS_MOVE_SPEED = 500;
|
||||
constexpr int AXIS_CURSOR_MOVE_INTERVAL = 1000;
|
||||
constexpr int TRIGGER_PRESS_THRESHOLD = 8000;
|
||||
|
||||
const int AXIS_DEAD_ZOOM = 6000;
|
||||
const int AXIS_MAX_ZOOM = 32000;
|
||||
const int AXIS_MOVE_SPEED = 500;
|
||||
const int AXIS_CURSOR_MOVE_INTERVAL = 1000;
|
||||
const int TRIGGER_PRESS_THRESHOLD = 8000;
|
||||
|
||||
enum class AxisType
|
||||
{
|
||||
CURSOR_MOTION,
|
||||
MAP_SCROLL,
|
||||
NONE
|
||||
};
|
||||
|
||||
/// Class that handles game controller input from SDL events
|
||||
class InputSourceGameController
|
||||
@ -31,7 +36,8 @@ class InputSourceGameController
|
||||
using GameControllerPtr = std::unique_ptr<SDL_GameController, decltype(&gameControllerDeleter)>;
|
||||
|
||||
std::map<int, GameControllerPtr> gameControllerMap;
|
||||
GameControllerConfig config;
|
||||
std::set<SDL_GameControllerAxis> pressedAxes;
|
||||
|
||||
long long lastCheckTime;
|
||||
int cursorAxisValueX;
|
||||
int cursorAxisValueY;
|
||||
@ -49,9 +55,7 @@ class InputSourceGameController
|
||||
void openGameController(int index);
|
||||
int getJoystickIndex(SDL_GameController * controller);
|
||||
int getRealAxisValue(int value);
|
||||
void dispatchTriggerShortcuts(const std::vector<EShortcut> & shortcutsVector, int axisValue);
|
||||
void dispatchTriggerLeftClick(int axisValue);
|
||||
void dispatchTriggerRightClick(int axisValue);
|
||||
void dispatchAxisShortcuts(const std::vector<EShortcut> & shortcutsVector, SDL_GameControllerAxis axisID, int axisValue);
|
||||
void tryToConvertCursor();
|
||||
void doCursorMove(int deltaX, int deltaY);
|
||||
int getMoveDis(float planDis);
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "CGuiHandler.h"
|
||||
#include "MouseButton.h"
|
||||
#include "WindowHandler.h"
|
||||
#include "gui/Shortcut.h"
|
||||
|
||||
#include "../../lib/Rect.h"
|
||||
|
||||
@ -74,6 +75,12 @@ void EventDispatcher::dispatchShortcutPressed(const std::vector<EShortcut> & sho
|
||||
{
|
||||
bool keysCaptured = false;
|
||||
|
||||
if (vstd::contains(shortcutsVector, EShortcut::MOUSE_LEFT))
|
||||
dispatchMouseLeftButtonPressed(GH.getCursorPosition(), 0);
|
||||
|
||||
if (vstd::contains(shortcutsVector, EShortcut::MOUSE_RIGHT))
|
||||
dispatchShowPopup(GH.getCursorPosition(), 0);
|
||||
|
||||
for(auto & i : keyinterested)
|
||||
for(EShortcut shortcut : shortcutsVector)
|
||||
if(i->captureThisKey(shortcut))
|
||||
@ -97,6 +104,12 @@ void EventDispatcher::dispatchShortcutReleased(const std::vector<EShortcut> & sh
|
||||
{
|
||||
bool keysCaptured = false;
|
||||
|
||||
if (vstd::contains(shortcutsVector, EShortcut::MOUSE_LEFT))
|
||||
dispatchMouseLeftButtonReleased(GH.getCursorPosition(), 0);
|
||||
|
||||
if (vstd::contains(shortcutsVector, EShortcut::MOUSE_RIGHT))
|
||||
dispatchClosePopup(GH.getCursorPosition());
|
||||
|
||||
for(auto & i : keyinterested)
|
||||
for(EShortcut shortcut : shortcutsVector)
|
||||
if(i->captureThisKey(shortcut))
|
||||
|
@ -13,6 +13,14 @@ enum class EShortcut
|
||||
{
|
||||
NONE,
|
||||
|
||||
// preudo-shortcuts that trigger mouse events
|
||||
MOUSE_LEFT,
|
||||
MOUSE_RIGHT,
|
||||
MOUSE_CURSOR_X,
|
||||
MOUSE_CURSOR_Y,
|
||||
MOUSE_SWIPE_X,
|
||||
MOUSE_SWIPE_Y,
|
||||
|
||||
// Global hotkeys that are available in multiple dialogs
|
||||
GLOBAL_ACCEPT, // Return - Accept query
|
||||
GLOBAL_CANCEL, // Escape - Cancel query
|
||||
|
@ -19,7 +19,16 @@ ShortcutHandler::ShortcutHandler()
|
||||
{
|
||||
const JsonNode config = JsonUtils::assembleFromFiles("config/shortcutsConfig");
|
||||
|
||||
for (auto const & entry : config["keyboard"].Struct())
|
||||
mappedKeyboardShortcuts = loadShortcuts(config["keyboard"]);
|
||||
mappedJoystickShortcuts = loadShortcuts(config["joystickButtons"]);
|
||||
mappedJoystickAxes = loadShortcuts(config["joystickAxes"]);
|
||||
}
|
||||
|
||||
std::multimap<std::string, EShortcut> ShortcutHandler::loadShortcuts(const JsonNode & data) const
|
||||
{
|
||||
std::multimap<std::string, EShortcut> result;
|
||||
|
||||
for (auto const & entry : data.Struct())
|
||||
{
|
||||
std::string shortcutName = entry.first;
|
||||
EShortcut shortcutID = findShortcut(shortcutName);
|
||||
@ -32,20 +41,22 @@ ShortcutHandler::ShortcutHandler()
|
||||
|
||||
if (entry.second.isString())
|
||||
{
|
||||
mappedShortcuts.emplace(entry.second.String(), shortcutID);
|
||||
result.emplace(entry.second.String(), shortcutID);
|
||||
}
|
||||
|
||||
if (entry.second.isVector())
|
||||
{
|
||||
for (auto const & entryVector : entry.second.Vector())
|
||||
mappedShortcuts.emplace(entryVector.String(), shortcutID);
|
||||
result.emplace(entryVector.String(), shortcutID);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<EShortcut> ShortcutHandler::translateKeycode(const std::string & key) const
|
||||
std::vector<EShortcut> ShortcutHandler::translateShortcut(const std::multimap<std::string, EShortcut> & options, const std::string & key) const
|
||||
{
|
||||
auto range = mappedShortcuts.equal_range(key);
|
||||
auto range = options.equal_range(key);
|
||||
|
||||
// FIXME: some code expects calls to keyPressed / captureThisKey even without defined hotkeys
|
||||
if (range.first == range.second)
|
||||
@ -59,9 +70,30 @@ std::vector<EShortcut> ShortcutHandler::translateKeycode(const std::string & key
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<EShortcut> ShortcutHandler::translateKeycode(const std::string & key) const
|
||||
{
|
||||
return translateShortcut(mappedKeyboardShortcuts, key);
|
||||
}
|
||||
|
||||
std::vector<EShortcut> ShortcutHandler::translateJoystickButton(const std::string & key) const
|
||||
{
|
||||
return translateShortcut(mappedJoystickShortcuts, key);
|
||||
}
|
||||
|
||||
std::vector<EShortcut> ShortcutHandler::translateJoystickAxis(const std::string & key) const
|
||||
{
|
||||
return translateShortcut(mappedJoystickAxes, key);
|
||||
}
|
||||
|
||||
EShortcut ShortcutHandler::findShortcut(const std::string & identifier ) const
|
||||
{
|
||||
static const std::map<std::string, EShortcut> shortcutNames = {
|
||||
{"mouseClickLeft", EShortcut::MOUSE_LEFT },
|
||||
{"mouseClickRight", EShortcut::MOUSE_RIGHT },
|
||||
{"mouseCursorX", EShortcut::MOUSE_CURSOR_X, },
|
||||
{"mouseCursorY", EShortcut::MOUSE_CURSOR_Y, },
|
||||
{"mouseSwipeX", EShortcut::MOUSE_SWIPE_X, },
|
||||
{"mouseSwipeY", EShortcut::MOUSE_SWIPE_Y, },
|
||||
{"globalAccept", EShortcut::GLOBAL_ACCEPT },
|
||||
{"globalCancel", EShortcut::GLOBAL_CANCEL },
|
||||
{"globalReturn", EShortcut::GLOBAL_RETURN },
|
||||
|
@ -12,15 +12,29 @@
|
||||
|
||||
enum class EShortcut;
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
class JsonNode;
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
||||
class ShortcutHandler
|
||||
{
|
||||
std::multimap<std::string, EShortcut> mappedShortcuts;
|
||||
std::multimap<std::string, EShortcut> mappedKeyboardShortcuts;
|
||||
std::multimap<std::string, EShortcut> mappedJoystickShortcuts;
|
||||
std::multimap<std::string, EShortcut> mappedJoystickAxes;
|
||||
|
||||
std::multimap<std::string, EShortcut> loadShortcuts(const JsonNode & data) const;
|
||||
std::vector<EShortcut> translateShortcut(const std::multimap<std::string, EShortcut> & options, const std::string & key) const;
|
||||
|
||||
public:
|
||||
ShortcutHandler();
|
||||
|
||||
/// returns list of shortcuts assigned to provided SDL keycode
|
||||
std::vector<EShortcut> translateKeycode(const std::string & key) const;
|
||||
|
||||
std::vector<EShortcut> translateJoystickButton(const std::string & key) const;
|
||||
|
||||
std::vector<EShortcut> translateJoystickAxis(const std::string & key) const;
|
||||
|
||||
/// attempts to find shortcut by its unique identifier. Returns EShortcut::NONE on failure
|
||||
EShortcut findShortcut(const std::string & identifier ) const;
|
||||
};
|
||||
|
@ -110,6 +110,7 @@
|
||||
"battleConsoleDown": "Down",
|
||||
"battleTacticsNext": "Space",
|
||||
"battleTacticsEnd": [ "Return", "Keypad Enter"],
|
||||
"battleToggleHeroesStats": [],
|
||||
"battleSelectAction": "S",
|
||||
"townOpenTavern": "T",
|
||||
"townSwapArmies": "Space",
|
||||
@ -137,24 +138,72 @@
|
||||
"heroCostume8": "8",
|
||||
"heroCostume9": "9"
|
||||
},
|
||||
"joystick": {
|
||||
"leftaxis": "cursorMotion",
|
||||
"rightaxis": "mapScroll",
|
||||
"a": ["globalAccept", "globalReturn", "lobbyBeginStandardGame", "lobbyBeginCampaign", "lobbyLoadGame", "lobbySaveGame", "adventureViewSelected", "adventureExitWorldView", "battleTacticsEnd"],
|
||||
"b": ["globalCancel", "globalReturn", "adventureExitWorldView"],
|
||||
"x": "mouseLeftClick",
|
||||
"y": "mouseRightClick",
|
||||
|
||||
"joystickAxes":
|
||||
{
|
||||
"mouseCursorX" : "leftx",
|
||||
"mouseCursorY" : "lefty",
|
||||
"mouseSwipeX" : "rightx",
|
||||
"mouseSwipeY" : "righty"
|
||||
},
|
||||
|
||||
"joystickButtons": {
|
||||
"globalAccept" : "a",
|
||||
"globalCancel" : "b",
|
||||
"globalReturn" : [ "a", "b" ],
|
||||
|
||||
"lobbyBeginStandardGame" : "a",
|
||||
"lobbyBeginCampaign" : "a",
|
||||
"lobbyLoadGame" : "a",
|
||||
"lobbySaveGame" : "a",
|
||||
"adventureViewSelected" : "a",
|
||||
"adventureExitWorldView" : [ "a", "b" ],
|
||||
"battleTacticsEnd" : "a",
|
||||
|
||||
"mouseClickLeft": "x",
|
||||
"mouseClickRight": "y",
|
||||
|
||||
"leftshoulder": ["adventureNextHero", "battleDefend"],
|
||||
"rightshoulder": ["adventureNextTown", "battleWait"],
|
||||
"lefttrigger": ["adventureVisitObject", "battleTacticsNext", "battleUseCreatureSpell"],
|
||||
"righttrigger": ["adventureCastSpell", "battleCastSpell"],
|
||||
"back": ["gameEndTurn", "battleAutocombatEnd"],
|
||||
"start": ["globalOptions", "adventureGameOptions"],
|
||||
"dpup": ["moveUp", "adventureViewWorld", "recruitmentUpgrade", "recruitmentUpgradeAll", "battleConsoleUp", "recruitmentMax"],
|
||||
"dpdown": ["moveDown", "adventureKingdomOverview", "battleConsoleDown","recruitmentMin"],
|
||||
"dpleft": ["moveLeft", "adventureViewScenario"],
|
||||
"dpright": ["moveRight", "adventureThievesGuild"],
|
||||
"leftstick" : ["adventureToggleMapLevel", "battleToggleHeroesStats"],
|
||||
"rightstick": ["adventureToggleGrid", "battleToggleQueue"]
|
||||
|
||||
"adventureNextTown" : "rightshoulder",
|
||||
"battleWait" : "rightshoulder",
|
||||
|
||||
"adventureVisitObject" : "lefttrigger",
|
||||
"battleTacticsNext" : "lefttrigger",
|
||||
"battleUseCreatureSpell" : "lefttrigger",
|
||||
|
||||
"adventureCastSpell" : "righttrigger",
|
||||
"battleCastSpell" : "righttrigger",
|
||||
|
||||
"gameEndTurn" : "back",
|
||||
"battleAutocombatEnd" : "back",
|
||||
|
||||
"globalOptions" : "start",
|
||||
"adventureGameOptions" : "start",
|
||||
|
||||
"moveUp" : "dpup",
|
||||
"adventureViewWorld" : "dpup",
|
||||
"recruitmentUpgrade" : "dpup",
|
||||
"recruitmentUpgradeAll" : "dpup",
|
||||
"battleConsoleUp" : "dpup",
|
||||
"recruitmentMax" : "dpup",
|
||||
|
||||
"moveDown" : "dpdown",
|
||||
"adventureKingdomOverview" : "dpdown",
|
||||
"battleConsoleDown" : "dpdown",
|
||||
"recruitmentMin" : "dpdown",
|
||||
|
||||
"moveLeft" : "dpleft",
|
||||
"adventureViewScenario" : "dpleft",
|
||||
|
||||
"moveRight" : "dpright",
|
||||
"adventureThievesGuild" : "dpright",
|
||||
|
||||
"adventureToggleMapLevel" : "leftstick",
|
||||
"battleToggleHeroesStats" : "leftstick",
|
||||
|
||||
"adventureToggleGrid" : "rightstick",
|
||||
"battleToggleQueue" : "rightstick",
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user