Skip to content

Commit

Permalink
*Improved usability on touch screen.
Browse files Browse the repository at this point in the history
  • Loading branch information
paladin-t committed Mar 18, 2024
1 parent 02ab1e2 commit 5c72b93
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 20 deletions.
86 changes: 68 additions & 18 deletions src/application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -645,10 +645,12 @@ class Application : public NonCopyable {
}

bool updateImGui(double delta, bool mouseCursorIndicated) {
// Prepare.
SDL_Window* wnd = (SDL_Window*)_window->pointer();

ImGuiIO &io = ImGui::GetIO();

// Handle the events.
SDL_Event evt;
bool alive = true;
bool reset = false;
Expand Down Expand Up @@ -882,18 +884,74 @@ class Application : public NonCopyable {
io.DisplayFramebufferScale = ImVec2((float)displayW / wndW, (float)displayH / wndH);
} while (false);

// Handle the mouse/touch input.
auto assignMouseStates = [&] (Window* wnd, Renderer* rnd, int mouseX, int mouseY) -> void {
const int scale = rnd->scale() / wnd->scale();
ImVec2 pos((float)mouseX, (float)mouseY);
if (scale != 1) {
pos.x /= scale;
pos.y /= scale;
}
if (_context.mousePosition.x != pos.x || _context.mousePosition.y != pos.y) {
_context.mousePosition = pos;

requestFrameRate(APPLICATION_INPUTING_FRAME_RATE);
}
io.MousePos = pos;
};

do {
io.MouseDown[0] = _context.mousePressed[0]; // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame.
io.MouseDown[1] = _context.mousePressed[1];
io.MouseDown[2] = _context.mousePressed[2];
_context.mousePressed[0] = _context.mousePressed[1] = _context.mousePressed[2] = false;
} while (false);

bool hasTouch = false;
do {
const int wndw = _window->width();
const int wndh = _window->height();

const int n = SDL_GetNumTouchDevices();
for (int m = 0; m < n; ++m) {
SDL_TouchID tid = SDL_GetTouchDevice(m);
if (tid == 0)
continue;

const int f = SDL_GetNumTouchFingers(tid);
for (int i = 0; i < f; ++i) {
SDL_Finger* finger = SDL_GetTouchFinger(tid, i);
if (!finger)
continue;

const int touchX = (int)(finger->x * ((float)wndw - Math::EPSILON<float>()));
const int touchY = (int)(finger->y * ((float)wndh - Math::EPSILON<float>()));
assignMouseStates(_window, _renderer, touchX, touchY);
io.MouseDown[0] |= true;
hasTouch = true;

break;
}

if (hasTouch)
break;
}
} while (false);

do {
if (hasTouch)
break;

if (io.WantSetMousePos)
SDL_WarpMouseInWindow(wnd, (int)io.MousePos.x, (int)io.MousePos.y);
else
io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);

int mouseX = 0, mouseY = 0;
const Uint32 mouseButtons = SDL_GetMouseState(&mouseX, &mouseY);
io.MouseDown[0] = _context.mousePressed[0] || !!(mouseButtons & SDL_BUTTON(SDL_BUTTON_LEFT)); // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame.
io.MouseDown[1] = _context.mousePressed[1] || !!(mouseButtons & SDL_BUTTON(SDL_BUTTON_RIGHT));
io.MouseDown[2] = _context.mousePressed[2] || !!(mouseButtons & SDL_BUTTON(SDL_BUTTON_MIDDLE));
_context.mousePressed[0] = _context.mousePressed[1] = _context.mousePressed[2] = false;
io.MouseDown[0] |= !!(mouseButtons & SDL_BUTTON(SDL_BUTTON_LEFT));
io.MouseDown[1] |= !!(mouseButtons & SDL_BUTTON(SDL_BUTTON_RIGHT));
io.MouseDown[2] |= !!(mouseButtons & SDL_BUTTON(SDL_BUTTON_MIDDLE));

#if SDL_VERSION_ATLEAST(2, 0, 4) && (defined BITTY_OS_WIN || defined BITTY_OS_MAC || defined BITTY_OS_LINUX)
SDL_Window* focusedWindow = SDL_GetKeyboardFocus();
Expand All @@ -908,27 +966,17 @@ class Application : public NonCopyable {
mouseX -= wndX;
mouseY -= wndY;
}
const int scale = _renderer->scale() / _window->scale();
ImVec2 pos((float)mouseX, (float)mouseY);
if (scale != 1) {
pos.x /= scale;
pos.y /= scale;
}
if (_context.mousePosition.x != pos.x || _context.mousePosition.y != pos.y) {
_context.mousePosition = pos;

requestFrameRate(APPLICATION_INPUTING_FRAME_RATE);
}
io.MousePos = pos;
assignMouseStates(_window, _renderer, mouseX, mouseY);
}

