mirror of
https://github.com/minetest/minetest.git
synced 2024-11-26 17:43:45 +01:00
Touchscreen: Allow mods to swap the meaning of short and long taps (punch with single tap) (#14087)
This works through a new field "touch_interaction" in item definitions. The two most important use cases are: - Punching players/entities with short tap instead of long tap (enabled by default) - Making items usable that require holding the place button (e.g. bows and shields in MC-like games)
This commit is contained in:
parent
8cbd629010
commit
404a063fdf
@ -9,8 +9,8 @@ due to limited capabilities of common devices. What can be done is described bel
|
|||||||
While you're playing the game normally (that is, no menu or inventory is
|
While you're playing the game normally (that is, no menu or inventory is
|
||||||
shown), the following controls are available:
|
shown), the following controls are available:
|
||||||
* Look around: touch screen and slide finger
|
* Look around: touch screen and slide finger
|
||||||
* Tap: Place a node
|
* Tap: Place a node, punch an object or use the selected item (default)
|
||||||
* Long tap: Dig node or use the held item
|
* Long tap: Dig a node or use the selected item (default)
|
||||||
* Press back: Pause menu
|
* Press back: Pause menu
|
||||||
* Touch buttons: Press button
|
* Touch buttons: Press button
|
||||||
* Buttons:
|
* Buttons:
|
||||||
|
@ -8787,6 +8787,20 @@ Used by `minetest.register_node`, `minetest.register_craftitem`, and
|
|||||||
-- Otherwise should be name of node which the client immediately places
|
-- Otherwise should be name of node which the client immediately places
|
||||||
-- upon digging. Server will always update with actual result shortly.
|
-- upon digging. Server will always update with actual result shortly.
|
||||||
|
|
||||||
|
touch_interaction = {
|
||||||
|
-- Only affects touchscreen clients.
|
||||||
|
-- Defines the meaning of short and long taps with the item in hand.
|
||||||
|
-- The fields in this table have two valid values:
|
||||||
|
-- * "long_dig_short_place" (long tap = dig, short tap = place)
|
||||||
|
-- * "short_dig_long_place" (short tap = dig, long tap = place)
|
||||||
|
-- The field to be used is selected according to the current
|
||||||
|
-- `pointed_thing`.
|
||||||
|
|
||||||
|
pointed_nothing = "long_dig_short_place",
|
||||||
|
pointed_node = "long_dig_short_place",
|
||||||
|
pointed_object = "short_dig_long_place",
|
||||||
|
},
|
||||||
|
|
||||||
sound = {
|
sound = {
|
||||||
-- Definition of item sounds to be played at various events.
|
-- Definition of item sounds to be played at various events.
|
||||||
-- All fields in this table are optional.
|
-- All fields in this table are optional.
|
||||||
|
@ -3349,6 +3349,11 @@ void Game::processPlayerInteraction(f32 dtime, bool show_hud)
|
|||||||
if (pointed != runData.pointed_old)
|
if (pointed != runData.pointed_old)
|
||||||
infostream << "Pointing at " << pointed.dump() << std::endl;
|
infostream << "Pointing at " << pointed.dump() << std::endl;
|
||||||
|
|
||||||
|
#ifdef HAVE_TOUCHSCREENGUI
|
||||||
|
if (g_touchscreengui)
|
||||||
|
g_touchscreengui->applyContextControls(selected_def.touch_interaction.getMode(pointed));
|
||||||
|
#endif
|
||||||
|
|
||||||
// Note that updating the selection mesh every frame is not particularly efficient,
|
// Note that updating the selection mesh every frame is not particularly efficient,
|
||||||
// but the halo rendering code is already inefficient so there's no point in optimizing it here
|
// but the halo rendering code is already inefficient so there's no point in optimizing it here
|
||||||
hud->updateSelectionMesh(camera_offset);
|
hud->updateSelectionMesh(camera_offset);
|
||||||
@ -4484,8 +4489,8 @@ void Game::showPauseMenu()
|
|||||||
static const std::string control_text = strgettext("Controls:\n"
|
static const std::string control_text = strgettext("Controls:\n"
|
||||||
"No menu open:\n"
|
"No menu open:\n"
|
||||||
"- slide finger: look around\n"
|
"- slide finger: look around\n"
|
||||||
"- tap: place/use\n"
|
"- tap: place/punch/use (default)\n"
|
||||||
"- long tap: dig/punch/use\n"
|
"- long tap: dig/use (default)\n"
|
||||||
"Menu/inventory open:\n"
|
"Menu/inventory open:\n"
|
||||||
"- double tap (outside):\n"
|
"- double tap (outside):\n"
|
||||||
" --> close\n"
|
" --> close\n"
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
Copyright (C) 2014 sapier
|
Copyright (C) 2014 sapier
|
||||||
Copyright (C) 2018 srifqi, Muhammad Rifqi Priyo Susanto
|
Copyright (C) 2018 srifqi, Muhammad Rifqi Priyo Susanto
|
||||||
<muhammadrifqipriyosusanto@gmail.com>
|
<muhammadrifqipriyosusanto@gmail.com>
|
||||||
|
Copyright (C) 2024 grorp, Gregor Parzefall
|
||||||
|
<gregor.parzefall@posteo.de>
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
This program is free software; you can redistribute it and/or modify
|
||||||
it under the terms of the GNU Lesser General Public License as published by
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
@ -657,23 +659,13 @@ void TouchScreenGUI::handleReleaseEvent(size_t evt_id)
|
|||||||
// handle the point used for moving view
|
// handle the point used for moving view
|
||||||
m_has_move_id = false;
|
m_has_move_id = false;
|
||||||
|
|
||||||
// if this pointer issued a mouse event issue symmetric release here
|
// If m_tap_state is already set to TapState::ShortTap, we must keep
|
||||||
if (m_move_sent_as_mouse_event) {
|
// that value. Otherwise, many short taps will be ignored if you tap
|
||||||
SEvent translated {};
|
// very fast.
|
||||||
translated.EventType = EET_MOUSE_INPUT_EVENT;
|
if (!m_move_has_really_moved && m_tap_state != TapState::LongTap) {
|
||||||
translated.MouseInput.X = m_move_downlocation.X;
|
m_tap_state = TapState::ShortTap;
|
||||||
translated.MouseInput.Y = m_move_downlocation.Y;
|
} else {
|
||||||
translated.MouseInput.Shift = false;
|
m_tap_state = TapState::None;
|
||||||
translated.MouseInput.Control = false;
|
|
||||||
translated.MouseInput.ButtonStates = 0;
|
|
||||||
translated.MouseInput.Event = EMIE_LMOUSE_LEFT_UP;
|
|
||||||
if (m_draw_crosshair) {
|
|
||||||
translated.MouseInput.X = m_screensize.X / 2;
|
|
||||||
translated.MouseInput.Y = m_screensize.Y / 2;
|
|
||||||
}
|
|
||||||
m_receiver->OnEvent(translated);
|
|
||||||
} else if (!m_move_has_really_moved) {
|
|
||||||
doRightClick();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -794,10 +786,8 @@ void TouchScreenGUI::translateEvent(const SEvent &event)
|
|||||||
m_move_id = event.TouchInput.ID;
|
m_move_id = event.TouchInput.ID;
|
||||||
m_move_has_really_moved = false;
|
m_move_has_really_moved = false;
|
||||||
m_move_downtime = porting::getTimeMs();
|
m_move_downtime = porting::getTimeMs();
|
||||||
m_move_downlocation = touch_pos;
|
// DON'T reset m_tap_state here, otherwise many short taps
|
||||||
m_move_sent_as_mouse_event = false;
|
// will be ignored if you tap very fast.
|
||||||
if (m_draw_crosshair)
|
|
||||||
m_move_downlocation = v2s32(m_screensize.X / 2, m_screensize.Y / 2);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -820,33 +810,20 @@ void TouchScreenGUI::translateEvent(const SEvent &event)
|
|||||||
|
|
||||||
const double touch_threshold_sq = m_touchscreen_threshold * m_touchscreen_threshold;
|
const double touch_threshold_sq = m_touchscreen_threshold * m_touchscreen_threshold;
|
||||||
|
|
||||||
if (m_has_move_id) {
|
if (m_has_move_id && event.TouchInput.ID == m_move_id) {
|
||||||
if (event.TouchInput.ID == m_move_id &&
|
|
||||||
(!m_move_sent_as_mouse_event || m_draw_crosshair)) {
|
|
||||||
if (dir_free.getLengthSQ() > touch_threshold_sq || m_move_has_really_moved) {
|
if (dir_free.getLengthSQ() > touch_threshold_sq || m_move_has_really_moved) {
|
||||||
m_move_has_really_moved = true;
|
m_move_has_really_moved = true;
|
||||||
|
|
||||||
// update camera_yaw and camera_pitch
|
|
||||||
m_pointer_pos[event.TouchInput.ID] = touch_pos;
|
m_pointer_pos[event.TouchInput.ID] = touch_pos;
|
||||||
|
|
||||||
|
if (m_tap_state == TapState::None || m_draw_crosshair) {
|
||||||
// adapt to similar behavior as pc screen
|
// adapt to similar behavior as pc screen
|
||||||
const double d = g_settings->getFloat("touchscreen_sensitivity", 0.001f, 10.0f) * 3.0f;
|
const double d = g_settings->getFloat("touchscreen_sensitivity", 0.001f, 10.0f) * 3.0f;
|
||||||
|
|
||||||
|
// update camera_yaw and camera_pitch
|
||||||
m_camera_yaw_change -= dir_free.X * d;
|
m_camera_yaw_change -= dir_free.X * d;
|
||||||
m_camera_pitch_change += dir_free.Y * d;
|
m_camera_pitch_change += dir_free.Y * d;
|
||||||
|
|
||||||
// update shootline
|
|
||||||
// no need to update (X, Y) when using crosshair since the shootline is not used
|
|
||||||
m_shootline = m_device
|
|
||||||
->getSceneManager()
|
|
||||||
->getSceneCollisionManager()
|
|
||||||
->getRayFromScreenCoordinates(touch_pos);
|
|
||||||
}
|
}
|
||||||
} else if (event.TouchInput.ID == m_move_id && m_move_sent_as_mouse_event) {
|
|
||||||
m_shootline = m_device
|
|
||||||
->getSceneManager()
|
|
||||||
->getSceneCollisionManager()
|
|
||||||
->getRayFromScreenCoordinates(touch_pos);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -931,40 +908,6 @@ void TouchScreenGUI::handleChangedButton(const SEvent &event)
|
|||||||
handleButtonEvent((touch_gui_button_id) current_button_id, event.TouchInput.ID, true);
|
handleButtonEvent((touch_gui_button_id) current_button_id, event.TouchInput.ID, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TouchScreenGUI::doRightClick()
|
|
||||||
{
|
|
||||||
v2s32 mPos = v2s32(m_move_downlocation.X, m_move_downlocation.Y);
|
|
||||||
if (m_draw_crosshair) {
|
|
||||||
mPos.X = m_screensize.X / 2;
|
|
||||||
mPos.Y = m_screensize.Y / 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
SEvent translated {};
|
|
||||||
translated.EventType = EET_MOUSE_INPUT_EVENT;
|
|
||||||
translated.MouseInput.X = mPos.X;
|
|
||||||
translated.MouseInput.Y = mPos.Y;
|
|
||||||
translated.MouseInput.Shift = false;
|
|
||||||
translated.MouseInput.Control = false;
|
|
||||||
translated.MouseInput.ButtonStates = EMBSM_RIGHT;
|
|
||||||
|
|
||||||
// update shootline
|
|
||||||
m_shootline = m_device
|
|
||||||
->getSceneManager()
|
|
||||||
->getSceneCollisionManager()
|
|
||||||
->getRayFromScreenCoordinates(mPos);
|
|
||||||
|
|
||||||
translated.MouseInput.Event = EMIE_RMOUSE_PRESSED_DOWN;
|
|
||||||
verbosestream << "TouchScreenGUI::translateEvent right click press" << std::endl;
|
|
||||||
m_receiver->OnEvent(translated);
|
|
||||||
|
|
||||||
translated.MouseInput.ButtonStates = 0;
|
|
||||||
translated.MouseInput.Event = EMIE_RMOUSE_LEFT_UP;
|
|
||||||
verbosestream << "TouchScreenGUI::translateEvent right click release" << std::endl;
|
|
||||||
m_receiver->OnEvent(translated);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TouchScreenGUI::applyJoystickStatus()
|
void TouchScreenGUI::applyJoystickStatus()
|
||||||
{
|
{
|
||||||
if (m_joystick_triggers_aux1) {
|
if (m_joystick_triggers_aux1) {
|
||||||
@ -1038,35 +981,25 @@ void TouchScreenGUI::step(float dtime)
|
|||||||
applyJoystickStatus();
|
applyJoystickStatus();
|
||||||
|
|
||||||
// if a new placed pointer isn't moved for some time start digging
|
// if a new placed pointer isn't moved for some time start digging
|
||||||
if (m_has_move_id &&
|
if (m_has_move_id && !m_move_has_really_moved && m_tap_state == TapState::None) {
|
||||||
(!m_move_has_really_moved) &&
|
|
||||||
(!m_move_sent_as_mouse_event)) {
|
|
||||||
u64 delta = porting::getDeltaMs(m_move_downtime, porting::getTimeMs());
|
u64 delta = porting::getDeltaMs(m_move_downtime, porting::getTimeMs());
|
||||||
|
|
||||||
if (delta > MIN_DIG_TIME_MS) {
|
if (delta > MIN_DIG_TIME_MS) {
|
||||||
s32 mX = m_move_downlocation.X;
|
m_tap_state = TapState::LongTap;
|
||||||
s32 mY = m_move_downlocation.Y;
|
|
||||||
if (m_draw_crosshair) {
|
|
||||||
mX = m_screensize.X / 2;
|
|
||||||
mY = m_screensize.Y / 2;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the shootline.
|
||||||
|
// Since not only the pointer position, but also the player position and
|
||||||
|
// thus the camera position can change, it doesn't suffice to update the
|
||||||
|
// shootline when a touch event occurs.
|
||||||
|
// Note that the shootline isn't used if touch_use_crosshair is enabled.
|
||||||
|
if (!m_draw_crosshair) {
|
||||||
|
v2s32 pointer_pos = getPointerPos();
|
||||||
m_shootline = m_device
|
m_shootline = m_device
|
||||||
->getSceneManager()
|
->getSceneManager()
|
||||||
->getSceneCollisionManager()
|
->getSceneCollisionManager()
|
||||||
->getRayFromScreenCoordinates(v2s32(mX, mY));
|
->getRayFromScreenCoordinates(pointer_pos);
|
||||||
|
|
||||||
SEvent translated {};
|
|
||||||
translated.EventType = EET_MOUSE_INPUT_EVENT;
|
|
||||||
translated.MouseInput.X = mX;
|
|
||||||
translated.MouseInput.Y = mY;
|
|
||||||
translated.MouseInput.Shift = false;
|
|
||||||
translated.MouseInput.Control = false;
|
|
||||||
translated.MouseInput.ButtonStates = EMBSM_LEFT;
|
|
||||||
translated.MouseInput.Event = EMIE_LMOUSE_PRESSED_DOWN;
|
|
||||||
verbosestream << "TouchScreenGUI::step left click press" << std::endl;
|
|
||||||
m_receiver->OnEvent(translated);
|
|
||||||
m_move_sent_as_mouse_event = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_settings_bar.step(dtime);
|
m_settings_bar.step(dtime);
|
||||||
@ -1125,3 +1058,100 @@ void TouchScreenGUI::show()
|
|||||||
|
|
||||||
setVisible(true);
|
setVisible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
v2s32 TouchScreenGUI::getPointerPos()
|
||||||
|
{
|
||||||
|
if (m_draw_crosshair)
|
||||||
|
return v2s32(m_screensize.X / 2, m_screensize.Y / 2);
|
||||||
|
return m_pointer_pos[m_move_id];
|
||||||
|
}
|
||||||
|
|
||||||
|
void TouchScreenGUI::emitMouseEvent(EMOUSE_INPUT_EVENT type)
|
||||||
|
{
|
||||||
|
v2s32 pointer_pos = getPointerPos();
|
||||||
|
|
||||||
|
SEvent event{};
|
||||||
|
event.EventType = EET_MOUSE_INPUT_EVENT;
|
||||||
|
event.MouseInput.X = pointer_pos.X;
|
||||||
|
event.MouseInput.Y = pointer_pos.Y;
|
||||||
|
event.MouseInput.Shift = false;
|
||||||
|
event.MouseInput.Control = false;
|
||||||
|
event.MouseInput.ButtonStates = 0;
|
||||||
|
event.MouseInput.Event = type;
|
||||||
|
m_receiver->OnEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TouchScreenGUI::applyContextControls(const TouchInteractionMode &mode)
|
||||||
|
{
|
||||||
|
// Since the pointed thing has already been determined when this function
|
||||||
|
// is called, we cannot use this function to update the shootline.
|
||||||
|
|
||||||
|
bool target_dig_pressed = false;
|
||||||
|
bool target_place_pressed = false;
|
||||||
|
|
||||||
|
u64 now = porting::getTimeMs();
|
||||||
|
|
||||||
|
switch (m_tap_state) {
|
||||||
|
case TapState::ShortTap:
|
||||||
|
if (mode == SHORT_DIG_LONG_PLACE) {
|
||||||
|
if (!m_dig_pressed) {
|
||||||
|
// The button isn't currently pressed, we can press it.
|
||||||
|
m_dig_pressed_until = now + SIMULATED_CLICK_DURATION_MS;
|
||||||
|
// We're done with this short tap.
|
||||||
|
m_tap_state = TapState::None;
|
||||||
|
} else {
|
||||||
|
// The button is already pressed, perhaps due to another short tap.
|
||||||
|
// Release it now, press it again during the next client step.
|
||||||
|
// We can't release and press during the same client step because
|
||||||
|
// the digging code simply ignores that.
|
||||||
|
m_dig_pressed_until = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!m_place_pressed) {
|
||||||
|
// The button isn't currently pressed, we can press it.
|
||||||
|
m_place_pressed_until = now + SIMULATED_CLICK_DURATION_MS;
|
||||||
|
// We're done with this short tap.
|
||||||
|
m_tap_state = TapState::None;
|
||||||
|
} else {
|
||||||
|
// The button is already pressed, perhaps due to another short tap.
|
||||||
|
// Release it now, press it again during the next client step.
|
||||||
|
// We can't release and press during the same client step because
|
||||||
|
// the digging code simply ignores that.
|
||||||
|
m_place_pressed_until = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TapState::LongTap:
|
||||||
|
if (mode == SHORT_DIG_LONG_PLACE)
|
||||||
|
target_place_pressed = true;
|
||||||
|
else
|
||||||
|
target_dig_pressed = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TapState::None:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply short taps.
|
||||||
|
target_dig_pressed |= now < m_dig_pressed_until;
|
||||||
|
target_place_pressed |= now < m_place_pressed_until;
|
||||||
|
|
||||||
|
if (target_dig_pressed && !m_dig_pressed) {
|
||||||
|
emitMouseEvent(EMIE_LMOUSE_PRESSED_DOWN);
|
||||||
|
m_dig_pressed = true;
|
||||||
|
|
||||||
|
} else if (!target_dig_pressed && m_dig_pressed) {
|
||||||
|
emitMouseEvent(EMIE_LMOUSE_LEFT_UP);
|
||||||
|
m_dig_pressed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target_place_pressed && !m_place_pressed) {
|
||||||
|
emitMouseEvent(EMIE_RMOUSE_PRESSED_DOWN);
|
||||||
|
m_place_pressed = true;
|
||||||
|
|
||||||
|
} else if (!target_place_pressed && m_place_pressed) {
|
||||||
|
emitMouseEvent(irr::EMIE_RMOUSE_LEFT_UP);
|
||||||
|
m_place_pressed = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
Copyright (C) 2014 sapier
|
Copyright (C) 2014 sapier
|
||||||
|
Copyright (C) 2024 grorp, Gregor Parzefall
|
||||||
|
<gregor.parzefall@posteo.de>
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
This program is free software; you can redistribute it and/or modify
|
||||||
it under the terms of the GNU Lesser General Public License as published by
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
@ -29,6 +31,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "itemdef.h"
|
||||||
#include "client/tile.h"
|
#include "client/tile.h"
|
||||||
#include "client/game.h"
|
#include "client/game.h"
|
||||||
|
|
||||||
@ -36,6 +39,13 @@ using namespace irr;
|
|||||||
using namespace irr::core;
|
using namespace irr::core;
|
||||||
using namespace irr::gui;
|
using namespace irr::gui;
|
||||||
|
|
||||||
|
enum class TapState
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
ShortTap,
|
||||||
|
LongTap,
|
||||||
|
};
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
jump_id = 0,
|
jump_id = 0,
|
||||||
@ -75,6 +85,11 @@ typedef enum
|
|||||||
#define SETTINGS_BAR_Y_OFFSET 5
|
#define SETTINGS_BAR_Y_OFFSET 5
|
||||||
#define RARE_CONTROLS_BAR_Y_OFFSET 5
|
#define RARE_CONTROLS_BAR_Y_OFFSET 5
|
||||||
|
|
||||||
|
// Our simulated clicks last some milliseconds so that server-side mods have a
|
||||||
|
// chance to detect them via l_get_player_control.
|
||||||
|
// If you tap faster than this value, the simulated clicks are of course shorter.
|
||||||
|
#define SIMULATED_CLICK_DURATION_MS 50
|
||||||
|
|
||||||
extern const std::string button_image_names[];
|
extern const std::string button_image_names[];
|
||||||
extern const std::string joystick_image_names[];
|
extern const std::string joystick_image_names[];
|
||||||
|
|
||||||
@ -161,6 +176,7 @@ public:
|
|||||||
~TouchScreenGUI();
|
~TouchScreenGUI();
|
||||||
|
|
||||||
void translateEvent(const SEvent &event);
|
void translateEvent(const SEvent &event);
|
||||||
|
void applyContextControls(const TouchInteractionMode &mode);
|
||||||
|
|
||||||
void init(ISimpleTextureSource *tsrc);
|
void init(ISimpleTextureSource *tsrc);
|
||||||
|
|
||||||
@ -230,8 +246,6 @@ private:
|
|||||||
size_t m_move_id;
|
size_t m_move_id;
|
||||||
bool m_move_has_really_moved = false;
|
bool m_move_has_really_moved = false;
|
||||||
u64 m_move_downtime = 0;
|
u64 m_move_downtime = 0;
|
||||||
bool m_move_sent_as_mouse_event = false;
|
|
||||||
v2s32 m_move_downlocation = v2s32(-10000, -10000); // off-screen
|
|
||||||
|
|
||||||
bool m_has_joystick_id = false;
|
bool m_has_joystick_id = false;
|
||||||
size_t m_joystick_id;
|
size_t m_joystick_id;
|
||||||
@ -283,9 +297,6 @@ private:
|
|||||||
// handle pressing hotbar items
|
// handle pressing hotbar items
|
||||||
bool isHotbarButton(const SEvent &event);
|
bool isHotbarButton(const SEvent &event);
|
||||||
|
|
||||||
// do a right-click
|
|
||||||
bool doRightClick();
|
|
||||||
|
|
||||||
// handle release event
|
// handle release event
|
||||||
void handleReleaseEvent(size_t evt_id);
|
void handleReleaseEvent(size_t evt_id);
|
||||||
|
|
||||||
@ -300,6 +311,16 @@ private:
|
|||||||
|
|
||||||
// rare controls bar
|
// rare controls bar
|
||||||
AutoHideButtonBar m_rare_controls_bar;
|
AutoHideButtonBar m_rare_controls_bar;
|
||||||
|
|
||||||
|
v2s32 getPointerPos();
|
||||||
|
void emitMouseEvent(EMOUSE_INPUT_EVENT type);
|
||||||
|
TapState m_tap_state = TapState::None;
|
||||||
|
|
||||||
|
bool m_dig_pressed = false;
|
||||||
|
u64 m_dig_pressed_until = 0;
|
||||||
|
|
||||||
|
bool m_place_pressed = false;
|
||||||
|
u64 m_place_pressed_until = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern TouchScreenGUI *g_touchscreengui;
|
extern TouchScreenGUI *g_touchscreengui;
|
||||||
|
@ -35,9 +35,60 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "util/serialize.h"
|
#include "util/serialize.h"
|
||||||
#include "util/container.h"
|
#include "util/container.h"
|
||||||
#include "util/thread.h"
|
#include "util/thread.h"
|
||||||
|
#include "util/pointedthing.h"
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
|
TouchInteraction::TouchInteraction()
|
||||||
|
{
|
||||||
|
pointed_nothing = LONG_DIG_SHORT_PLACE;
|
||||||
|
pointed_node = LONG_DIG_SHORT_PLACE;
|
||||||
|
// Map punching to single tap by default.
|
||||||
|
pointed_object = SHORT_DIG_LONG_PLACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
TouchInteractionMode TouchInteraction::getMode(const PointedThing &pointed) const
|
||||||
|
{
|
||||||
|
switch (pointed.type) {
|
||||||
|
case POINTEDTHING_NOTHING:
|
||||||
|
return pointed_nothing;
|
||||||
|
case POINTEDTHING_NODE:
|
||||||
|
return pointed_node;
|
||||||
|
case POINTEDTHING_OBJECT:
|
||||||
|
return pointed_object;
|
||||||
|
default:
|
||||||
|
FATAL_ERROR("Invalid PointedThingType given to TouchInteraction::getMode");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TouchInteraction::serialize(std::ostream &os) const
|
||||||
|
{
|
||||||
|
writeU8(os, pointed_nothing);
|
||||||
|
writeU8(os, pointed_node);
|
||||||
|
writeU8(os, pointed_object);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TouchInteraction::deSerialize(std::istream &is)
|
||||||
|
{
|
||||||
|
u8 tmp = readU8(is);
|
||||||
|
if (is.eof())
|
||||||
|
throw SerializationError("");
|
||||||
|
if (tmp < TouchInteractionMode_END)
|
||||||
|
pointed_nothing = (TouchInteractionMode)tmp;
|
||||||
|
|
||||||
|
tmp = readU8(is);
|
||||||
|
if (is.eof())
|
||||||
|
throw SerializationError("");
|
||||||
|
if (tmp < TouchInteractionMode_END)
|
||||||
|
pointed_node = (TouchInteractionMode)tmp;
|
||||||
|
|
||||||
|
tmp = readU8(is);
|
||||||
|
if (is.eof())
|
||||||
|
throw SerializationError("");
|
||||||
|
if (tmp < TouchInteractionMode_END)
|
||||||
|
pointed_object = (TouchInteractionMode)tmp;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
ItemDefinition
|
ItemDefinition
|
||||||
*/
|
*/
|
||||||
@ -84,6 +135,7 @@ ItemDefinition& ItemDefinition::operator=(const ItemDefinition &def)
|
|||||||
range = def.range;
|
range = def.range;
|
||||||
palette_image = def.palette_image;
|
palette_image = def.palette_image;
|
||||||
color = def.color;
|
color = def.color;
|
||||||
|
touch_interaction = def.touch_interaction;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,6 +178,7 @@ void ItemDefinition::reset()
|
|||||||
node_placement_prediction.clear();
|
node_placement_prediction.clear();
|
||||||
place_param2.reset();
|
place_param2.reset();
|
||||||
wallmounted_rotate_vertical = false;
|
wallmounted_rotate_vertical = false;
|
||||||
|
touch_interaction = TouchInteraction();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ItemDefinition::serialize(std::ostream &os, u16 protocol_version) const
|
void ItemDefinition::serialize(std::ostream &os, u16 protocol_version) const
|
||||||
@ -185,7 +238,9 @@ void ItemDefinition::serialize(std::ostream &os, u16 protocol_version) const
|
|||||||
os << (u8)place_param2.has_value(); // protocol_version >= 43
|
os << (u8)place_param2.has_value(); // protocol_version >= 43
|
||||||
if (place_param2)
|
if (place_param2)
|
||||||
os << *place_param2;
|
os << *place_param2;
|
||||||
|
|
||||||
writeU8(os, wallmounted_rotate_vertical);
|
writeU8(os, wallmounted_rotate_vertical);
|
||||||
|
touch_interaction.serialize(os);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ItemDefinition::deSerialize(std::istream &is, u16 protocol_version)
|
void ItemDefinition::deSerialize(std::istream &is, u16 protocol_version)
|
||||||
@ -260,6 +315,7 @@ void ItemDefinition::deSerialize(std::istream &is, u16 protocol_version)
|
|||||||
place_param2 = readU8(is);
|
place_param2 = readU8(is);
|
||||||
|
|
||||||
wallmounted_rotate_vertical = readU8(is); // 0 if missing
|
wallmounted_rotate_vertical = readU8(is); // 0 if missing
|
||||||
|
touch_interaction.deSerialize(is);
|
||||||
} catch(SerializationError &e) {};
|
} catch(SerializationError &e) {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,6 +31,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
class IGameDef;
|
class IGameDef;
|
||||||
class Client;
|
class Client;
|
||||||
struct ToolCapabilities;
|
struct ToolCapabilities;
|
||||||
|
struct PointedThing;
|
||||||
#ifndef SERVER
|
#ifndef SERVER
|
||||||
#include "client/tile.h"
|
#include "client/tile.h"
|
||||||
struct ItemMesh;
|
struct ItemMesh;
|
||||||
@ -50,6 +51,25 @@ enum ItemType : u8
|
|||||||
ItemType_END // Dummy for validity check
|
ItemType_END // Dummy for validity check
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum TouchInteractionMode : u8
|
||||||
|
{
|
||||||
|
LONG_DIG_SHORT_PLACE,
|
||||||
|
SHORT_DIG_LONG_PLACE,
|
||||||
|
TouchInteractionMode_END, // Dummy for validity check
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TouchInteraction
|
||||||
|
{
|
||||||
|
TouchInteractionMode pointed_nothing;
|
||||||
|
TouchInteractionMode pointed_node;
|
||||||
|
TouchInteractionMode pointed_object;
|
||||||
|
|
||||||
|
TouchInteraction();
|
||||||
|
TouchInteractionMode getMode(const PointedThing &pointed) const;
|
||||||
|
void serialize(std::ostream &os) const;
|
||||||
|
void deSerialize(std::istream &is);
|
||||||
|
};
|
||||||
|
|
||||||
struct ItemDefinition
|
struct ItemDefinition
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@ -92,6 +112,8 @@ struct ItemDefinition
|
|||||||
std::optional<u8> place_param2;
|
std::optional<u8> place_param2;
|
||||||
bool wallmounted_rotate_vertical;
|
bool wallmounted_rotate_vertical;
|
||||||
|
|
||||||
|
TouchInteraction touch_interaction;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Some helpful methods
|
Some helpful methods
|
||||||
*/
|
*/
|
||||||
|
@ -138,6 +138,20 @@ void read_item_definition(lua_State* L, int index,
|
|||||||
def.place_param2 = rangelim(place_param2, 0, U8_MAX);
|
def.place_param2 = rangelim(place_param2, 0, U8_MAX);
|
||||||
|
|
||||||
getboolfield(L, index, "wallmounted_rotate_vertical", def.wallmounted_rotate_vertical);
|
getboolfield(L, index, "wallmounted_rotate_vertical", def.wallmounted_rotate_vertical);
|
||||||
|
|
||||||
|
lua_getfield(L, index, "touch_interaction");
|
||||||
|
if (!lua_isnil(L, -1)) {
|
||||||
|
luaL_checktype(L, -1, LUA_TTABLE);
|
||||||
|
|
||||||
|
TouchInteraction &inter = def.touch_interaction;
|
||||||
|
inter.pointed_nothing = (TouchInteractionMode)getenumfield(L, -1, "pointed_nothing",
|
||||||
|
es_TouchInteractionMode, inter.pointed_nothing);
|
||||||
|
inter.pointed_node = (TouchInteractionMode)getenumfield(L, -1, "pointed_node",
|
||||||
|
es_TouchInteractionMode, inter.pointed_node);
|
||||||
|
inter.pointed_object = (TouchInteractionMode)getenumfield(L, -1, "pointed_object",
|
||||||
|
es_TouchInteractionMode, inter.pointed_object);
|
||||||
|
}
|
||||||
|
lua_pop(L, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
@ -199,6 +213,16 @@ void push_item_definition_full(lua_State *L, const ItemDefinition &i)
|
|||||||
lua_setfield(L, -2, "node_placement_prediction");
|
lua_setfield(L, -2, "node_placement_prediction");
|
||||||
lua_pushboolean(L, i.wallmounted_rotate_vertical);
|
lua_pushboolean(L, i.wallmounted_rotate_vertical);
|
||||||
lua_setfield(L, -2, "wallmounted_rotate_vertical");
|
lua_setfield(L, -2, "wallmounted_rotate_vertical");
|
||||||
|
|
||||||
|
lua_createtable(L, 0, 3);
|
||||||
|
const TouchInteraction &inter = i.touch_interaction;
|
||||||
|
lua_pushstring(L, es_TouchInteractionMode[inter.pointed_nothing].str);
|
||||||
|
lua_setfield(L, -2,"pointed_nothing");
|
||||||
|
lua_pushstring(L, es_TouchInteractionMode[inter.pointed_node].str);
|
||||||
|
lua_setfield(L, -2,"pointed_node");
|
||||||
|
lua_pushstring(L, es_TouchInteractionMode[inter.pointed_object].str);
|
||||||
|
lua_setfield(L, -2,"pointed_object");
|
||||||
|
lua_setfield(L, -2, "touch_interaction");
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
@ -32,3 +32,10 @@ struct EnumString es_ItemType[] =
|
|||||||
{ITEM_TOOL, "tool"},
|
{ITEM_TOOL, "tool"},
|
||||||
{0, NULL},
|
{0, NULL},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct EnumString es_TouchInteractionMode[] =
|
||||||
|
{
|
||||||
|
{LONG_DIG_SHORT_PLACE, "long_dig_short_place"},
|
||||||
|
{SHORT_DIG_LONG_PLACE, "short_dig_long_place"},
|
||||||
|
{0, NULL},
|
||||||
|
};
|
||||||
|
@ -59,3 +59,4 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
extern EnumString es_ItemType[];
|
extern EnumString es_ItemType[];
|
||||||
|
extern EnumString es_TouchInteractionMode[];
|
||||||
|
Loading…
Reference in New Issue
Block a user