Skip to content

Commit

Permalink
Android: Enabled use of external input devices (gamepads, keyboards, …
Browse files Browse the repository at this point in the history
…mice)

Closes #1778

- Touch controls now automatically toggle on/off depending on the last
  input method.
- Fixed conflicts between mouse movement and touch controls
- No longer overwrite user settings with default mobile settings
- Most input options are now configurable on Android
- Known issue: Game crashes when turning off Bluetooth input devices.
  Trace pointed to SDL, but maybe it can be circumvented.
  • Loading branch information
dorkster committed Oct 20, 2024
1 parent 02ff419 commit 83e6b71
Show file tree
Hide file tree
Showing 16 changed files with 52 additions and 46 deletions.
1 change: 1 addition & 0 deletions RELEASE_NOTES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Engine features:
* Added a game filter for the inactive mods list in the Configuration menu.
* Added 'inactivemods_filter' to menu/config.txt config.
* Added 'preview_enabled' and 'preview_pos' to menus/inventory.txt config.
* Android: Enabled use of external input devices (gamepads, keyboards, mice)

Engine fixes:

Expand Down
28 changes: 16 additions & 12 deletions src/Avatar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ bool Avatar::pressing_move() {
else if (stats.effects.knockback_speed != 0) {
return false;
}
else if (settings->mouse_move) {
else if (checkMouseMoveEnabled()) {
return inpt->pressing[mm_key] && !inpt->pressing[Input::SHIFT] && mm_is_distant;
}
else {
Expand All @@ -274,7 +274,7 @@ void Avatar::set_direction() {
int old_dir = stats.direction;

// handle direction changes
if (settings->mouse_move) {
if (checkMouseMoveEnabled()) {
if (mm_is_distant) {
FPoint target = Utils::screenToMap(inpt->mouse.x, inpt->mouse.y, mapr->cam.pos.x, mapr->cam.pos.y);
stats.direction = Utils::calcDirection(stats.pos.x, stats.pos.y, target.x, target.y);
Expand Down Expand Up @@ -324,7 +324,7 @@ void Avatar::set_direction() {
*/
void Avatar::logic() {
bool restrict_power_use = false;
if (settings->mouse_move) {
if (checkMouseMoveEnabled()) {
if(inpt->pressing[mm_key] && !inpt->pressing[Input::SHIFT] && !menu->act->isWithinSlots(inpt->mouse) && !menu->act->isWithinMenus(inpt->mouse)) {
restrict_power_use = true;
}
Expand Down Expand Up @@ -432,7 +432,7 @@ void Avatar::logic() {
PowerID mm_attack_id = (settings->mouse_move_swap ? menu->act->getSlotPower(MenuActionBar::SLOT_MAIN2) : menu->act->getSlotPower(MenuActionBar::SLOT_MAIN1));
bool mm_can_use_power = true;

if (settings->mouse_move) {
if (checkMouseMoveEnabled()) {
if (!inpt->pressing[mm_key]) {
lock_enemy = NULL;
}
Expand Down Expand Up @@ -540,7 +540,7 @@ void Avatar::logic() {
setAnimation("stance");

// allowed to move or use powers?
if (settings->mouse_move) {
if (checkMouseMoveEnabled()) {
allowed_to_move = restrict_power_use && (!inpt->lock[mm_key] || drag_walking) && !lock_enemy;
allowed_to_turn = allowed_to_move;

Expand All @@ -563,7 +563,7 @@ void Avatar::logic() {

if (pressing_move() && allowed_to_move) {
if (move()) { // no collision
if (settings->mouse_move && inpt->pressing[mm_key]) {
if (checkMouseMoveEnabled() && inpt->pressing[mm_key]) {
inpt->lock[mm_key] = true;
drag_walking = true;
}
Expand All @@ -572,7 +572,7 @@ void Avatar::logic() {
}
}

if (settings->mouse_move && settings->mouse_move_attack && cursor_enemy && !cursor_enemy->stats.hero_ally && mm_can_use_power && powers->checkCombatRange(mm_attack_id, &stats, cursor_enemy->stats.pos)) {
if (checkMouseMoveEnabled() && settings->mouse_move_attack && cursor_enemy && !cursor_enemy->stats.hero_ally && mm_can_use_power && powers->checkCombatRange(mm_attack_id, &stats, cursor_enemy->stats.pos)) {
stats.cur_state = StatBlock::ENTITY_STANCE;
lock_enemy = cursor_enemy;
}
Expand Down Expand Up @@ -602,7 +602,7 @@ void Avatar::logic() {
stats.cur_state = StatBlock::ENTITY_STANCE;
break;
}
else if ((settings->mouse_move || !settings->mouse_aim) && inpt->pressing[Input::SHIFT]) {
else if ((checkMouseMoveEnabled() || !settings->mouse_aim) && inpt->pressing[Input::SHIFT]) {
// Shift should stop movement in some cases.
// With mouse_move, it allows the player to stop moving and begin attacking.
// With mouse_aim disabled, it allows the player to aim their attacks without having to move.
Expand All @@ -613,7 +613,7 @@ void Avatar::logic() {
if (activeAnimation->getName() != "run")
stats.cur_state = StatBlock::ENTITY_STANCE;

if (settings->mouse_move && settings->mouse_move_attack && cursor_enemy && !cursor_enemy->stats.hero_ally && mm_can_use_power && powers->checkCombatRange(mm_attack_id, &stats, cursor_enemy->stats.pos)) {
if (checkMouseMoveEnabled() && settings->mouse_move_attack && cursor_enemy && !cursor_enemy->stats.hero_ally && mm_can_use_power && powers->checkCombatRange(mm_attack_id, &stats, cursor_enemy->stats.pos)) {
stats.cur_state = StatBlock::ENTITY_STANCE;
lock_enemy = cursor_enemy;
}
Expand Down Expand Up @@ -669,12 +669,12 @@ void Avatar::logic() {
stats.cur_state = StatBlock::ENTITY_STANCE;
stats.cooldown.reset(Timer::BEGIN);
stats.prevent_interrupt = false;
if (settings->mouse_move) {
if (checkMouseMoveEnabled()) {
drag_walking = true;
}
}

if (settings->mouse_move && lock_enemy && !powers->checkCombatRange(mm_attack_id, &stats, lock_enemy->stats.pos)) {
if (checkMouseMoveEnabled() && lock_enemy && !powers->checkCombatRange(mm_attack_id, &stats, lock_enemy->stats.pos)) {
lock_enemy = NULL;
}

Expand All @@ -701,7 +701,7 @@ void Avatar::logic() {

if (activeAnimation->getTimesPlayed() >= 1 || activeAnimation->getName() != "hit") {
stats.cur_state = StatBlock::ENTITY_STANCE;
if (settings->mouse_move) {
if (checkMouseMoveEnabled()) {
drag_walking = true;
}
}
Expand Down Expand Up @@ -1061,6 +1061,10 @@ std::string Avatar::getGfxFromType(const std::string& gfx_type) {
return gfx;
}

bool Avatar::checkMouseMoveEnabled() {
return settings->mouse_move && !inpt->usingTouchscreen();
}

Avatar::~Avatar() {
delete charmed_stats;
delete hero_stats;
Expand Down
1 change: 1 addition & 0 deletions src/Avatar.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ class Avatar : public Entity {
void transform();
void untransform();
void beginPower(PowerID power_id, FPoint* target);
bool checkMouseMoveEnabled();


std::vector<Step_sfx> step_def;
Expand Down
1 change: 1 addition & 0 deletions src/InputState.h
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ class InputState {
virtual std::string getAttackString() = 0;
virtual int getNumJoysticks() = 0;
virtual bool usingMouse() = 0;
virtual bool usingTouchscreen() = 0;
virtual void startTextInput() = 0;
virtual void stopTextInput() = 0;

Expand Down
2 changes: 1 addition & 1 deletion src/MapRenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1323,7 +1323,7 @@ void MapRenderer::checkNearestEvent() {
}

if (nearest != events.end()) {
if (!inpt->usingMouse() || settings->touchscreen) {
if (!inpt->usingMouse() || inpt->usingTouchscreen()) {
// new tooltip?
createTooltip(nearest->getComponent(EventComponent::TOOLTIP));
tip_pos = Utils::mapToScreen(nearest->center.x, nearest->center.y, cam.shake.x, cam.shake.y);
Expand Down
6 changes: 3 additions & 3 deletions src/MenuActionBar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -511,8 +511,8 @@ void MenuActionBar::remove(const Point& mouse) {
* add that power to the action queue
*/
void MenuActionBar::checkAction(std::vector<ActionData> &action_queue) {
bool enable_mm_attack = (!settings->mouse_move || inpt->pressing[Input::SHIFT] || pc->lock_enemy);
bool enable_main1 = (!settings->touchscreen || (!menu->menus_open && menu->touch_controls->checkAllowMain1())) && (settings->mouse_move_swap || enable_mm_attack);
bool enable_mm_attack = (!settings->mouse_move || inpt->pressing[Input::SHIFT] || pc->lock_enemy || inpt->usingTouchscreen());
bool enable_main1 = (!inpt->usingTouchscreen() || (!menu->menus_open && menu->touch_controls->checkAllowMain1())) && (settings->mouse_move_swap || enable_mm_attack);
bool enable_main2 = !settings->mouse_move_swap || enable_mm_attack;

// check click and hotkey actions
Expand Down Expand Up @@ -714,7 +714,7 @@ void MenuActionBar::set(std::vector<PowerID> power_id, bool skip_empty) {
* Set a target depending on how a power was triggered
*/
FPoint MenuActionBar::setTarget(bool have_aim, const Power* pow) {
if (have_aim && settings->mouse_aim && !settings->touchscreen) {
if (have_aim && settings->mouse_aim && !inpt->usingTouchscreen()) {
FPoint map_pos;
if (pow->aim_assist)
map_pos = Utils::screenToMap(inpt->mouse.x, inpt->mouse.y + eset->misc.aim_assist, mapr->cam.pos.x, mapr->cam.pos.y);
Expand Down
4 changes: 2 additions & 2 deletions src/MenuInventory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -514,7 +514,7 @@ ItemStack MenuInventory::click(const Point& position) {
if (drag_prev_src > -1) {
item = inventory[drag_prev_src].click(position);

if (settings->touchscreen) {
if (inpt->usingTouchscreen()) {
tablist.setCurrent(inventory[drag_prev_src].current_slot);
tap_to_activate_timer.reset(Timer::BEGIN);
}
Expand Down Expand Up @@ -656,7 +656,7 @@ bool MenuInventory::drop(const Point& position, ItemStack stack) {
// NOTE: the quantity must be 1, since the number picker appears when tapping on a stack of more than 1 item
// NOTE: we only support activating books since equipment activation doesn't work for some reason
// NOTE: Consumables are usually in stacks > 1, so we ignore those as well for consistency
if (settings->touchscreen && !tap_to_activate_timer.isEnd() && stack.quantity == 1 && items->isValid(stack.item) && !items->items[stack.item]->book.empty()) {
if (inpt->usingTouchscreen() && !tap_to_activate_timer.isEnd() && stack.quantity == 1 && items->isValid(stack.item) && !items->items[stack.item]->book.empty()) {
activate(position);
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/MenuManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -829,7 +829,7 @@ void MenuManager::logic() {
menus_open = (inv->visible || pow->visible || chr->visible || questlog->visible || vendor->visible || talker->visible || book->visible || console_open);
pause = (eset->misc.menus_pause && menus_open) || exit->visible || console_open || book->visible;

touch_controls->visible = !menus_open && !exit->visible;
touch_controls->visible = !menus_open && !exit->visible && inpt->usingTouchscreen();

if (pc->stats.alive) {

Expand Down Expand Up @@ -1493,7 +1493,7 @@ void MenuManager::render() {
touch_controls->render();

if (!num_picker->visible && !action_picker->visible && !mouse_dragging && !sticky_dragging) {
if (!inpt->usingMouse() || settings->touchscreen)
if (!inpt->usingMouse() || inpt->usingTouchscreen())
handleKeyboardTooltips();
else {
// Find tooltips depending on mouse position
Expand All @@ -1520,7 +1520,7 @@ void MenuManager::render() {
else if (drag_src == DRAG_SRC_POWERS || drag_src == DRAG_SRC_ACTIONBAR)
setDragIcon(powers->powers[drag_power]->icon, -1);

if (settings->touchscreen && sticky_dragging)
if (inpt->usingTouchscreen() && sticky_dragging)
renderIcon(keydrag_pos.x - eset->resolutions.icon_size/2, keydrag_pos.y - eset->resolutions.icon_size/2);
else
renderIcon(inpt->mouse.x - eset->resolutions.icon_size/2, inpt->mouse.y - eset->resolutions.icon_size/2);
Expand Down
8 changes: 4 additions & 4 deletions src/MenuStash.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ void MenuStash::logic() {
if (!dragging)
tab_control->logic();

if (settings->touchscreen && activetab != static_cast<size_t>(tab_control->getActiveTab())) {
if (inpt->usingTouchscreen() && activetab != static_cast<size_t>(tab_control->getActiveTab())) {
for (size_t i = 0; i < tabs.size(); ++i) {
tabs[i].tablist.defocus();
}
Expand All @@ -249,7 +249,7 @@ void MenuStash::logic() {

tablist.setNextTabList(&(tabs[activetab].tablist));

if (settings->touchscreen) {
if (inpt->usingTouchscreen()) {
if (tabs[activetab].tablist.getCurrent() == -1)
tabs[activetab].stock.current_slot = NULL;
}
Expand Down Expand Up @@ -377,7 +377,7 @@ bool MenuStash::add(ItemStack stack, int slot, bool play_sound) {
*/
ItemStack MenuStash::click(const Point& position) {
ItemStack stack = tabs[activetab].stock.click(position);
if (settings->touchscreen) {
if (inpt->usingTouchscreen()) {
tabs[activetab].tablist.setCurrent(tabs[activetab].stock.current_slot);
}
return stack;
Expand Down Expand Up @@ -453,7 +453,7 @@ void MenuStash::enableSharedTab(bool permadeath) {
}

void MenuStash::setTab(size_t tab) {
if (settings->touchscreen && activetab != tab) {
if (inpt->usingTouchscreen() && activetab != tab) {
for (size_t i = 0; i < tabs.size(); ++i) {
tabs[i].tablist.defocus();
}
Expand Down
8 changes: 4 additions & 4 deletions src/MenuVendor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ void MenuVendor::logic() {
if (stock[ItemManager::VENDOR_BUY].drag_prev_slot == -1 && stock[ItemManager::VENDOR_SELL].drag_prev_slot == -1)
tabControl->logic();

if (settings->touchscreen && activetab != tabControl->getActiveTab()) {
if (inpt->usingTouchscreen() && activetab != tabControl->getActiveTab()) {
tablist_buy.defocus();
tablist_sell.defocus();
}
Expand All @@ -166,7 +166,7 @@ void MenuVendor::logic() {
tablist.setNextTabList(&tablist_sell);
}

if (settings->touchscreen) {
if (inpt->usingTouchscreen()) {
if (activetab == ItemManager::VENDOR_BUY && tablist_buy.getCurrent() == -1)
stock[ItemManager::VENDOR_BUY].current_slot = NULL;
else if (activetab == ItemManager::VENDOR_SELL && tablist_sell.getCurrent() == -1)
Expand All @@ -180,7 +180,7 @@ void MenuVendor::logic() {
}

void MenuVendor::setTab(int tab) {
if (settings->touchscreen && activetab != tab) {
if (inpt->usingTouchscreen() && activetab != tab) {
tablist_buy.defocus();
tablist_sell.defocus();
}
Expand Down Expand Up @@ -214,7 +214,7 @@ void MenuVendor::render() {
ItemStack MenuVendor::click(const Point& position) {
ItemStack stack = stock[activetab].click(position);
saveInventory();
if (settings->touchscreen) {
if (inpt->usingTouchscreen()) {
if (activetab == ItemManager::VENDOR_BUY)
tablist_buy.setCurrent(stock[activetab].current_slot);
else if (activetab == ItemManager::VENDOR_SELL)
Expand Down
8 changes: 1 addition & 7 deletions src/PlatformAndroid.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,16 +122,10 @@ Platform::Platform()

config_interface[Platform::Interface::HARDWARE_CURSOR] = false;

config_input[Platform::Input::JOYSTICK] = false;
config_input[Platform::Input::MOUSE_MOVE] = false;
config_input[Platform::Input::MOUSE_AIM] = false;
config_input[Platform::Input::NO_MOUSE] = false;
config_input[Platform::Input::MOUSE_MOVE_SWAP] = false;
config_input[Platform::Input::MOUSE_MOVE_ATTACK] = false;
config_input[Platform::Input::JOYSTICK_DEADZONE] = false;
config_input[Platform::Input::TOUCH_CONTROLS] = false;

config_misc[Platform::Misc::KEYBINDS] = false;
config_misc[Platform::Misc::KEYBINDS] = true;
}

Platform::~Platform() {
Expand Down
17 changes: 12 additions & 5 deletions src/SDLInputState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -632,6 +632,9 @@ void SDLInputState::handle() {
}
}
}

if (!usingTouchscreen())
touch_locked = false;
}

void SDLInputState::hideCursor() {
Expand Down Expand Up @@ -796,15 +799,15 @@ std::string SDLInputState::getGamepadBindingString(int key, bool get_short_strin
std::string SDLInputState::getMovementString() {
std::string output = "[";

if (settings->enable_joystick) {
if (inpt->usingTouchscreen()) {
output += msg->get("Touch control D-Pad");
}
else if (settings->enable_joystick) {
output += getGamepadBindingString(Input::LEFT) + "/";
output += getGamepadBindingString(Input::RIGHT) + "/";
output += getGamepadBindingString(Input::UP) + "/";
output += getGamepadBindingString(Input::DOWN);
}
else if (settings->touchscreen) {
output += msg->get("Touch control D-Pad");
}
else if (settings->mouse_move) {
output += (settings->mouse_move_swap ? getBindingString(Input::MAIN2) : getBindingString(Input::MAIN1));
}
Expand All @@ -822,7 +825,7 @@ std::string SDLInputState::getMovementString() {
std::string SDLInputState::getAttackString() {
std::string output = "[";

if (settings->touchscreen) {
if (inpt->usingTouchscreen()) {
output += msg->get("Touch control buttons");
}
else {
Expand All @@ -841,6 +844,10 @@ bool SDLInputState::usingMouse() {
return !settings->no_mouse && mode != MODE_JOYSTICK;
}

bool SDLInputState::usingTouchscreen() {
return settings->touchscreen && mode == MODE_TOUCHSCREEN;
}

void SDLInputState::startTextInput() {
if (!text_input) {
SDL_StartTextInput();
Expand Down
1 change: 1 addition & 0 deletions src/SDLInputState.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ class SDLInputState : public InputState {
std::string getAttackString();
int getNumJoysticks();
bool usingMouse();
bool usingTouchscreen();
void startTextInput();
void stopTextInput();
void setCommonStrings();
Expand Down
3 changes: 0 additions & 3 deletions src/Settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -175,8 +175,6 @@ void Settings::loadSettings() {
}
}

loadMobileDefaults();

// Force using the software renderer if safe mode is enabled
if (safe_video) {
render_device_name = "sdl";
Expand Down Expand Up @@ -233,7 +231,6 @@ void Settings::loadDefaults() {
void Settings::loadMobileDefaults() {
if (platform.is_mobile_device) {
mouse_move = false;
mouse_aim = false;
no_mouse = false;
enable_joystick = false;
hardware_cursor = true;
Expand Down
2 changes: 1 addition & 1 deletion src/Version.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ FLARE. If not, see http://www.gnu.org/licenses/

#include <SDL.h>

Version VersionInfo::ENGINE(1, 14, 67);
Version VersionInfo::ENGINE(1, 14, 68);
Version VersionInfo::MIN(0, 0, 0);
Version VersionInfo::MAX(USHRT_MAX, USHRT_MAX, USHRT_MAX);

Expand Down
2 changes: 1 addition & 1 deletion src/Widget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -471,7 +471,7 @@ void TabList::logic() {

// Also defocus if we start using the mouse
// we need to disable this for touchscreen devices so that item tooltips will work
if (!settings->touchscreen && current != -1 && inpt->usingMouse()) {
if (!inpt->usingTouchscreen() && current != -1 && inpt->usingMouse()) {
defocus();
}
}
Expand Down

0 comments on commit 83e6b71

Please sign in to comment.