TouchControls: touch_use_crosshair, dig/place simulation refactoring (#15800)

-   get rid of simulated mouse events for digging/placing, use keyboard events
    instead
    -   consistent with other simulated events, less code, no need for a
        pointer position
    -   more correct: touch controls no longer break if you have custom
        dig/place keybindings set
-   move reading of "touch_use_crosshair" setting from Game to TouchControls
This commit is contained in:
grorp 2025-02-25 13:19:44 -05:00 committed by GitHub
parent abcd2e0b81
commit 5e89371ecd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 53 additions and 63 deletions

View file

@ -772,9 +772,10 @@ private:
bool m_is_paused = false;
bool m_touch_simulate_aux1 = false;
bool m_touch_use_crosshair;
inline bool isTouchCrosshairDisabled() {
return !m_touch_use_crosshair && camera->getCameraMode() == CAMERA_MODE_FIRST;
inline bool isTouchShootlineUsed()
{
return g_touchcontrols && g_touchcontrols->isShootlineAvailable() &&
camera->getCameraMode() == CAMERA_MODE_FIRST;
}
#ifdef __ANDROID__
bool m_android_chat_open;
@ -823,8 +824,6 @@ Game::Game() :
&settingChangedCallback, this);
g_settings->registerChangedCallback("pause_on_lost_focus",
&settingChangedCallback, this);
g_settings->registerChangedCallback("touch_use_crosshair",
&settingChangedCallback, this);
readSettings();
}
@ -1380,10 +1379,8 @@ bool Game::initGui()
gui_chat_console = make_irr<GUIChatConsole>(guienv, guienv->getRootGUIElement(),
-1, chat_backend, client, &g_menumgr);
if (shouldShowTouchControls()) {
if (shouldShowTouchControls())
g_touchcontrols = new TouchControls(device, texture_src);
g_touchcontrols->setUseCrosshair(!isTouchCrosshairDisabled());
}
return true;
}
@ -2980,9 +2977,6 @@ void Game::updateCameraMode()
if (player->allowed_camera_mode != CAMERA_MODE_ANY)
camera->setCameraMode(player->allowed_camera_mode);
if (g_touchcontrols)
g_touchcontrols->setUseCrosshair(!isTouchCrosshairDisabled());
GenericCAO *playercao = player->getCAO();
if (playercao) {
// Make the player visible depending on camera mode.
@ -3086,7 +3080,7 @@ void Game::processPlayerInteraction(f32 dtime, bool show_hud)
}
shootline.end = shootline.start + camera_direction * BS * d;
if (g_touchcontrols && isTouchCrosshairDisabled()) {
if (isTouchShootlineUsed()) {
shootline = g_touchcontrols->getShootline();
// Scale shootline to the acual distance the player can reach
shootline.end = shootline.start +
@ -4059,7 +4053,7 @@ void Game::drawScene(ProfilerGraph *graph, RunStats *stats)
(player->hud_flags & HUD_FLAG_CROSSHAIR_VISIBLE) &&
(this->camera->getCameraMode() != CAMERA_MODE_THIRD_FRONT));
if (g_touchcontrols && isTouchCrosshairDisabled())
if (isTouchShootlineUsed())
draw_crosshair = false;
this->m_rendering_engine->draw_scene(sky_color, this->m_game_ui->m_flags.show_hud,
@ -4139,10 +4133,6 @@ void Game::readSettings()
m_invert_hotbar_mouse_wheel = g_settings->getBool("invert_hotbar_mouse_wheel");
m_does_lost_focus_pause_game = g_settings->getBool("pause_on_lost_focus");
m_touch_use_crosshair = g_settings->getBool("touch_use_crosshair");
if (g_touchcontrols)
g_touchcontrols->setUseCrosshair(!isTouchCrosshairDisabled());
}
/****************************************************************************/

View file

@ -142,6 +142,12 @@ static EKEY_CODE id_to_keycode(touch_gui_button_id id)
std::string key = "";
switch (id) {
case dig_id:
key = "dig";
break;
case place_id:
key = "place";
break;
case jump_id:
key = "jump";
break;
@ -204,6 +210,7 @@ static EKEY_CODE id_to_keycode(touch_gui_button_id id)
static const char *setting_names[] = {
"touch_use_crosshair",
"touchscreen_threshold", "touch_long_tap_delay",
"fixed_virtual_joystick", "virtual_joystick_triggers_aux1",
"touch_layout",
@ -230,6 +237,7 @@ void TouchControls::settingChangedCallback(const std::string &name, void *data)
void TouchControls::readSettings()
{
m_use_crosshair = g_settings->getBool("touch_use_crosshair");
m_touchscreen_threshold = g_settings->getU16("touchscreen_threshold");
m_long_tap_delay = g_settings->getU16("touch_long_tap_delay");
m_fixed_joystick = g_settings->getBool("fixed_virtual_joystick");
@ -542,10 +550,11 @@ void TouchControls::translateEvent(const SEvent &event)
m_move_has_really_moved = false;
m_move_downtime = porting::getTimeMs();
m_move_pos = touch_pos;
// DON'T reset m_tap_state here, otherwise many short taps
// will be ignored if you tap very fast.
m_had_move_id = true;
m_move_prevent_short_tap = prevent_short_tap;
// DON'T reset m_tap_state here, otherwise many short taps
// will be ignored if you tap very fast.
}
}
}
@ -663,15 +672,13 @@ void TouchControls::step(float dtime)
// 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.
// Only updating when m_has_move_id means that the shootline will stay at
// it's last in-world position when the player doesn't need it.
if (!m_draw_crosshair && (m_has_move_id || m_had_move_id)) {
v2s32 pointer_pos = getPointerPos();
if (!m_use_crosshair && (m_has_move_id || m_had_move_id)) {
m_shootline = m_device
->getSceneManager()
->getSceneCollisionManager()
->getRayFromScreenCoordinates(pointer_pos);
->getRayFromScreenCoordinates(m_move_pos);
}
m_had_move_id = false;
}
@ -734,11 +741,11 @@ void TouchControls::releaseAll()
// Release those manually too since the change initiated by
// handleReleaseEvent will only be applied later by applyContextControls.
if (m_dig_pressed) {
emitMouseEvent(EMIE_LMOUSE_LEFT_UP);
emitKeyboardEvent(id_to_keycode(dig_id), false);
m_dig_pressed = false;
}
if (m_place_pressed) {
emitMouseEvent(EMIE_RMOUSE_LEFT_UP);
emitKeyboardEvent(id_to_keycode(place_id), false);
m_place_pressed = false;
}
}
@ -753,31 +760,6 @@ void TouchControls::show()
setVisible(true);
}
v2s32 TouchControls::getPointerPos()
{
if (m_draw_crosshair)
return v2s32(m_screensize.X / 2, m_screensize.Y / 2);
// We can't just use m_pointer_pos[m_move_id] because applyContextControls
// may emit release events after m_pointer_pos[m_move_id] is erased.
return m_move_pos;
}
void TouchControls::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;
event.MouseInput.Simulated = true;
m_receiver->OnEvent(event);
}
void TouchControls::applyContextControls(const TouchInteractionMode &mode)
{
// Since the pointed thing has already been determined when this function
@ -844,20 +826,20 @@ void TouchControls::applyContextControls(const TouchInteractionMode &mode)
target_place_pressed |= now < m_place_pressed_until;
if (target_dig_pressed && !m_dig_pressed) {
emitMouseEvent(EMIE_LMOUSE_PRESSED_DOWN);
emitKeyboardEvent(id_to_keycode(dig_id), true);
m_dig_pressed = true;
} else if (!target_dig_pressed && m_dig_pressed) {
emitMouseEvent(EMIE_LMOUSE_LEFT_UP);
emitKeyboardEvent(id_to_keycode(dig_id), false);
m_dig_pressed = false;
}
if (target_place_pressed && !m_place_pressed) {
emitMouseEvent(EMIE_RMOUSE_PRESSED_DOWN);
emitKeyboardEvent(id_to_keycode(place_id), true);
m_place_pressed = true;
} else if (!target_place_pressed && m_place_pressed) {
emitMouseEvent(EMIE_RMOUSE_LEFT_UP);
emitKeyboardEvent(id_to_keycode(place_id), false);
m_place_pressed = false;
}
}

