Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion data/gui/dialogs/android/multitouch_settings.stkgui
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,23 @@
<div x="2%" y="2%" width="96%" height="96%" layout="vertical-row" >
<header id="title" width="100%" height="fit" text_align="center" word_wrap="true" text="Touch Device Settings" />

<spacer height="35" width="10" />
<spacer height="20" width="10" />

<div width="90%" layout="horizontal-row" proportion="1">
<label proportion="1" align="center" text_align="right" I18N="In the multitouch settings screen" text="Touch controls"/>
<div proportion="1" align="center" height="fit" layout="horizontal-row" >
<spacer width="40" height="10" />
<spinner id="multitouch_active" proportion="1" min_value="0" max_value="2" wrap_around="false"/>
</div>
</div>

<div width="90%" layout="horizontal-row" proportion="1">
<label proportion="1" align="center" text_align="right" I18N="In the multitouch settings screen" text="Auto-detect touch-only devices"/>
<div proportion="1" align="center" height="fit" layout="horizontal-row" >
<spacer width="40" height="10" />
<checkbox id="touch_only"/>
</div>
</div>

<div width="75%" layout="horizontal-row" proportion="1">
<label proportion="1" align="center" text_align="right" I18N="In the multitouch settings screen" text="Device enabled"/>
Expand Down
16 changes: 15 additions & 1 deletion lib/irrlicht/source/Irrlicht/CIrrDeviceSDL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "ge_vulkan_driver.hpp"
#include "ge_vulkan_scene_manager.hpp"
#include "MoltenVK.h"
#include "input/linux_touch_detect.hpp"

#include <SDL_vulkan.h>

Expand Down Expand Up @@ -1550,7 +1551,20 @@ void CIrrDeviceSDL::createKeyMap()

bool CIrrDeviceSDL::supportsTouchDevice() const
{
return SDL_GetNumTouchDevices() > 0;
if (SDL_GetNumTouchDevices() > 0)
return true;
return LinuxTouchDetect::hasTouchscreen();
}

bool CIrrDeviceSDL::hasHardwareKeyboard() const
{
#if defined(ANDROID) || defined(IOS_STK)
return false;
#elif defined(__linux__)
return LinuxTouchDetect::hasHardwareKeyboard();
#else
return true;
#endif
}


Expand Down
2 changes: 2 additions & 0 deletions lib/irrlicht/source/Irrlicht/CIrrDeviceSDL.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ class MoltenVK;

virtual bool supportsTouchDevice() const;

virtual bool hasHardwareKeyboard() const;

//! Get the device type
virtual E_DEVICE_TYPE getType() const
{
Expand Down
5 changes: 5 additions & 0 deletions src/config/user_config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,11 @@ namespace UserConfigParams
&m_multitouch_group,
"Enable multitouch support: 0 = disabled, 1 = if available, 2 = enabled") );

PARAM_PREFIX BoolUserConfigParam m_multitouch_touch_only
PARAM_DEFAULT( BoolUserConfigParam(false, "multitouch_touch_only",
&m_multitouch_group,
"When multitouch_active is 1 (auto), enable only on touch-only devices (touchscreen and no physical keyboard)"));

PARAM_PREFIX BoolUserConfigParam m_multitouch_draw_gui
PARAM_DEFAULT( BoolUserConfigParam(false, "multitouch_draw_gui",
&m_multitouch_group,
Expand Down
28 changes: 28 additions & 0 deletions src/graphics/irr_driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "challenges/story_mode_timer.hpp"
#include "config/player_manager.hpp"
#include "config/user_config.hpp"
#include "input/linux_touch_detect.hpp"
#include "font/bold_face.hpp"
#include "font/digit_face.hpp"
#include "font/font_manager.hpp"
Expand Down Expand Up @@ -403,6 +404,33 @@ void IrrDriver::createListOfVideoModes()
} // for i < video modes count
} // createListOfVideoModes

bool IrrDriver::isTouchOnlyDevice() const
{
#if defined(ANDROID) || defined(IOS_STK)
return true;
#elif defined(__linux__)
if (m_device && m_device->supportsTouchDevice() &&
!m_device->hasHardwareKeyboard())
return true;
return LinuxTouchDetect::isTouchOnly();
#else
return false;
#endif
}

bool IrrDriver::isMultitouchEnabled() const
{
if (UserConfigParams::m_multitouch_active == 0)
return false;
if (UserConfigParams::m_multitouch_active > 1)
return true;
if (!m_device || !m_device->supportsTouchDevice())
return false;
if (UserConfigParams::m_multitouch_touch_only && !isTouchOnlyDevice())
return false;
return true;
}

