Skip to content

Commit

Permalink
Improve touch controls (#283)
Browse files Browse the repository at this point in the history
  • Loading branch information
alexbatalov committed May 9, 2023
1 parent efdc2e0 commit a06097a
Show file tree
Hide file tree
Showing 8 changed files with 406 additions and 130 deletions.
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,8 @@ target_sources(${EXECUTABLE_NAME} PUBLIC
"src/sfall_lists.h"
"src/sfall_opcodes.cc"
"src/sfall_opcodes.h"
"src/touch.cc"
"src/touch.h"
)

if(IOS)
Expand Down
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,11 @@ $ sudo apt install libsdl2-2.0-0

### Android

> **NOTE**: Fallout 2 was designed with mouse in mind. There are many controls that require precise cursor positioning, which is not possible with fingers. When playing on Android you'll use fingers to move mouse cursor, not a character, or a map. Double tap to "click" left mouse button in the current cursor position, triple tap to "click" right mouse button. It might feel awkward at first, but it's super handy - you can play with just a thumb. This is not set in stone and might change in the future.
> **NOTE**: Fallout 2 was designed with mouse in mind. There are many controls that require precise cursor positioning, which is not possible with fingers. Current control scheme resembles trackpad usage:
- One finger moves mouse cursor around.
- Tap one finger for left mouse click.
- Tap two fingers for right mouse click (switches mouse cursor mode).
- Move two fingers to scroll current view (map view, worldmap view, inventory scrollers).

> **NOTE**: From Android standpoint release and debug builds are different apps. Both apps require their own copy of game assets and have their own savegames. This is intentional. As a gamer just stick with release version and check for updates.
Expand Down
136 changes: 8 additions & 128 deletions src/dinput.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,9 @@

namespace fallout {

enum InputType {
INPUT_TYPE_MOUSE,
INPUT_TYPE_TOUCH,
} InputType;

static int gLastInputType = INPUT_TYPE_MOUSE;

static int gTouchMouseLastX = 0;
static int gTouchMouseLastY = 0;
static int gTouchMouseDeltaX = 0;
static int gTouchMouseDeltaY = 0;

static int gTouchFingers = 0;
static unsigned int gTouchGestureLastTouchDownTimestamp = 0;
static unsigned int gTouchGestureLastTouchUpTimestamp = 0;
static int gTouchGestureTaps = 0;
static bool gTouchGestureHandled = false;

static int gMouseWheelDeltaX = 0;
static int gMouseWheelDeltaY = 0;

extern int screenGetWidth();
extern int screenGetHeight();

// 0x4E0400
bool directInputInit()
{
Expand Down Expand Up @@ -71,49 +50,14 @@ bool mouseDeviceUnacquire()
// 0x4E053C
bool mouseDeviceGetData(MouseData* mouseState)
{
if (gLastInputType == INPUT_TYPE_TOUCH) {
mouseState->x = gTouchMouseDeltaX;
mouseState->y = gTouchMouseDeltaY;
mouseState->buttons[0] = 0;
mouseState->buttons[1] = 0;
mouseState->wheelX = 0;
mouseState->wheelY = 0;
gTouchMouseDeltaX = 0;
gTouchMouseDeltaY = 0;

if (gTouchFingers == 0) {
if (SDL_GetTicks() - gTouchGestureLastTouchUpTimestamp > 150) {
if (!gTouchGestureHandled) {
if (gTouchGestureTaps == 2) {
mouseState->buttons[0] = 1;
gTouchGestureHandled = true;
} else if (gTouchGestureTaps == 3) {
mouseState->buttons[1] = 1;
gTouchGestureHandled = true;
}
}
}
} else if (gTouchFingers == 1) {
if (SDL_GetTicks() - gTouchGestureLastTouchDownTimestamp > 150) {
if (gTouchGestureTaps == 1) {
mouseState->buttons[0] = 1;
gTouchGestureHandled = true;
} else if (gTouchGestureTaps == 2) {
mouseState->buttons[1] = 1;
gTouchGestureHandled = true;
}
}
}
} else {
Uint32 buttons = SDL_GetRelativeMouseState(&(mouseState->x), &(mouseState->y));
mouseState->buttons[0] = (buttons & SDL_BUTTON(SDL_BUTTON_LEFT)) != 0;
mouseState->buttons[1] = (buttons & SDL_BUTTON(SDL_BUTTON_RIGHT)) != 0;
mouseState->wheelX = gMouseWheelDeltaX;
mouseState->wheelY = gMouseWheelDeltaY;

gMouseWheelDeltaX = 0;
gMouseWheelDeltaY = 0;
}
Uint32 buttons = SDL_GetRelativeMouseState(&(mouseState->x), &(mouseState->y));
mouseState->buttons[0] = (buttons & SDL_BUTTON(SDL_BUTTON_LEFT)) != 0;
mouseState->buttons[1] = (buttons & SDL_BUTTON(SDL_BUTTON_RIGHT)) != 0;
mouseState->wheelX = gMouseWheelDeltaX;
mouseState->wheelY = gMouseWheelDeltaY;

gMouseWheelDeltaX = 0;
gMouseWheelDeltaY = 0;

return true;
}
Expand Down Expand Up @@ -174,70 +118,6 @@ void handleMouseEvent(SDL_Event* event)
gMouseWheelDeltaX += event->wheel.x;
gMouseWheelDeltaY += event->wheel.y;
}

if (gLastInputType != INPUT_TYPE_MOUSE) {
// Reset touch data.
gTouchMouseLastX = 0;
gTouchMouseLastY = 0;
gTouchMouseDeltaX = 0;
gTouchMouseDeltaY = 0;

gTouchFingers = 0;
gTouchGestureLastTouchDownTimestamp = 0;
gTouchGestureLastTouchUpTimestamp = 0;
gTouchGestureTaps = 0;
gTouchGestureHandled = false;

gLastInputType = INPUT_TYPE_MOUSE;
}
}

void handleTouchEvent(SDL_Event* event)
{
int windowWidth = screenGetWidth();
int windowHeight = screenGetHeight();

if (event->tfinger.type == SDL_FINGERDOWN) {
gTouchFingers++;

gTouchMouseLastX = (int)(event->tfinger.x * windowWidth);
gTouchMouseLastY = (int)(event->tfinger.y * windowHeight);
gTouchMouseDeltaX = 0;
gTouchMouseDeltaY = 0;

if (event->tfinger.timestamp - gTouchGestureLastTouchDownTimestamp > 250) {
gTouchGestureTaps = 0;
gTouchGestureHandled = false;
}

gTouchGestureLastTouchDownTimestamp = event->tfinger.timestamp;
} else if (event->tfinger.type == SDL_FINGERMOTION) {
int prevX = gTouchMouseLastX;
int prevY = gTouchMouseLastY;
gTouchMouseLastX = (int)(event->tfinger.x * windowWidth);
gTouchMouseLastY = (int)(event->tfinger.y * windowHeight);
gTouchMouseDeltaX += gTouchMouseLastX - prevX;
gTouchMouseDeltaY += gTouchMouseLastY - prevY;
} else if (event->tfinger.type == SDL_FINGERUP) {
gTouchFingers--;

int prevX = gTouchMouseLastX;
int prevY = gTouchMouseLastY;
gTouchMouseLastX = (int)(event->tfinger.x * windowWidth);
gTouchMouseLastY = (int)(event->tfinger.y * windowHeight);
gTouchMouseDeltaX += gTouchMouseLastX - prevX;
gTouchMouseDeltaY += gTouchMouseLastY - prevY;

gTouchGestureTaps++;
gTouchGestureLastTouchUpTimestamp = event->tfinger.timestamp;
}

if (gLastInputType != INPUT_TYPE_TOUCH) {
// Reset mouse data.
SDL_GetRelativeMouseState(NULL, NULL);

gLastInputType = INPUT_TYPE_TOUCH;
}
}

} // namespace fallout
6 changes: 6 additions & 0 deletions src/game_movie.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "settings.h"
#include "svga.h"
#include "text_font.h"
#include "touch.h"
#include "window_manager.h"