View file

@ -93,6 +93,8 @@ public:
return res;
}
bool isShootlineAvailable() { return !m_use_crosshair; }
/**
* Returns a line which describes what the player is pointing at.
* The starting point and looking direction are significant,
@ -100,6 +102,9 @@ public:
* the player can reach.
* The line starts at the camera and ends on the camera's far plane.
* The coordinates do not contain the camera offset.
*
* This may only be used if isShootlineAvailable returns true.
* Otherwise, the normal crosshair must be used.
*/
line3d<f32> getShootline() { return m_shootline; }
@ -107,7 +112,6 @@ public:
float getJoystickSpeed() { return m_joystick_speed; }
void step(float dtime);
inline void setUseCrosshair(bool use_crosshair) { m_draw_crosshair = use_crosshair; }
void setVisible(bool visible);
void hide();
@ -132,6 +136,7 @@ private:
s32 m_button_size;
// cached settings
bool m_use_crosshair;
double m_touchscreen_threshold;
u16 m_long_tap_delay;
bool m_fixed_joystick;
@ -143,9 +148,6 @@ private:
ButtonLayout m_layout;
void applyLayout(const ButtonLayout &layout);
// not read from a setting, but set by Game via setUseCrosshair
bool m_draw_crosshair = false;
std::unordered_map<u16, recti> m_hotbar_rects;
std::optional<u16> m_hotbar_selection = std::nullopt;
@ -157,6 +159,8 @@ private:
* A line starting at the camera and pointing towards the selected object.
* The line ends on the camera's far plane.
* The coordinates do not contain the camera offset.
*
* Only valid if !m_use_crosshair
*/
line3d<f32> m_shootline;
@ -164,7 +168,9 @@ private:
size_t m_move_id;
bool m_move_has_really_moved = false;
u64 m_move_downtime = 0;
// m_move_pos stays valid even after m_move_id has been released.
// m_move_pos stays valid even after the m_move_id pointer has been
// released and m_pointer_pos[m_move_id] has been erased
// (or even overwritten by a new pointer reusing the same id).
v2s32 m_move_pos;
// This is needed so that we don't miss if m_has_move_id is true for less
// than one client step, i.e. press and release happen in the same step.
@ -236,8 +242,6 @@ private:
// map to store the IDs and positions of currently pressed pointers
std::unordered_map<size_t, v2s32> m_pointer_pos;
v2s32 getPointerPos();
void emitMouseEvent(EMOUSE_INPUT_EVENT type);
TouchInteractionMode m_last_mode = TouchInteractionMode_END;
TapState m_tap_state = TapState::None;