// `SDL_CaptureMouse` let the OS know e.g. that our ImGui drag outside the SDL window boundaries shouldn't e.g. trigger the OS window resize cursor.
// The function is only supported from SDL 2.0.4 (released Jan 2016).
const bool anyMouseButtonDown = ImGui::IsAnyMouseDown();
SDL_CaptureMouse(anyMouseButtonDown ? SDL_TRUE : SDL_FALSE);
#else /* Platform macro. */
if (SDL_GetWindowFlags(wnd) & SDL_WINDOW_INPUT_FOCUS)
io.MousePos = ImVec2((float)mouseX, (float)mouseY);
if (SDL_GetWindowFlags(wnd) & SDL_WINDOW_INPUT_FOCUS) {
assignMouseStates(_window, _renderer, mouseX, mouseY);
}
#endif /* Platform macro. */
} while (false);

Expand All @@ -951,6 +999,7 @@ class Application : public NonCopyable {
}
} while (false);

// Handle the gamepad input.
do {
memset(io.NavInputs, 0, sizeof(io.NavInputs));
if (!(io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad))
Expand Down Expand Up @@ -988,6 +1037,7 @@ class Application : public NonCopyable {
#undef MAP_ANALOG
} while (false);

// Finish.
return alive;
}

Expand Down
7 changes: 5 additions & 2 deletions src/input.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -537,16 +537,19 @@ class InputImpl : public Input {
SDL_TouchID tid = SDL_GetTouchDevice(m);
if (tid == 0)
continue;

const int f = SDL_GetNumTouchFingers(tid);
while ((int)_mouseStatesNative.size() < f)
_mouseStatesNative.push_back(Mouse(-1, -1, false, false, false, 0, 0));
for (int i = 0; i < f; ++i) {
SDL_Finger* finger = SDL_GetTouchFinger(tid, i);
if (!finger)
continue;

Mouse &touch = _mouseStatesNative[i];
if (touch.buttons[0])
continue;

touch = Mouse(
(int)(finger->x * ((float)wndw - Math::EPSILON<float>())),
(int)(finger->y * ((float)wndh - Math::EPSILON<float>())),
Expand All @@ -568,7 +571,7 @@ class InputImpl : public Input {
if (_mouseStatesNative.empty())
_mouseStatesNative.push_back(Mouse(-1, -1, false, false, false, 0, 0));
Mouse &touch = _mouseStatesNative[0];
Uint32 btns = SDL_GetMouseState(&touch.x, &touch.y);
const Uint32 btns = SDL_GetMouseState(&touch.x, &touch.y);
touch.buttons[0] = !!(btns & SDL_BUTTON(SDL_BUTTON_LEFT));
touch.buttons[1] = !!(btns & SDL_BUTTON(SDL_BUTTON_RIGHT));
touch.buttons[2] = !!(btns & SDL_BUTTON(SDL_BUTTON_MIDDLE));
Expand Down Expand Up @@ -835,7 +838,7 @@ class InputImpl : public Input {

if (!hasTouch) {
int x = 0, y = 0;
Uint32 btns = SDL_GetMouseState(&x, &y);
const Uint32 btns = SDL_GetMouseState(&x, &y);
if (!!(btns & SDL_BUTTON(SDL_BUTTON_LEFT))) {
if (collides(range, (float)x, (float)y, scale_)) {
pad[i] = true;
Expand Down

0 comments on commit 5c72b93

Please sign in to comment.