mirror of
https://github.com/minetest/minetest.git
synced 2024-11-05 07:13:46 +01:00
Touchscreen: Recognize double-taps as double-clicks (#14187)
This commit is contained in:
parent
e17455cb22
commit
05a53cd330
@ -51,11 +51,8 @@ GUIModalMenu::GUIModalMenu(gui::IGUIEnvironment* env, gui::IGUIElement* parent,
|
|||||||
setVisible(true);
|
setVisible(true);
|
||||||
m_menumgr->createdMenu(this);
|
m_menumgr->createdMenu(this);
|
||||||
|
|
||||||
m_doubleclickdetect[0].time = 0;
|
m_last_touch.time = 0;
|
||||||
m_doubleclickdetect[1].time = 0;
|
m_last_touch.pos = v2s32(0, 0);
|
||||||
|
|
||||||
m_doubleclickdetect[0].pos = v2s32(0, 0);
|
|
||||||
m_doubleclickdetect[1].pos = v2s32(0, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GUIModalMenu::~GUIModalMenu()
|
GUIModalMenu::~GUIModalMenu()
|
||||||
@ -109,7 +106,18 @@ void GUIModalMenu::quitMenu()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GUIModalMenu::DoubleClickDetection(const SEvent &event)
|
static bool isChild(gui::IGUIElement *tocheck, gui::IGUIElement *parent)
|
||||||
|
{
|
||||||
|
while (tocheck) {
|
||||||
|
if (tocheck == parent) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
tocheck = tocheck->getParent();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GUIModalMenu::remapDoubleClick(const SEvent &event)
|
||||||
{
|
{
|
||||||
/* The following code is for capturing double-clicks of the mouse button
|
/* The following code is for capturing double-clicks of the mouse button
|
||||||
* and translating the double-click into an EET_KEY_INPUT_EVENT event
|
* and translating the double-click into an EET_KEY_INPUT_EVENT event
|
||||||
@ -124,27 +132,18 @@ bool GUIModalMenu::DoubleClickDetection(const SEvent &event)
|
|||||||
if (!m_remap_dbl_click)
|
if (!m_remap_dbl_click)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN) {
|
if (event.EventType != EET_MOUSE_INPUT_EVENT ||
|
||||||
m_doubleclickdetect[0].pos = m_doubleclickdetect[1].pos;
|
event.MouseInput.Event != EMIE_LMOUSE_DOUBLE_CLICK)
|
||||||
m_doubleclickdetect[0].time = m_doubleclickdetect[1].time;
|
|
||||||
|
|
||||||
m_doubleclickdetect[1].pos = m_pointer;
|
|
||||||
m_doubleclickdetect[1].time = porting::getTimeMs();
|
|
||||||
} else if (event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP) {
|
|
||||||
u64 delta = porting::getDeltaMs(
|
|
||||||
m_doubleclickdetect[0].time, porting::getTimeMs());
|
|
||||||
if (delta > 400)
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
double squaredistance = m_doubleclickdetect[0].pos.
|
// Only exit if the double-click happened outside the menu.
|
||||||
getDistanceFromSQ(m_doubleclickdetect[1].pos);
|
gui::IGUIElement *hovered =
|
||||||
|
Environment->getRootGUIElement()->getElementFromPoint(m_pointer);
|
||||||
if (squaredistance > (30 * 30)) {
|
if (isChild(hovered, this))
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
|
// Translate double-click to escape.
|
||||||
SEvent translated{};
|
SEvent translated{};
|
||||||
// translate doubleclick to escape
|
|
||||||
translated.EventType = EET_KEY_INPUT_EVENT;
|
translated.EventType = EET_KEY_INPUT_EVENT;
|
||||||
translated.KeyInput.Key = KEY_ESCAPE;
|
translated.KeyInput.Key = KEY_ESCAPE;
|
||||||
translated.KeyInput.Control = false;
|
translated.KeyInput.Control = false;
|
||||||
@ -156,23 +155,14 @@ bool GUIModalMenu::DoubleClickDetection(const SEvent &event)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
bool GUIModalMenu::simulateMouseEvent(ETOUCH_INPUT_EVENT touch_event, bool second_try)
|
||||||
}
|
|
||||||
|
|
||||||
static bool isChild(gui::IGUIElement *tocheck, gui::IGUIElement *parent)
|
|
||||||
{
|
{
|
||||||
while (tocheck) {
|
IGUIElement *target;
|
||||||
if (tocheck == parent) {
|
if (!second_try)
|
||||||
return true;
|
target = Environment->getFocus();
|
||||||
}
|
else
|
||||||
tocheck = tocheck->getParent();
|
target = m_touch_hovered.get();
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GUIModalMenu::simulateMouseEvent(
|
|
||||||
gui::IGUIElement *target, ETOUCH_INPUT_EVENT touch_event)
|
|
||||||
{
|
|
||||||
SEvent mouse_event{}; // value-initialized, not unitialized
|
SEvent mouse_event{}; // value-initialized, not unitialized
|
||||||
mouse_event.EventType = EET_MOUSE_INPUT_EVENT;
|
mouse_event.EventType = EET_MOUSE_INPUT_EVENT;
|
||||||
mouse_event.MouseInput.X = m_pointer.X;
|
mouse_event.MouseInput.X = m_pointer.X;
|
||||||
@ -190,6 +180,11 @@ bool GUIModalMenu::simulateMouseEvent(
|
|||||||
mouse_event.MouseInput.Event = EMIE_LMOUSE_LEFT_UP;
|
mouse_event.MouseInput.Event = EMIE_LMOUSE_LEFT_UP;
|
||||||
mouse_event.MouseInput.ButtonStates = 0;
|
mouse_event.MouseInput.ButtonStates = 0;
|
||||||
break;
|
break;
|
||||||
|
case ETIE_COUNT:
|
||||||
|
// ETIE_COUNT is used for double-tap events.
|
||||||
|
mouse_event.MouseInput.Event = EMIE_LMOUSE_DOUBLE_CLICK;
|
||||||
|
mouse_event.MouseInput.ButtonStates = EMBSM_LEFT;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -209,6 +204,9 @@ bool GUIModalMenu::simulateMouseEvent(
|
|||||||
} while (false);
|
} while (false);
|
||||||
m_simulated_mouse = false;
|
m_simulated_mouse = false;
|
||||||
|
|
||||||
|
if (!retval && !second_try)
|
||||||
|
return simulateMouseEvent(touch_event, true);
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -293,12 +291,28 @@ bool GUIModalMenu::preprocessEvent(const SEvent &event)
|
|||||||
leave();
|
leave();
|
||||||
enter(hovered);
|
enter(hovered);
|
||||||
}
|
}
|
||||||
gui::IGUIElement *focused = Environment->getFocus();
|
bool ret = simulateMouseEvent(event.TouchInput.Event);
|
||||||
bool ret = simulateMouseEvent(focused, event.TouchInput.Event);
|
|
||||||
if (!ret && m_touch_hovered != focused)
|
|
||||||
ret = simulateMouseEvent(m_touch_hovered.get(), event.TouchInput.Event);
|
|
||||||
if (event.TouchInput.Event == ETIE_LEFT_UP)
|
if (event.TouchInput.Event == ETIE_LEFT_UP)
|
||||||
leave();
|
leave();
|
||||||
|
|
||||||
|
// Detect double-taps and convert them into double-click events.
|
||||||
|
if (event.TouchInput.Event == ETIE_PRESSED_DOWN) {
|
||||||
|
u64 time_now = porting::getTimeMs();
|
||||||
|
u64 time_delta = porting::getDeltaMs(m_last_touch.time, time_now);
|
||||||
|
|
||||||
|
v2s32 pos_delta = m_pointer - m_last_touch.pos;
|
||||||
|
f32 distance_sq = (f32)pos_delta.X * pos_delta.X +
|
||||||
|
(f32)pos_delta.Y * pos_delta.Y;
|
||||||
|
|
||||||
|
if (time_delta < 400 && distance_sq < (30 * 30)) {
|
||||||
|
// ETIE_COUNT is used for double-tap events.
|
||||||
|
simulateMouseEvent(ETIE_COUNT);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_last_touch.time = time_now;
|
||||||
|
m_last_touch.pos = m_pointer;
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
} else if (event.TouchInput.touchedCount == 2) {
|
} else if (event.TouchInput.touchedCount == 2) {
|
||||||
if (event.TouchInput.Event != ETIE_LEFT_UP)
|
if (event.TouchInput.Event != ETIE_LEFT_UP)
|
||||||
@ -325,14 +339,9 @@ bool GUIModalMenu::preprocessEvent(const SEvent &event)
|
|||||||
m_touch_hovered.reset();
|
m_touch_hovered.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
gui::IGUIElement *hovered =
|
if (remapDoubleClick(event))
|
||||||
Environment->getRootGUIElement()->getElementFromPoint(m_pointer);
|
|
||||||
if (!isChild(hovered, this)) {
|
|
||||||
if (DoubleClickDetection(event)) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -69,13 +69,6 @@ protected:
|
|||||||
virtual std::wstring getLabelByID(s32 id) = 0;
|
virtual std::wstring getLabelByID(s32 id) = 0;
|
||||||
virtual std::string getNameByID(s32 id) = 0;
|
virtual std::string getNameByID(s32 id) = 0;
|
||||||
|
|
||||||
/**
|
|
||||||
* check if event is part of a double click
|
|
||||||
* @param event event to evaluate
|
|
||||||
* @return true/false if a doubleclick was detected
|
|
||||||
*/
|
|
||||||
bool DoubleClickDetection(const SEvent &event);
|
|
||||||
|
|
||||||
// Stores the last known pointer type.
|
// Stores the last known pointer type.
|
||||||
PointerType m_pointer_type = PointerType::Mouse;
|
PointerType m_pointer_type = PointerType::Mouse;
|
||||||
// Stores the last known pointer position.
|
// Stores the last known pointer position.
|
||||||
@ -97,13 +90,6 @@ protected:
|
|||||||
bool m_simulated_mouse = false;
|
bool m_simulated_mouse = false;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct clickpos
|
|
||||||
{
|
|
||||||
v2s32 pos;
|
|
||||||
s64 time;
|
|
||||||
};
|
|
||||||
clickpos m_doubleclickdetect[2];
|
|
||||||
|
|
||||||
IMenuManager *m_menumgr;
|
IMenuManager *m_menumgr;
|
||||||
/* If true, remap a double-click (or double-tap) action to ESC. This is so
|
/* If true, remap a double-click (or double-tap) action to ESC. This is so
|
||||||
* that, for example, Android users can double-tap to close a formspec.
|
* that, for example, Android users can double-tap to close a formspec.
|
||||||
@ -112,6 +98,8 @@ private:
|
|||||||
* and the default value for the setting is true.
|
* and the default value for the setting is true.
|
||||||
*/
|
*/
|
||||||
bool m_remap_dbl_click;
|
bool m_remap_dbl_click;
|
||||||
|
bool remapDoubleClick(const SEvent &event);
|
||||||
|
|
||||||
// This might be necessary to expose to the implementation if it
|
// This might be necessary to expose to the implementation if it
|
||||||
// wants to launch other menus
|
// wants to launch other menus
|
||||||
bool m_allow_focus_removal = false;
|
bool m_allow_focus_removal = false;
|
||||||
@ -120,7 +108,13 @@ private:
|
|||||||
|
|
||||||
irr_ptr<gui::IGUIElement> m_touch_hovered;
|
irr_ptr<gui::IGUIElement> m_touch_hovered;
|
||||||
|
|
||||||
bool simulateMouseEvent(gui::IGUIElement *target, ETOUCH_INPUT_EVENT touch_event);
|
bool simulateMouseEvent(ETOUCH_INPUT_EVENT touch_event, bool second_try=false);
|
||||||
void enter(gui::IGUIElement *element);
|
void enter(gui::IGUIElement *element);
|
||||||
void leave();
|
void leave();
|
||||||
|
|
||||||
|
// Used to detect double-taps and convert them into double-click events.
|
||||||
|
struct {
|
||||||
|
v2s32 pos;
|
||||||
|
s64 time;
|
||||||
|
} m_last_touch;
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user