// --------------------------------------------------------------------------------------------
/** This creates the actualy OpenGL device. This is called
*/
Expand Down
2 changes: 2 additions & 0 deletions src/graphics/irr_driver.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,8 @@ class IrrDriver : public IEventReceiver, public NoCopy
// ------------------------------------------------------------------------
/** Returns the irrlicht device. */
IrrlichtDevice *getDevice() const { return m_device; }
bool isMultitouchEnabled() const;
bool isTouchOnlyDevice() const;
// ------------------------------------------------------------------------
/** Returns the irrlicht video driver. */
video::IVideoDriver *getVideoDriver() const { return m_video_driver; }
Expand Down
4 changes: 1 addition & 3 deletions src/guiengine/widgets/dynamic_ribbon_widget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -713,9 +713,7 @@ EventPropagation DynamicRibbonWidget::mouseHovered(Widget* child, const int play

updateLabel();

bool multitouch_enabled = (UserConfigParams::m_multitouch_active == 1 &&
irr_driver->getDevice()->supportsTouchDevice()) ||
UserConfigParams::m_multitouch_active > 1;
bool multitouch_enabled = irr_driver->isMultitouchEnabled();
// For now disable it to fix the weird "triangle selection" for touch
// screen
if (!multitouch_enabled)
Expand Down
13 changes: 10 additions & 3 deletions src/input/device_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,7 @@ bool DeviceManager::initialize()
m_keyboards.push_back(new KeyboardDevice(m_keyboard_configs.get(n)));
}

if ((UserConfigParams::m_multitouch_active == 1 &&
irr_driver->getDevice()->supportsTouchDevice()) ||
UserConfigParams::m_multitouch_active > 1)
if (irr_driver->isMultitouchEnabled())
{
m_multitouch_device = new MultitouchDevice();
}
Expand Down Expand Up @@ -121,6 +119,15 @@ void DeviceManager::clearMultitouchDevices()
m_multitouch_device = NULL;
} // clearMultitouchDevices

void DeviceManager::updateMultitouchAvailability()
{
const bool want = irr_driver->isMultitouchEnabled();
if (want && m_multitouch_device == NULL)
m_multitouch_device = new MultitouchDevice();
else if (!want && m_multitouch_device != NULL)
clearMultitouchDevices();
} // updateMultitouchAvailability