View file

@ -14,6 +14,9 @@
#include "IGUIStaticText.h"
const char *button_names[] = {
"dig",
"place",
"jump",
"sneak",
"zoom",
@ -41,6 +44,9 @@ const char *button_names[] = {
// compare with GUIKeyChangeMenu::init_keys
const char *button_titles[] = {
N_("Dig/punch/use"),
N_("Place/use"),
N_("Jump"),
N_("Sneak"),
N_("Zoom"),
@ -67,6 +73,9 @@ const char *button_titles[] = {
};
const char *button_image_names[] = {
"",
"",
"jump_btn.png",
"down.png",
"zoom.png",
@ -123,7 +132,8 @@ void ButtonMeta::setPos(v2s32 pos, v2u32 screensize, s32 button_size)
bool ButtonLayout::isButtonAllowed(touch_gui_button_id id)
{
return id != joystick_off_id && id != joystick_bg_id && id != joystick_center_id &&
return id != dig_id && id != place_id &&
id != joystick_off_id && id != joystick_bg_id && id != joystick_center_id &&
id != touch_gui_button_id_END;
}

View file

@ -22,7 +22,11 @@ namespace irr::video
enum touch_gui_button_id : u8
{
jump_id = 0,
// these two are no actual buttons ... yet
dig_id = 0,
place_id,
jump_id,
sneak_id,
zoom_id,
aux1_id,