mirror of
https://github.com/mauiaaron/apple2.git
synced 2024-12-29 04:29:32 +00:00
Move tap delay to joystick variant
- Keypad variant already has a key repeat threshold - Improved variant touch lifecycle naming
This commit is contained in:
parent
f046af0bef
commit
287df44133
@ -15,13 +15,6 @@
|
|||||||
#error this is a touch interface module, possibly you mean to not compile this at all?
|
#error this is a touch interface module, possibly you mean to not compile this at all?
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define DEBUG_TOUCH_JOY 0
|
|
||||||
#if DEBUG_TOUCH_JOY
|
|
||||||
# define TOUCH_JOY_LOG(...) LOG(__VA_ARGS__)
|
|
||||||
#else
|
|
||||||
# define TOUCH_JOY_LOG(...)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define MODEL_DEPTH -1/32.f
|
#define MODEL_DEPTH -1/32.f
|
||||||
#define TRACKING_NONE (-1)
|
#define TRACKING_NONE (-1)
|
||||||
|
|
||||||
@ -48,7 +41,6 @@
|
|||||||
#define BUTTON_OBJ_HALF_H (BUTTON_OBJ_H/2.f)
|
#define BUTTON_OBJ_HALF_H (BUTTON_OBJ_H/2.f)
|
||||||
|
|
||||||
#define BUTTON_SWITCH_THRESHOLD_DEFAULT 22
|
#define BUTTON_SWITCH_THRESHOLD_DEFAULT 22
|
||||||
#define BUTTON_TAP_DELAY_NANOS_DEFAULT 50000000
|
|
||||||
|
|
||||||
GLTouchJoyGlobals joyglobals = { 0 };
|
GLTouchJoyGlobals joyglobals = { 0 };
|
||||||
GLTouchJoyAxes axes = { 0 };
|
GLTouchJoyAxes axes = { 0 };
|
||||||
@ -199,76 +191,6 @@ static inline void _setup_button_object_with_char(char newChar) {
|
|||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
// Tap Delay Thread : delays processing of touch-down so that a different joystick button/key can be fired
|
|
||||||
|
|
||||||
static inline void _signal_tap_delay(void) {
|
|
||||||
pthread_mutex_lock(&buttons.tapDelayMutex);
|
|
||||||
pthread_cond_signal(&buttons.tapDelayCond);
|
|
||||||
pthread_mutex_unlock(&buttons.tapDelayMutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *_button_tap_delayed_thread(void *dummyptr) {
|
|
||||||
LOG(">>> [DELAYEDTAP] thread start ...");
|
|
||||||
|
|
||||||
pthread_mutex_lock(&buttons.tapDelayMutex);
|
|
||||||
|
|
||||||
do {
|
|
||||||
pthread_cond_wait(&buttons.tapDelayCond, &buttons.tapDelayMutex);
|
|
||||||
TOUCH_JOY_LOG(">>> [DELAYEDTAP] begin ...");
|
|
||||||
|
|
||||||
if (UNLIKELY(joyglobals.isShuttingDown)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct timespec ts = { .tv_sec=0, .tv_nsec=buttons.tapDelayNanos };
|
|
||||||
|
|
||||||
// sleep for the configured delay time
|
|
||||||
pthread_mutex_unlock(&buttons.tapDelayMutex);
|
|
||||||
nanosleep(&ts, NULL);
|
|
||||||
pthread_mutex_lock(&buttons.tapDelayMutex);
|
|
||||||
|
|
||||||
// wait until touch up/cancel
|
|
||||||
do {
|
|
||||||
|
|
||||||
// now set the emulator's joystick button values (or keypad value)
|
|
||||||
uint8_t displayChar = variant.curr->buttonPress();
|
|
||||||
_setup_button_object_with_char(displayChar);
|
|
||||||
|
|
||||||
if ( (buttons.trackingIndex == TRACKING_NONE) || joyglobals.isShuttingDown) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_cond_wait(&buttons.tapDelayCond, &buttons.tapDelayMutex);
|
|
||||||
|
|
||||||
if ( (buttons.trackingIndex == TRACKING_NONE) || joyglobals.isShuttingDown) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
TOUCH_JOY_LOG(">>> [DELAYEDTAP] looping ...");
|
|
||||||
} while (1);
|
|
||||||
|
|
||||||
if (UNLIKELY(joyglobals.isShuttingDown)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// delay the ending of button tap or touch/move event by the configured delay time
|
|
||||||
pthread_mutex_unlock(&buttons.tapDelayMutex);
|
|
||||||
nanosleep(&ts, NULL);
|
|
||||||
pthread_mutex_lock(&buttons.tapDelayMutex);
|
|
||||||
|
|
||||||
variant.curr->buttonRelease();
|
|
||||||
|
|
||||||
TOUCH_JOY_LOG(">>> [DELAYEDTAP] end ...");
|
|
||||||
} while (1);
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&buttons.tapDelayMutex);
|
|
||||||
|
|
||||||
LOG(">>> [DELAYEDTAP] thread exit ...");
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
static inline void resetState() {
|
static inline void resetState() {
|
||||||
LOG("%s", "");
|
LOG("%s", "");
|
||||||
axes.trackingIndex = TRACKING_NONE;
|
axes.trackingIndex = TRACKING_NONE;
|
||||||
@ -286,8 +208,6 @@ static void gltouchjoy_setup(void) {
|
|||||||
mdlDestroyModel(&buttons.model);
|
mdlDestroyModel(&buttons.model);
|
||||||
|
|
||||||
joyglobals.isShuttingDown = false;
|
joyglobals.isShuttingDown = false;
|
||||||
assert((buttons.tapDelayThreadId == 0) && "setup called multiple times!");
|
|
||||||
pthread_create(&buttons.tapDelayThreadId, NULL, (void *)&_button_tap_delayed_thread, (void *)NULL);
|
|
||||||
|
|
||||||
axes.model = mdlCreateQuad(-1.05, -1.0, AXIS_OBJ_W, AXIS_OBJ_H, MODEL_DEPTH, AXIS_FB_WIDTH, AXIS_FB_HEIGHT, (GLCustom){
|
axes.model = mdlCreateQuad(-1.05, -1.0, AXIS_OBJ_W, AXIS_OBJ_H, MODEL_DEPTH, AXIS_FB_WIDTH, AXIS_FB_HEIGHT, (GLCustom){
|
||||||
.create = &_create_touchjoy_hud,
|
.create = &_create_touchjoy_hud,
|
||||||
@ -319,6 +239,9 @@ static void gltouchjoy_setup(void) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
variant.joys->setup(&_setup_button_object_with_char);
|
||||||
|
variant.kpad->setup(&_setup_button_object_with_char);
|
||||||
|
|
||||||
struct timespec now;
|
struct timespec now;
|
||||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||||
axes.timingBegin = now;
|
axes.timingBegin = now;
|
||||||
@ -336,15 +259,10 @@ static void gltouchjoy_shutdown(void) {
|
|||||||
resetState();
|
resetState();
|
||||||
|
|
||||||
joyglobals.isAvailable = false;
|
joyglobals.isAvailable = false;
|
||||||
|
|
||||||
joyglobals.isShuttingDown = true;
|
joyglobals.isShuttingDown = true;
|
||||||
pthread_cond_signal(&buttons.tapDelayCond);
|
|
||||||
if (pthread_join(buttons.tapDelayThreadId, NULL)) {
|
variant.joys->shutdown();
|
||||||
ERRLOG("OOPS: pthread_join tap delay thread ...");
|
variant.kpad->shutdown();
|
||||||
}
|
|
||||||
buttons.tapDelayThreadId = 0;
|
|
||||||
buttons.tapDelayMutex = (pthread_mutex_t){ 0 };
|
|
||||||
buttons.tapDelayCond = (pthread_cond_t)PTHREAD_COND_INITIALIZER;
|
|
||||||
|
|
||||||
mdlDestroyModel(&axes.model);
|
mdlDestroyModel(&axes.model);
|
||||||
mdlDestroyModel(&buttons.model);
|
mdlDestroyModel(&buttons.model);
|
||||||
@ -495,9 +413,6 @@ static inline void _axis_touch_down(int x, int y) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline void _button_touch_down(int x, int y) {
|
static inline void _button_touch_down(int x, int y) {
|
||||||
variant.curr->setCurrButtonValue(buttons.touchDownChar, buttons.touchDownScancode);
|
|
||||||
_signal_tap_delay();
|
|
||||||
|
|
||||||
buttons.centerX = x;
|
buttons.centerX = x;
|
||||||
buttons.centerY = y;
|
buttons.centerY = y;
|
||||||
|
|
||||||
@ -505,11 +420,12 @@ static inline void _button_touch_down(int x, int y) {
|
|||||||
buttons.modelDirty = true;
|
buttons.modelDirty = true;
|
||||||
|
|
||||||
TOUCH_JOY_LOG("---TOUCH %sDOWN (buttons index %d) center:(%d,%d) -> buttons(0x%02X,0x%02X)", (action == TOUCH_DOWN ? "" : "POINTER "), buttons.trackingIndex, buttons.centerX, buttons.centerY, joy_button0, joy_button1);
|
TOUCH_JOY_LOG("---TOUCH %sDOWN (buttons index %d) center:(%d,%d) -> buttons(0x%02X,0x%02X)", (action == TOUCH_DOWN ? "" : "POINTER "), buttons.trackingIndex, buttons.centerX, buttons.centerY, joy_button0, joy_button1);
|
||||||
|
variant.curr->buttonDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void _axis_move(int x, int y) {
|
static inline void _axis_move(int x, int y) {
|
||||||
x = (x - axes.centerX);
|
x -= axes.centerX;
|
||||||
y = (y - axes.centerY);
|
y -= axes.centerY;
|
||||||
TOUCH_JOY_LOG("---TOUCH MOVE ...tracking axis:%d (%d,%d) -> joy(0x%02X,0x%02X)", axes.trackingIndex, x, y, joy_x, joy_y);
|
TOUCH_JOY_LOG("---TOUCH MOVE ...tracking axis:%d (%d,%d) -> joy(0x%02X,0x%02X)", axes.trackingIndex, x, y, joy_x, joy_y);
|
||||||
variant.curr->axisMove(x, y);
|
variant.curr->axisMove(x, y);
|
||||||
}
|
}
|
||||||
@ -517,21 +433,8 @@ static inline void _axis_move(int x, int y) {
|
|||||||
static inline void _button_move(int x, int y) {
|
static inline void _button_move(int x, int y) {
|
||||||
x -= buttons.centerX;
|
x -= buttons.centerX;
|
||||||
y -= buttons.centerY;
|
y -= buttons.centerY;
|
||||||
if ((y < -joyglobals.switchThreshold) || (y > joyglobals.switchThreshold)) {
|
TOUCH_JOY_LOG("+++TOUCH MOVE ...tracking button:%d (%d,%d) -> buttons(0x%02X,0x%02X)", buttons.trackingIndex, x, y, joy_button0, joy_button1);
|
||||||
touchjoy_button_type_t theButtonChar = -1;
|
variant.curr->buttonMove(x, y);
|
||||||
int theButtonScancode = -1;
|
|
||||||
if (y < 0) {
|
|
||||||
theButtonChar = buttons.northChar;
|
|
||||||
theButtonScancode = buttons.northScancode;
|
|
||||||
} else {
|
|
||||||
theButtonChar = buttons.southChar;
|
|
||||||
theButtonScancode = buttons.southScancode;
|
|
||||||
}
|
|
||||||
|
|
||||||
variant.curr->setCurrButtonValue(theButtonChar, theButtonScancode);
|
|
||||||
_signal_tap_delay();
|
|
||||||
TOUCH_JOY_LOG("+++TOUCH MOVE ...tracking button:%d (%d,%d) -> buttons(0x%02X,0x%02X)", buttons.trackingIndex, x, y, joy_button0, joy_button1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void _axis_touch_up(int x, int y) {
|
static inline void _axis_touch_up(int x, int y) {
|
||||||
@ -544,8 +447,8 @@ static inline void _axis_touch_up(int x, int y) {
|
|||||||
TOUCH_JOY_LOG("---TOUCH %sUP (axis went up)%s", (action == TOUCH_UP ? "" : "POINTER "), (resetIndex ? " (reset buttons index!)" : ""));
|
TOUCH_JOY_LOG("---TOUCH %sUP (axis went up)%s", (action == TOUCH_UP ? "" : "POINTER "), (resetIndex ? " (reset buttons index!)" : ""));
|
||||||
#endif
|
#endif
|
||||||
LOG("%s", "");
|
LOG("%s", "");
|
||||||
x = (x - axes.centerX);
|
x -= axes.centerX;
|
||||||
y = (y - axes.centerY);
|
y -= axes.centerY;
|
||||||
if (buttons.trackingIndex > axes.trackingIndex) {
|
if (buttons.trackingIndex > axes.trackingIndex) {
|
||||||
LOG("!!! : DECREMENTING buttons.trackingIndex");
|
LOG("!!! : DECREMENTING buttons.trackingIndex");
|
||||||
--buttons.trackingIndex;
|
--buttons.trackingIndex;
|
||||||
@ -554,7 +457,7 @@ static inline void _axis_touch_up(int x, int y) {
|
|||||||
axes.trackingIndex = TRACKING_NONE;
|
axes.trackingIndex = TRACKING_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void _button_touch_up(void) {
|
static inline void _button_touch_up(int x, int y) {
|
||||||
#if DEBUG_TOUCH_JOY
|
#if DEBUG_TOUCH_JOY
|
||||||
bool resetIndex = false;
|
bool resetIndex = false;
|
||||||
if (axes.trackingIndex > buttons.trackingIndex) {
|
if (axes.trackingIndex > buttons.trackingIndex) {
|
||||||
@ -564,12 +467,14 @@ static inline void _button_touch_up(void) {
|
|||||||
TOUCH_JOY_LOG("---TOUCH %sUP (buttons went up)%s", (action == TOUCH_UP ? "" : "POINTER "), (resetIndex ? " (reset axis index!)" : ""));
|
TOUCH_JOY_LOG("---TOUCH %sUP (buttons went up)%s", (action == TOUCH_UP ? "" : "POINTER "), (resetIndex ? " (reset axis index!)" : ""));
|
||||||
#endif
|
#endif
|
||||||
LOG("%s", "");
|
LOG("%s", "");
|
||||||
|
x -= buttons.centerX;
|
||||||
|
y -= buttons.centerY;
|
||||||
if (axes.trackingIndex > buttons.trackingIndex) {
|
if (axes.trackingIndex > buttons.trackingIndex) {
|
||||||
LOG("!!! : DECREMENTING axes.trackingIndex");
|
LOG("!!! : DECREMENTING axes.trackingIndex");
|
||||||
--axes.trackingIndex;
|
--axes.trackingIndex;
|
||||||
}
|
}
|
||||||
|
variant.curr->buttonUp(x, y);
|
||||||
buttons.trackingIndex = TRACKING_NONE;
|
buttons.trackingIndex = TRACKING_NONE;
|
||||||
_signal_tap_delay();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -648,7 +553,9 @@ static int64_t gltouchjoy_onTouchEvent(interface_touch_event_t action, int point
|
|||||||
int y = (int)y_coords[axes.trackingIndex];
|
int y = (int)y_coords[axes.trackingIndex];
|
||||||
_axis_touch_up(x, y);
|
_axis_touch_up(x, y);
|
||||||
} else if (pointer_idx == buttons.trackingIndex) {
|
} else if (pointer_idx == buttons.trackingIndex) {
|
||||||
_button_touch_up();
|
int x = (int)x_coords[buttons.trackingIndex];
|
||||||
|
int y = (int)y_coords[buttons.trackingIndex];
|
||||||
|
_button_touch_up(x, y);
|
||||||
} else {
|
} else {
|
||||||
if (pointer_count == 1) {
|
if (pointer_count == 1) {
|
||||||
LOG("!!! : RESETTING TOUCH JOYSTICK STATE MACHINE");
|
LOG("!!! : RESETTING TOUCH JOYSTICK STATE MACHINE");
|
||||||
@ -764,16 +671,6 @@ static void gltouchjoy_setTouchButtonTypes(
|
|||||||
_setup_button_object_with_char(currButtonDisplayChar);
|
_setup_button_object_with_char(currButtonDisplayChar);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gltouchjoy_setTapDelay(float secs) {
|
|
||||||
if (UNLIKELY(secs < 0.f)) {
|
|
||||||
ERRLOG("Clamping tap delay to 0.0 secs");
|
|
||||||
}
|
|
||||||
if (UNLIKELY(secs > 1.f)) {
|
|
||||||
ERRLOG("Clamping tap delay to 1.0 secs");
|
|
||||||
}
|
|
||||||
buttons.tapDelayNanos = (unsigned int)((float)NANOSECONDS_PER_SECOND * secs);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void gltouchjoy_setTouchAxisSensitivity(float multiplier) {
|
static void gltouchjoy_setTouchAxisSensitivity(float multiplier) {
|
||||||
axes.multiplier = multiplier;
|
axes.multiplier = multiplier;
|
||||||
}
|
}
|
||||||
@ -883,11 +780,6 @@ static void _init_gltouchjoy(void) {
|
|||||||
|
|
||||||
buttons.activeChar = MOUSETEXT_OPENAPPLE;
|
buttons.activeChar = MOUSETEXT_OPENAPPLE;
|
||||||
|
|
||||||
buttons.tapDelayThreadId = 0;
|
|
||||||
buttons.tapDelayMutex = (pthread_mutex_t){ 0 };
|
|
||||||
buttons.tapDelayCond = (pthread_cond_t)PTHREAD_COND_INITIALIZER;
|
|
||||||
buttons.tapDelayNanos = BUTTON_TAP_DELAY_NANOS_DEFAULT;
|
|
||||||
|
|
||||||
joyglobals.isEnabled = true;
|
joyglobals.isEnabled = true;
|
||||||
joyglobals.ownsScreen = true;
|
joyglobals.ownsScreen = true;
|
||||||
joyglobals.showControls = true;
|
joyglobals.showControls = true;
|
||||||
@ -904,7 +796,6 @@ static void _init_gltouchjoy(void) {
|
|||||||
joydriver_ownsScreen = &gltouchjoy_ownsScreen;
|
joydriver_ownsScreen = &gltouchjoy_ownsScreen;
|
||||||
joydriver_setShowControls = &gltouchjoy_setShowControls;
|
joydriver_setShowControls = &gltouchjoy_setShowControls;
|
||||||
joydriver_setTouchButtonTypes = &gltouchjoy_setTouchButtonTypes;
|
joydriver_setTouchButtonTypes = &gltouchjoy_setTouchButtonTypes;
|
||||||
joydriver_setTapDelay = &gltouchjoy_setTapDelay;
|
|
||||||
joydriver_setTouchAxisSensitivity = &gltouchjoy_setTouchAxisSensitivity;
|
joydriver_setTouchAxisSensitivity = &gltouchjoy_setTouchAxisSensitivity;
|
||||||
joydriver_setButtonSwitchThreshold = &gltouchjoy_setButtonSwitchThreshold;
|
joydriver_setButtonSwitchThreshold = &gltouchjoy_setButtonSwitchThreshold;
|
||||||
joydriver_setTouchVariant = &gltouchjoy_setTouchVariant;
|
joydriver_setTouchVariant = &gltouchjoy_setTouchVariant;
|
||||||
|
@ -17,6 +17,13 @@
|
|||||||
#include "video/glhudmodel.h"
|
#include "video/glhudmodel.h"
|
||||||
#include "video/glnode.h"
|
#include "video/glnode.h"
|
||||||
|
|
||||||
|
#define DEBUG_TOUCH_JOY 0
|
||||||
|
#if DEBUG_TOUCH_JOY
|
||||||
|
# define TOUCH_JOY_LOG(...) LOG(__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
# define TOUCH_JOY_LOG(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
// globals
|
// globals
|
||||||
|
|
||||||
typedef struct GLTouchJoyGlobals {
|
typedef struct GLTouchJoyGlobals {
|
||||||
@ -75,23 +82,23 @@ typedef struct GLTouchJoyButtons {
|
|||||||
int trackingIndex;
|
int trackingIndex;
|
||||||
struct timespec timingBegin;
|
struct timespec timingBegin;
|
||||||
|
|
||||||
pthread_t tapDelayThreadId;
|
|
||||||
pthread_mutex_t tapDelayMutex;
|
|
||||||
pthread_cond_t tapDelayCond;
|
|
||||||
unsigned int tapDelayNanos;
|
|
||||||
|
|
||||||
} GLTouchJoyButtons;
|
} GLTouchJoyButtons;
|
||||||
extern GLTouchJoyButtons buttons;
|
extern GLTouchJoyButtons buttons;
|
||||||
|
|
||||||
typedef struct GLTouchJoyVariant {
|
typedef struct GLTouchJoyVariant {
|
||||||
touchjoy_variant_t (*variant)(void);
|
touchjoy_variant_t (*variant)(void);
|
||||||
void (*resetState)(void);
|
void (*resetState)(void);
|
||||||
void (*setCurrButtonValue)(touchjoy_button_type_t theButtonChar, int theButtonScancode);
|
void (*setup)(void (*buttonDrawCallback)(char newChar));
|
||||||
uint8_t (*buttonPress)(void);
|
void (*shutdown)(void);
|
||||||
void (*buttonRelease)(void);
|
|
||||||
void (*axisDown)(void);
|
void (*buttonDown)(void);
|
||||||
void (*axisMove)(int dx, int dy);
|
void (*buttonMove)(int dx, int dy);
|
||||||
void (*axisUp)(int dx, int dy);
|
void (*buttonUp)(int dx, int dy);
|
||||||
|
|
||||||
|
void (*axisDown)(void);
|
||||||
|
void (*axisMove)(int dx, int dy);
|
||||||
|
void (*axisUp)(int dx, int dy);
|
||||||
|
|
||||||
} GLTouchJoyVariant;
|
} GLTouchJoyVariant;
|
||||||
|
|
||||||
// registers a touch joystick variant with manager
|
// registers a touch joystick variant with manager
|
||||||
|
@ -15,14 +15,25 @@
|
|||||||
#error this is a touch interface module, possibly you mean to not compile this at all?
|
#error this is a touch interface module, possibly you mean to not compile this at all?
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define BUTTON_TAP_DELAY_NANOS_DEFAULT 50000000
|
||||||
|
|
||||||
static GLTouchJoyVariant happyHappyJoyJoy = { 0 };
|
static GLTouchJoyVariant happyHappyJoyJoy = { 0 };
|
||||||
|
|
||||||
static struct {
|
static struct {
|
||||||
uint8_t currJoyButtonValue0;
|
uint8_t currJoyButtonValue0;
|
||||||
uint8_t currJoyButtonValue1;
|
uint8_t currJoyButtonValue1;
|
||||||
uint8_t currButtonDisplayChar;
|
uint8_t currButtonDisplayChar;
|
||||||
|
void (*buttonDrawCallback)(char newChar);
|
||||||
|
|
||||||
|
bool trackingButton;
|
||||||
|
pthread_t tapDelayThreadId;
|
||||||
|
pthread_mutex_t tapDelayMutex;
|
||||||
|
pthread_cond_t tapDelayCond;
|
||||||
|
unsigned int tapDelayNanos;
|
||||||
} joys;
|
} joys;
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
static touchjoy_variant_t touchjoy_variant(void) {
|
static touchjoy_variant_t touchjoy_variant(void) {
|
||||||
return EMULATED_JOYSTICK;
|
return EMULATED_JOYSTICK;
|
||||||
}
|
}
|
||||||
@ -45,6 +56,93 @@ static void touchjoy_resetState(void) {
|
|||||||
_reset_buttons_state();
|
_reset_buttons_state();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Tap Delay Thread : delays processing of touch-down so that a different joystick button can be fired
|
||||||
|
|
||||||
|
static inline void _signal_tap_delay(void) {
|
||||||
|
pthread_mutex_lock(&joys.tapDelayMutex);
|
||||||
|
pthread_cond_signal(&joys.tapDelayCond);
|
||||||
|
pthread_mutex_unlock(&joys.tapDelayMutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *_button_tap_delayed_thread(void *dummyptr) {
|
||||||
|
LOG(">>> [DELAYEDTAP] thread start ...");
|
||||||
|
|
||||||
|
pthread_mutex_lock(&joys.tapDelayMutex);
|
||||||
|
|
||||||
|
do {
|
||||||
|
pthread_cond_wait(&joys.tapDelayCond, &joys.tapDelayMutex);
|
||||||
|
TOUCH_JOY_LOG(">>> [DELAYEDTAP] begin ...");
|
||||||
|
|
||||||
|
if (UNLIKELY(joyglobals.isShuttingDown)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct timespec ts = { .tv_sec=0, .tv_nsec=joys.tapDelayNanos };
|
||||||
|
|
||||||
|
// sleep for the configured delay time
|
||||||
|
pthread_mutex_unlock(&joys.tapDelayMutex);
|
||||||
|
nanosleep(&ts, NULL);
|
||||||
|
pthread_mutex_lock(&joys.tapDelayMutex);
|
||||||
|
|
||||||
|
// wait until touch up/cancel
|
||||||
|
do {
|
||||||
|
|
||||||
|
// now set the joystick button values
|
||||||
|
joy_button0 = joys.currJoyButtonValue0;
|
||||||
|
joy_button1 = joys.currJoyButtonValue1;
|
||||||
|
joys.buttonDrawCallback(joys.currButtonDisplayChar);
|
||||||
|
|
||||||
|
if (!joys.trackingButton || joyglobals.isShuttingDown) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_cond_wait(&joys.tapDelayCond, &joys.tapDelayMutex);
|
||||||
|
|
||||||
|
if (!joys.trackingButton || joyglobals.isShuttingDown) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
TOUCH_JOY_LOG(">>> [DELAYEDTAP] looping ...");
|
||||||
|
} while (1);
|
||||||
|
|
||||||
|
if (UNLIKELY(joyglobals.isShuttingDown)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// delay the ending of button tap or touch/move event by the configured delay time
|
||||||
|
pthread_mutex_unlock(&joys.tapDelayMutex);
|
||||||
|
nanosleep(&ts, NULL);
|
||||||
|
pthread_mutex_lock(&joys.tapDelayMutex);
|
||||||
|
|
||||||
|
_reset_buttons_state();
|
||||||
|
|
||||||
|
TOUCH_JOY_LOG(">>> [DELAYEDTAP] end ...");
|
||||||
|
} while (1);
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&joys.tapDelayMutex);
|
||||||
|
|
||||||
|
LOG(">>> [DELAYEDTAP] thread exit ...");
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void touchjoy_setup(void (*buttonDrawCallback)(char newChar)) {
|
||||||
|
assert((joys.tapDelayThreadId == 0) && "setup called multiple times!");
|
||||||
|
joys.buttonDrawCallback = buttonDrawCallback;
|
||||||
|
pthread_create(&joys.tapDelayThreadId, NULL, (void *)&_button_tap_delayed_thread, (void *)NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void touchjoy_shutdown(void) {
|
||||||
|
pthread_cond_signal(&joys.tapDelayCond);
|
||||||
|
if (pthread_join(joys.tapDelayThreadId, NULL)) {
|
||||||
|
ERRLOG("OOPS: pthread_join tap delay thread ...");
|
||||||
|
}
|
||||||
|
joys.tapDelayThreadId = 0;
|
||||||
|
joys.tapDelayMutex = (pthread_mutex_t){ 0 };
|
||||||
|
joys.tapDelayCond = (pthread_cond_t)PTHREAD_COND_INITIALIZER;
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// axis state
|
// axis state
|
||||||
|
|
||||||
@ -85,7 +183,7 @@ static void touchjoy_axisUp(int x, int y) {
|
|||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// button state
|
// button state
|
||||||
|
|
||||||
static void touchjoy_setCurrButtonValue(touchjoy_button_type_t theButtonChar, int theButtonScancode) {
|
static void _set_current_button_state(touchjoy_button_type_t theButtonChar, int theButtonScancode) {
|
||||||
if (theButtonChar == TOUCH_BUTTON0) {
|
if (theButtonChar == TOUCH_BUTTON0) {
|
||||||
joys.currJoyButtonValue0 = 0x80;
|
joys.currJoyButtonValue0 = 0x80;
|
||||||
joys.currJoyButtonValue1 = 0;
|
joys.currJoyButtonValue1 = 0;
|
||||||
@ -105,14 +203,42 @@ static void touchjoy_setCurrButtonValue(touchjoy_button_type_t theButtonChar, in
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t touchjoy_buttonPress(void) {
|
static void touchjoy_buttonDown(void) {
|
||||||
joy_button0 = joys.currJoyButtonValue0;
|
_set_current_button_state(buttons.touchDownChar, buttons.touchDownScancode);
|
||||||
joy_button1 = joys.currJoyButtonValue1;
|
joys.trackingButton = true;
|
||||||
return joys.currButtonDisplayChar;
|
_signal_tap_delay();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void touchjoy_buttonRelease(void) {
|
static void touchjoy_buttonMove(int dx, int dy) {
|
||||||
_reset_buttons_state();
|
if ((dy < -joyglobals.switchThreshold) || (dy > joyglobals.switchThreshold)) {
|
||||||
|
touchjoy_button_type_t theButtonChar = -1;
|
||||||
|
int theButtonScancode = -1;
|
||||||
|
if (dy < 0) {
|
||||||
|
theButtonChar = buttons.northChar;
|
||||||
|
theButtonScancode = buttons.northScancode;
|
||||||
|
} else {
|
||||||
|
theButtonChar = buttons.southChar;
|
||||||
|
theButtonScancode = buttons.southScancode;
|
||||||
|
}
|
||||||
|
|
||||||
|
_set_current_button_state(theButtonChar, theButtonScancode);
|
||||||
|
_signal_tap_delay();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void touchjoy_buttonUp(int dx, int dy) {
|
||||||
|
joys.trackingButton = false;
|
||||||
|
_signal_tap_delay();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gltouchjoy_setTapDelay(float secs) {
|
||||||
|
if (UNLIKELY(secs < 0.f)) {
|
||||||
|
ERRLOG("Clamping tap delay to 0.0 secs");
|
||||||
|
}
|
||||||
|
if (UNLIKELY(secs > 1.f)) {
|
||||||
|
ERRLOG("Clamping tap delay to 1.0 secs");
|
||||||
|
}
|
||||||
|
joys.tapDelayNanos = (unsigned int)((float)NANOSECONDS_PER_SECOND * secs);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
@ -123,15 +249,23 @@ static void _init_gltouchjoy_joy(void) {
|
|||||||
|
|
||||||
happyHappyJoyJoy.variant = &touchjoy_variant,
|
happyHappyJoyJoy.variant = &touchjoy_variant,
|
||||||
happyHappyJoyJoy.resetState = &touchjoy_resetState,
|
happyHappyJoyJoy.resetState = &touchjoy_resetState,
|
||||||
|
happyHappyJoyJoy.setup = &touchjoy_setup,
|
||||||
|
happyHappyJoyJoy.shutdown = &touchjoy_shutdown,
|
||||||
|
|
||||||
happyHappyJoyJoy.setCurrButtonValue = &touchjoy_setCurrButtonValue,
|
happyHappyJoyJoy.buttonDown = &touchjoy_buttonDown,
|
||||||
happyHappyJoyJoy.buttonPress = &touchjoy_buttonPress,
|
happyHappyJoyJoy.buttonMove = &touchjoy_buttonMove,
|
||||||
happyHappyJoyJoy.buttonRelease = &touchjoy_buttonRelease,
|
happyHappyJoyJoy.buttonUp = &touchjoy_buttonUp,
|
||||||
|
|
||||||
happyHappyJoyJoy.axisDown = &touchjoy_axisDown,
|
happyHappyJoyJoy.axisDown = &touchjoy_axisDown,
|
||||||
happyHappyJoyJoy.axisMove = &touchjoy_axisMove,
|
happyHappyJoyJoy.axisMove = &touchjoy_axisMove,
|
||||||
happyHappyJoyJoy.axisUp = &touchjoy_axisUp,
|
happyHappyJoyJoy.axisUp = &touchjoy_axisUp,
|
||||||
|
|
||||||
|
joys.tapDelayMutex = (pthread_mutex_t){ 0 };
|
||||||
|
joys.tapDelayCond = (pthread_cond_t)PTHREAD_COND_INITIALIZER;
|
||||||
|
joys.tapDelayNanos = BUTTON_TAP_DELAY_NANOS_DEFAULT;
|
||||||
|
|
||||||
|
joydriver_setTapDelay = &gltouchjoy_setTapDelay;
|
||||||
|
|
||||||
gltouchjoy_registerVariant(EMULATED_JOYSTICK, &happyHappyJoyJoy);
|
gltouchjoy_registerVariant(EMULATED_JOYSTICK, &happyHappyJoyJoy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,6 +50,7 @@ static struct {
|
|||||||
keypad_octant_t axisCurrentOctant;
|
keypad_octant_t axisCurrentOctant;
|
||||||
|
|
||||||
uint8_t currButtonDisplayChar;
|
uint8_t currButtonDisplayChar;
|
||||||
|
void (*buttonDrawCallback)(char newChar);
|
||||||
|
|
||||||
// index of repeating scancodes to fire
|
// index of repeating scancodes to fire
|
||||||
keypad_fire_t fireIdx;
|
keypad_fire_t fireIdx;
|
||||||
@ -162,6 +163,10 @@ static void touchkpad_keyboardReadCallback(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (fired == REPEAT_BUTTON) {
|
||||||
|
kpad.buttonDrawCallback(kpad.currButtonDisplayChar);
|
||||||
|
}
|
||||||
|
|
||||||
bool lockedAxis = _callback_sourceTryLock(&kpad.axisLock);
|
bool lockedAxis = _callback_sourceTryLock(&kpad.axisLock);
|
||||||
if (lockedAxis) {
|
if (lockedAxis) {
|
||||||
if (fired == REPEAT_AXIS || fired == REPEAT_AXIS_ALT) {
|
if (fired == REPEAT_AXIS || fired == REPEAT_AXIS_ALT) {
|
||||||
@ -227,6 +232,14 @@ static void touchkpad_resetState(void) {
|
|||||||
c_keys_handle_input(buttons.southScancode, /*pressed:*/false, /*ASCII:*/false);
|
c_keys_handle_input(buttons.southScancode, /*pressed:*/false, /*ASCII:*/false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void touchkpad_setup(void (*buttonDrawCallback)(char newChar)) {
|
||||||
|
kpad.buttonDrawCallback = buttonDrawCallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void touchkpad_shutdown(void) {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// axis key(s) state
|
// axis key(s) state
|
||||||
|
|
||||||
@ -465,7 +478,7 @@ static void touchkpad_axisUp(int dx, int dy) {
|
|||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// button key state
|
// button key state
|
||||||
|
|
||||||
static void touchkpad_setCurrButtonValue(touchjoy_button_type_t theButtonChar, int theButtonScancode) {
|
static void _set_current_button_state(touchjoy_button_type_t theButtonChar, int theButtonScancode) {
|
||||||
LOG("%s", "");
|
LOG("%s", "");
|
||||||
if (theButtonChar >= 0) {
|
if (theButtonChar >= 0) {
|
||||||
kpad.currButtonDisplayChar = theButtonChar;
|
kpad.currButtonDisplayChar = theButtonChar;
|
||||||
@ -476,23 +489,40 @@ static void touchkpad_setCurrButtonValue(touchjoy_button_type_t theButtonChar, i
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t touchkpad_buttonPress(void) {
|
static void touchkpad_buttonDown(void) {
|
||||||
LOG("%s", "");
|
|
||||||
if (!kpad.buttonBegan) {
|
if (!kpad.buttonBegan) {
|
||||||
// avoid multiple locks on extra buttonPress()
|
|
||||||
kpad.buttonBegan = true;
|
kpad.buttonBegan = true;
|
||||||
_touch_sourceBegin(&kpad.buttonLock);
|
_touch_sourceBegin(&kpad.buttonLock);
|
||||||
}
|
}
|
||||||
|
_set_current_button_state(buttons.touchDownChar, buttons.touchDownScancode);
|
||||||
if (kpad.scancodes[REPEAT_BUTTON] >= 0) {
|
if (kpad.scancodes[REPEAT_BUTTON] >= 0) {
|
||||||
LOG("->BUTT : %d/'%c'", kpad.scancodes[REPEAT_BUTTON], kpad.currButtonDisplayChar);
|
LOG("->BUTT : %d/'%c'", kpad.scancodes[REPEAT_BUTTON], kpad.currButtonDisplayChar);
|
||||||
clock_gettime(CLOCK_MONOTONIC, &kpad.timingBegins[REPEAT_BUTTON]);
|
clock_gettime(CLOCK_MONOTONIC, &kpad.timingBegins[REPEAT_BUTTON]);
|
||||||
keydriver_keyboardReadCallback = &touchkpad_keyboardReadCallback;
|
keydriver_keyboardReadCallback = &touchkpad_keyboardReadCallback;
|
||||||
}
|
}
|
||||||
return kpad.currButtonDisplayChar;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void touchkpad_buttonRelease(void) {
|
static void touchkpad_buttonMove(int dx, int dy) {
|
||||||
|
// Currently this is the same logic as the "regular" joystick variant ... but we could likely be more creative here
|
||||||
|
// in a future revision, like having a full octant of key possibilities ... (for example, playing Bolo with a friend
|
||||||
|
// on the same tablet, one driving, the other shooting and controlling the turret)
|
||||||
|
if ((dy < -joyglobals.switchThreshold) || (dy > joyglobals.switchThreshold)) {
|
||||||
|
touchjoy_button_type_t theButtonChar = -1;
|
||||||
|
int theButtonScancode = -1;
|
||||||
|
if (dy < 0) {
|
||||||
|
theButtonChar = buttons.northChar;
|
||||||
|
theButtonScancode = buttons.northScancode;
|
||||||
|
} else {
|
||||||
|
theButtonChar = buttons.southChar;
|
||||||
|
theButtonScancode = buttons.southScancode;
|
||||||
|
}
|
||||||
|
_set_current_button_state(theButtonChar, theButtonScancode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void touchkpad_buttonUp(int dx, int dy) {
|
||||||
LOG("%s", "");
|
LOG("%s", "");
|
||||||
|
touchkpad_buttonMove(dx, dy);
|
||||||
kpad.timingBegins[REPEAT_BUTTON] = (struct timespec){ 0 };
|
kpad.timingBegins[REPEAT_BUTTON] = (struct timespec){ 0 };
|
||||||
if (kpad.buttonBegan) {
|
if (kpad.buttonBegan) {
|
||||||
kpad.buttonBegan = false;
|
kpad.buttonBegan = false;
|
||||||
@ -521,10 +551,12 @@ static void _init_gltouchjoy_kpad(void) {
|
|||||||
|
|
||||||
kpadJoy.variant = &touchkpad_variant,
|
kpadJoy.variant = &touchkpad_variant,
|
||||||
kpadJoy.resetState = &touchkpad_resetState,
|
kpadJoy.resetState = &touchkpad_resetState,
|
||||||
|
kpadJoy.setup = &touchkpad_setup,
|
||||||
|
kpadJoy.shutdown = &touchkpad_shutdown,
|
||||||
|
|
||||||
kpadJoy.setCurrButtonValue = &touchkpad_setCurrButtonValue,
|
kpadJoy.buttonDown = &touchkpad_buttonDown,
|
||||||
kpadJoy.buttonPress = &touchkpad_buttonPress,
|
kpadJoy.buttonMove = &touchkpad_buttonMove,
|
||||||
kpadJoy.buttonRelease = &touchkpad_buttonRelease,
|
kpadJoy.buttonUp = &touchkpad_buttonUp,
|
||||||
|
|
||||||
kpadJoy.axisDown = &touchkpad_axisDown,
|
kpadJoy.axisDown = &touchkpad_axisDown,
|
||||||
kpadJoy.axisMove = &touchkpad_axisMove,
|
kpadJoy.axisMove = &touchkpad_axisMove,
|
||||||
|
Loading…
Reference in New Issue
Block a user