// -----------------------------------------------------------------------------
void DeviceManager::setAssignMode(const PlayerAssignMode assignMode)
{
Expand Down
1 change: 1 addition & 0 deletions src/input/device_manager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ class DeviceManager: public NoCopy
MultitouchDevice* getMultitouchDevice() { return m_multitouch_device; }
void clearMultitouchDevices();
void updateMultitouchDevice();
void updateMultitouchAvailability();


/**
Expand Down
217 changes: 217 additions & 0 deletions src/input/linux_touch_detect.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
#ifndef HEADER_LINUX_TOUCH_DETECT_HPP
#define HEADER_LINUX_TOUCH_DETECT_HPP

#include <cctype>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>

#ifndef _WIN32
#include <unistd.h>
#endif

/** Linux /proc and DMI helpers for touchscreen vs keyboard.
* Used by Irrlicht SDL (supportsTouchDevice) and STK (touch-only policy). */
namespace LinuxTouchDetect
{
const int KEY_A = 30;
const int ABS_MT_POSITION_X = 53;
const int INPUT_PROP_DIRECT = 1;

inline bool containsI(const char* hay, const char* needle)
{
if (!hay || !needle || !needle[0])
return false;
const size_t nlen = std::strlen(needle);
const size_t hlen = std::strlen(hay);
if (nlen > hlen)
return false;
for (size_t i = 0; i + nlen <= hlen; i++)
{
size_t j = 0;
for (; j < nlen; j++)
{
if (std::tolower((unsigned char)hay[i + j]) !=
std::tolower((unsigned char)needle[j]))
break;
}
if (j == nlen)
return true;
}
return false;
}

inline bool ignoredKeyboardName(const char* name)
{
if (!name || !name[0])
return true;
return containsI(name, "power button") ||
containsI(name, "sleep button") ||
containsI(name, "lid switch") ||
containsI(name, "video bus") ||
containsI(name, "gpio-keys") ||
containsI(name, "headset") ||
containsI(name, "hdmi") ||
containsI(name, "sof-hda") ||
containsI(name, "consumer control");
}

inline bool bitmapHasBit(const char* hex, unsigned bit)
{
unsigned long words[32];
int n = 0;
int word_bits = 32;
const char* p = hex;
std::memset(words, 0, sizeof(words));
while (p && *p && n < 32)
{
while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r')
p++;
if (!*p)
break;
const char* start = p;
char* end = NULL;
words[n] = std::strtoul(p, &end, 16);
if (end == p)
break;
if ((int)(end - start) > 8)
word_bits = 64;
n++;
p = end;
}
if (n == 0)
return false;
const unsigned word_from_low = bit / (unsigned)word_bits;
const unsigned bit_in_word = bit % (unsigned)word_bits;
const int idx = n - 1 - (int)word_from_low;
if (idx < 0 || idx >= n)
return false;
return (words[idx] & (1UL << bit_in_word)) != 0;
}

inline void scanProcBusInput(bool* has_touch, bool* has_keyboard)
{
FILE* f = std::fopen("/proc/bus/input/devices", "r");
if (!f)
return;
char line[512];
char name[256];
unsigned prop = 0;
bool key_a = false;
bool abs_mt = false;
name[0] = 0;
while (std::fgets(line, sizeof(line), f))
{
if (std::strncmp(line, "N: Name=\"", 9) == 0)
{
name[0] = 0;
std::sscanf(line, "N: Name=\"%255[^\"]\"", name);
}
else if (std::strncmp(line, "B: PROP=", 8) == 0)
prop = (unsigned)std::strtoul(line + 8, NULL, 16);
else if (std::strncmp(line, "B: KEY=", 7) == 0)
key_a = bitmapHasBit(line + 7, KEY_A);
else if (std::strncmp(line, "B: ABS=", 7) == 0)
abs_mt = bitmapHasBit(line + 7, ABS_MT_POSITION_X);
else if (line[0] == '\n' || line[0] == '\r' || line[0] == 0)
{
if ((prop & (1u << INPUT_PROP_DIRECT)) ||
containsI(name, "touchscreen"))
*has_touch = true;
else if (abs_mt && !(prop & 1u) && containsI(name, "touch"))
*has_touch = true;
if (key_a && !ignoredKeyboardName(name))
*has_keyboard = true;
name[0] = 0;
prop = 0;
key_a = false;
abs_mt = false;
}
}
std::fclose(f);
}

inline int chassisType()
{
FILE* f = std::fopen("/sys/class/dmi/id/chassis_type", "r");
if (!f)
return -1;
int type = -1;
if (std::fscanf(f, "%d", &type) != 1)
type = -1;
std::fclose(f);
return type;
}

inline bool osReleaseHas(const char* needle)
{
FILE* f = std::fopen("/etc/os-release", "r");
if (!f)
return false;
char line[512];
while (std::fgets(line, sizeof(line), f))
{
if (containsI(line, needle))
{
std::fclose(f);
return true;
}
}
std::fclose(f);
return false;
}

inline bool isUbuntuTouch()
{
if (osReleaseHas("Ubuntu Touch") || osReleaseHas("UBUNTU_TOUCH") ||
osReleaseHas("VARIANT_ID=touch") || osReleaseHas("lomiri"))
return true;
#ifndef _WIN32
if (access("/usr/share/ubports", F_OK) == 0)
return true;
#endif
const char* desktop = std::getenv("XDG_CURRENT_DESKTOP");
if (desktop && (containsI(desktop, "Lomiri") || containsI(desktop, "Unity8")))
return true;
const char* click = std::getenv("CLICK_FRAMEWORK");
return click && click[0];
}

inline bool hasTouchscreen()
{
bool touch = false;
bool keyboard = false;
scanProcBusInput(&touch, &keyboard);
if (isUbuntuTouch())
touch = true;
return touch;
}

inline bool hasHardwareKeyboard()
{
bool touch = false;
bool keyboard = false;
scanProcBusInput(&touch, &keyboard);
if (isUbuntuTouch())
return false;
const int chassis = chassisType();
if (chassis == 11 || chassis == 30)
return false;
return keyboard;
}

inline bool isTouchOnly()
{
if (isUbuntuTouch())
return true;
const int chassis = chassisType();
bool touch = hasTouchscreen();
bool keyboard = hasHardwareKeyboard();
if ((chassis == 11 || chassis == 30) && touch)
return true;
return touch && !keyboard;
}
}

#endif
2 changes: 1 addition & 1 deletion src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2476,7 +2476,7 @@ int main(int argc, char *argv[])
// doesn't have
android_tv = SDL_IsAndroidTV();
#endif
if (!android_tv && irr_driver->getDevice()->supportsTouchDevice())
if (!android_tv && irr_driver->isMultitouchEnabled())
{
InitAndroidDialog* init_android = new InitAndroidDialog(
0.8f, 0.8f);
Expand Down
Loading