diff --git a/src/video/gltouchjoy_kpad.c b/src/video/gltouchjoy_kpad.c index 495712ab..f9c323b5 100644 --- a/src/video/gltouchjoy_kpad.c +++ b/src/video/gltouchjoy_kpad.c @@ -123,11 +123,6 @@ static inline void _press_key(subvariant_s *subvariant, keypad_press_t pressIdx) ++(subvariant->keyPressCount); } -// No-op callback -static void touchkpad_nopCallback(uint8_t textFlashCounter) { - (void)textFlashCounter; -} - // End-of-video-frame callback (handling tap delay and auto-strobe) static void touchkpad_frameCallback(uint8_t textFlashCounter) { @@ -224,7 +219,7 @@ static void touchkpad_frameCallback(uint8_t textFlashCounter) { if ((kpad.axis.currEventType == TOUCH_UP) && (kpad.butt.currEventType == TOUCH_UP)) { // all touch up occurred -- unlatch the callback TOUCH_JOY_LOG("\t\t+++kpad callback done"); - kpad.frameCallback = touchkpad_nopCallback; + kpad.frameCallback = NULL; kpad.axis.scancodes[REPEAT_IDX_A] = -1; kpad.axis.scancodes[REPEAT_IDX_B] = -1; kpad.butt.scancodes[REPEAT_IDX_A] = -1; diff --git a/src/video/gltouchkbd.c b/src/video/gltouchkbd.c index 7473224f..680660e6 100644 --- a/src/video/gltouchkbd.c +++ b/src/video/gltouchkbd.c @@ -41,6 +41,8 @@ #define KBD_OBJ_W GL_MODEL_MAX // model width fits screen #define KBD_OBJ_H_LANDSCAPE GL_MODEL_MAX +#define KBD_BUTTON_HOLD_FRAMES 7 // >= 1/10 sec (seems reasonable for AppleSoft BASIC sampling ;) + typedef enum keyboard_variant_t { KBD_VARIANT_DEFAULT=0, KBD_VARIANT_LOWERCASE, @@ -122,6 +124,8 @@ static struct { static struct { GLModel *model; + video_frame_callback_fn frameCallback; + GLfloat modelHeight; GLfloat modelSkewY; bool modelDirty; @@ -141,6 +145,9 @@ static struct { struct timespec timingBegin; + uint8_t button0Count; + uint8_t button1Count; + bool prefsChanged; } kbd = { 0 }; @@ -149,6 +156,54 @@ static void gltouchkbd_applyPrefs(void); // ---------------------------------------------------------------------------- // Misc internal methods +// End-of-video-frame callback ... +// +// NOTE : Currently this is only handling the joystick buttons being pressed for a set number of frames. +// +// But could we augment the touch keyboard to implement full auto-repeat functionality (following a similar state machine to +// gltouchjoy_kpad variant)? +// +// At present time, the show-stopper for auto-repeat is that it breaks fundamental existing UI/UX: +// +// - It is possible now with this touch keyboard to place a thumb down indefinitely, keeping the keyboard lit up rather than +// invisible, while you then hunt for the key you want to select on the touch up. This is fundamental UI/UX that has always +// been supported, and auto-repeat functionality directly challenges that! +// +// - Presumably an auto-repeat keyboard would press the key tapped on touch down (possibly after a delay to detect either +// long-press or motion beyond the x/y threshold of the touch down key) ... and this would break the existing "hold-and-hunt" +// functionality. +// +// - It's worth noting that auto-repeat is implicitly handled by hardware keyboards on all major platforms we compile on. +// Presumably if auto-repeat is important, then just use a hardware keyboard... +// +// - What about a special gesture or special sticky (AUTO-LOCK) key that engages the auto-repeat behavior? +// +static void touchkbd_frameCallback(uint8_t textFlashCounter) { + + // When activated, this is called every video frame -- ~16.688 millis + + ASSERT_ON_CPU_THREAD(); + + if (kbd.button0Count) { + --kbd.button0Count; + } + if (!kbd.button0Count) { + run_args.joy_button0 = 0x0; + } + + if (kbd.button1Count) { + --kbd.button1Count; + } + if (!kbd.button1Count) { + run_args.joy_button1 = 0x0; + } + + if (!kbd.button0Count && !kbd.button1Count) { + // unlatch frame callback ... + kbd.frameCallback = NULL; + } +} + #warning FIXME TODO ... make this a generic GLModelHUDElement function static void _rerender_character(int col, int row) { GLModelHUDElement *hudKeyboard = (GLModelHUDElement *)(kbd.model->custom); @@ -407,13 +462,15 @@ static inline int64_t _tap_key_at_point(float x, float y) { break; case MOUSETEXT_OPENAPPLE: - run_args.joy_button0 = run_args.joy_button0 ? 0x0 : 0x80; - scancode = SCODE_L_ALT; + run_args.joy_button0 = 0x80; + kbd.button0Count = KBD_BUTTON_HOLD_FRAMES; + kbd.frameCallback = touchkbd_frameCallback; break; case MOUSETEXT_CLOSEDAPPLE: - run_args.joy_button1 = run_args.joy_button1 ? 0x0 : 0x80; - scancode = SCODE_R_ALT; + run_args.joy_button1 = 0x80; + kbd.button1Count = KBD_BUTTON_HOLD_FRAMES; + kbd.frameCallback = touchkbd_frameCallback; break; case MOUSETEXT_CURSOR0: @@ -1146,6 +1203,8 @@ static void _init_gltouchkbd(void) { prefs_registerListener(PREF_DOMAIN_KEYBOARD, &gltouchkbd_prefsChanged); prefs_registerListener(PREF_DOMAIN_TOUCHSCREEN, &gltouchkbd_prefsChanged); prefs_registerListener(PREF_DOMAIN_INTERFACE, &gltouchkbd_prefsChanged); + + video_registerFrameCallback(&kbd.frameCallback); } static __attribute__((constructor)) void __init_gltouchkbd(void) {