namespace fallout {
Expand Down Expand Up @@ -249,6 +250,11 @@ int gameMoviePlay(int movie, int flags)
break;
}

Gesture gesture;
if (touch_get_gesture(&gesture) && gesture.state == kEnded) {
break;
}

int x;
int y;
_mouse_get_raw_state(&x, &y, &buttons);
Expand Down
9 changes: 8 additions & 1 deletion src/input.cc
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "mouse.h"
#include "svga.h"
#include "text_font.h"
#include "touch.h"
#include "vcr.h"
#include "win32.h"

Expand Down Expand Up @@ -1084,9 +1085,13 @@ void _GNW95_process_message()
handleMouseEvent(&e);
break;
case SDL_FINGERDOWN:
touch_handle_start(&(e.tfinger));
break;
case SDL_FINGERMOTION:
touch_handle_move(&(e.tfinger));
break;
case SDL_FINGERUP:
handleTouchEvent(&e);
touch_handle_end(&(e.tfinger));
break;
case SDL_KEYDOWN:
case SDL_KEYUP:
Expand Down Expand Up @@ -1121,6 +1126,8 @@ void _GNW95_process_message()
}
}

touch_process_gesture();

if (gProgramIsActive && !keyboardIsDisabled()) {
// NOTE: Uninline
int tick = getTicks();
Expand Down
49 changes: 49 additions & 0 deletions src/mouse.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "kb.h"
#include "memory.h"
#include "svga.h"
#include "touch.h"
#include "vcr.h"

namespace fallout {
Expand Down Expand Up @@ -381,6 +382,54 @@ void _mouse_info()
return;
}

Gesture gesture;
if (touch_get_gesture(&gesture)) {
static int prevx;
static int prevy;

switch (gesture.type) {
case kTap:
if (gesture.numberOfTouches == 1) {
_mouse_simulate_input(0, 0, MOUSE_STATE_LEFT_BUTTON_DOWN);
} else if (gesture.numberOfTouches == 2) {
_mouse_simulate_input(0, 0, MOUSE_STATE_RIGHT_BUTTON_DOWN);
}
break;
case kLongPress:
case kPan:
if (gesture.state == kBegan) {
prevx = gesture.x;
prevy = gesture.y;
}

if (gesture.type == kLongPress) {
if (gesture.numberOfTouches == 1) {
_mouse_simulate_input(gesture.x - prevx, gesture.y - prevy, MOUSE_STATE_LEFT_BUTTON_DOWN);
} else if (gesture.numberOfTouches == 2) {
_mouse_simulate_input(gesture.x - prevx, gesture.y - prevy, MOUSE_STATE_RIGHT_BUTTON_DOWN);
}
} else if (gesture.type == kPan) {
if (gesture.numberOfTouches == 1) {
_mouse_simulate_input(gesture.x - prevx, gesture.y - prevy, 0);
} else if (gesture.numberOfTouches == 2) {
gMouseWheelX = (prevx - gesture.x) / 2;
gMouseWheelY = (gesture.y - prevy) / 2;

if (gMouseWheelX != 0 || gMouseWheelY != 0) {
gMouseEvent |= MOUSE_EVENT_WHEEL;
_raw_buttons |= MOUSE_EVENT_WHEEL;
}
}
}

prevx = gesture.x;
prevy = gesture.y;
break;
}

return;
}

int x;
int y;
int buttons = 0;
Expand Down
Loading

0 comments on commit a06097a

Please sign in to comment.