Skip to content

Commit

Permalink
Merge pull request #939 from floooh/sapp-emsc-consume-event
Browse files Browse the repository at this point in the history
sokol_app.h emsc: more control over input event consumption, remove hidden text input field
  • Loading branch information
floooh authored Jan 2, 2024
2 parents adf1f83 + 0365e52 commit c3ed0f9
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 99 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/gen_bindings.yml
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ jobs:
steps:
- uses: jiro4989/setup-nim-action@v1
with:
nim-version: devel
nim-version: '2.x'
repo-token: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/checkout@v4
with:
Expand Down
18 changes: 18 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,23 @@
## Updates

#### 02-Jan-2024

Happy New Year! A couple of input-related changes in the sokol_app.h Emscripten backend:

- Mouse and touch events now bubble up to the HTML document instead of being consumed, in some scenarios this
allows better integration with the surrounding web page. To prevent event bubbling,
call `sapp_consume_event()` from within the sokol_app.h event callback function.
- **NOTE**: wheel/scroll events behave as before and are always consumed. This prevents
an ugly "scroll bumping" effect when a wheel event bubbles up on a page where
scrolling shouldn't be possible.
- The hidden HTML text input field hack for text input on mobile browsers has been
removed. This idea never really worked across all browsers, and it actually
interfered with Dear ImGui text input fields because the hidden HTML text field
generated focus-in/out events which confused the Dear ImGui input handling code.

Those changes fix a couple of problem when trying to integrate sokol_app.h applications
into VSCode webview panels, see: https://marketplace.visualstudio.com/items?itemName=floooh.vscode-kcide

#### 10-Nov-2023

A small change in the sokol_gfx.h GL backend on Windows only:
Expand Down
123 changes: 25 additions & 98 deletions sokol_app.h
Original file line number Diff line number Diff line change
Expand Up @@ -1665,7 +1665,7 @@ typedef struct sapp_desc {
sapp_allocator allocator; // optional memory allocation overrides (default: malloc/free)
sapp_logger logger; // logging callback override (default: NO LOGGING!)

/* backend-specific options */
// backend-specific options
int gl_major_version; // override GL major and minor version (the default GL version is 3.2)
int gl_minor_version;
bool win32_console_utf8; // if true, set the output console codepage to UTF-8
Expand Down Expand Up @@ -2411,9 +2411,6 @@ typedef struct {
#endif

typedef struct {
bool textfield_created;
bool wants_show_keyboard;
bool wants_hide_keyboard;
bool mouse_lock_requested;
uint16_t mouse_buttons;
} _sapp_emsc_t;
Expand Down Expand Up @@ -4648,13 +4645,6 @@ extern "C" {

typedef void (*_sapp_html5_fetch_callback) (const sapp_html5_fetch_response*);

/* this function is called from a JS event handler when the user hides
the onscreen keyboard pressing the 'dismiss keyboard key'
*/
EMSCRIPTEN_KEEPALIVE void _sapp_emsc_notify_keyboard_hidden(void) {
_sapp.onscreen_keyboard_shown = false;
}

EMSCRIPTEN_KEEPALIVE void _sapp_emsc_onpaste(const char* str) {
if (_sapp.clipboard.enabled) {
_sapp_strcpy(str, _sapp.clipboard.buffer, _sapp.clipboard.buf_size);
Expand Down Expand Up @@ -4745,27 +4735,6 @@ EMSCRIPTEN_KEEPALIVE void _sapp_emsc_invoke_fetch_cb(int index, int success, int
} /* extern "C" */
#endif

/* Javascript helper functions for mobile virtual keyboard input */
EM_JS(void, sapp_js_create_textfield, (void), {
const _sapp_inp = document.createElement("input");
_sapp_inp.type = "text";
_sapp_inp.id = "_sokol_app_input_element";
_sapp_inp.autocapitalize = "none";
_sapp_inp.addEventListener("focusout", function(_sapp_event) {
__sapp_emsc_notify_keyboard_hidden()

});
document.body.append(_sapp_inp);
});

EM_JS(void, sapp_js_focus_textfield, (void), {
document.getElementById("_sokol_app_input_element").focus();
});

EM_JS(void, sapp_js_unfocus_textfield, (void), {
document.getElementById("_sokol_app_input_element").blur();
});

EM_JS(void, sapp_js_add_beforeunload_listener, (void), {
Module.sokol_beforeunload = (event) => {
if (__sapp_html5_get_ask_leave_site() != 0) {
Expand Down Expand Up @@ -4901,45 +4870,6 @@ EM_JS(void, sapp_js_remove_dragndrop_listeners, (const char* canvas_name_cstr),
canvas.removeEventListener('drop', Module.sokol_drop);
});

/* called from the emscripten event handler to update the keyboard visibility
state, this must happen from an JS input event handler, otherwise
the request will be ignored by the browser
*/
_SOKOL_PRIVATE void _sapp_emsc_update_keyboard_state(void) {
if (_sapp.emsc.wants_show_keyboard) {
/* create input text field on demand */
if (!_sapp.emsc.textfield_created) {
_sapp.emsc.textfield_created = true;
sapp_js_create_textfield();
}
/* focus the text input field, this will bring up the keyboard */
_sapp.onscreen_keyboard_shown = true;
_sapp.emsc.wants_show_keyboard = false;
sapp_js_focus_textfield();
}
if (_sapp.emsc.wants_hide_keyboard) {
/* unfocus the text input field */
if (_sapp.emsc.textfield_created) {
_sapp.onscreen_keyboard_shown = false;
_sapp.emsc.wants_hide_keyboard = false;
sapp_js_unfocus_textfield();
}
}
}

/* actually showing the onscreen keyboard must be initiated from a JS
input event handler, so we'll just keep track of the desired
state, and the actual state change will happen with the next input event
*/
_SOKOL_PRIVATE void _sapp_emsc_show_keyboard(bool show) {
if (show) {
_sapp.emsc.wants_show_keyboard = true;
}
else {
_sapp.emsc.wants_hide_keyboard = true;
}
}

EM_JS(void, sapp_js_init, (const char* c_str_target), {
// lookup and store canvas object by name
const target_str = UTF8ToString(c_str_target);
Expand Down Expand Up @@ -5165,6 +5095,7 @@ _SOKOL_PRIVATE EM_BOOL _sapp_emsc_size_changed(int event_type, const EmscriptenU

_SOKOL_PRIVATE EM_BOOL _sapp_emsc_mouse_cb(int emsc_type, const EmscriptenMouseEvent* emsc_event, void* user_data) {
_SOKOL_UNUSED(user_data);
bool consume_event = false;
_sapp.emsc.mouse_buttons = emsc_event->buttons;
if (_sapp.mouse.locked) {
_sapp.mouse.dx = (float) emsc_event->movementX;
Expand Down Expand Up @@ -5225,15 +5156,14 @@ _SOKOL_PRIVATE EM_BOOL _sapp_emsc_mouse_cb(int emsc_type, const EmscriptenMouseE
} else {
_sapp.event.mouse_button = SAPP_MOUSEBUTTON_INVALID;
}
_sapp_call_event(&_sapp.event);
consume_event = _sapp_call_event(&_sapp.event);
}
// mouse lock can only be activated in mouse button events (not in move, enter or leave)
if (is_button_event) {
_sapp_emsc_update_mouse_lock_state();
}
}
_sapp_emsc_update_keyboard_state();
return true;
return consume_event;
}

_SOKOL_PRIVATE EM_BOOL _sapp_emsc_wheel_cb(int emsc_type, const EmscriptenWheelEvent* emsc_event, void* user_data) {
Expand All @@ -5255,8 +5185,9 @@ _SOKOL_PRIVATE EM_BOOL _sapp_emsc_wheel_cb(int emsc_type, const EmscriptenWheelE
_sapp.event.scroll_y = scale * (float)emsc_event->deltaY;
_sapp_call_event(&_sapp.event);
}
_sapp_emsc_update_keyboard_state();
_sapp_emsc_update_mouse_lock_state();
// NOTE: wheel events are always consumed because they try to scroll the
// page which looks pretty bad
return true;
}

Expand Down Expand Up @@ -5383,7 +5314,7 @@ _SOKOL_PRIVATE sapp_keycode _sapp_emsc_translate_key(const char* str) {

_SOKOL_PRIVATE EM_BOOL _sapp_emsc_key_cb(int emsc_type, const EmscriptenKeyboardEvent* emsc_event, void* user_data) {
_SOKOL_UNUSED(user_data);
bool retval = true;
bool consume_event = false;
if (_sapp_events_enabled()) {
sapp_event_type type;
switch (emsc_type) {
Expand All @@ -5406,14 +5337,9 @@ _SOKOL_PRIVATE EM_BOOL _sapp_emsc_key_cb(int emsc_type, const EmscriptenKeyboard
_sapp.event.key_repeat = emsc_event->repeat;
_sapp.event.modifiers = _sapp_emsc_key_event_mods(emsc_event);
if (type == SAPP_EVENTTYPE_CHAR) {
// FIXME: this doesn't appear to work on Android Chrome
// NOTE: charCode doesn't appear to be supported on Android Chrome
_sapp.event.char_code = emsc_event->charCode;
/* workaround to make Cmd+V work on Safari */
if ((emsc_event->metaKey) && (emsc_event->charCode == 118)) {
retval = false;
}
}
else {
} else {
if (0 != emsc_event->code[0]) {
// This code path is for desktop browsers which send untranslated 'physical' key code strings
// (which is what we actually want for key events)
Expand All @@ -5437,7 +5363,9 @@ _SOKOL_PRIVATE EM_BOOL _sapp_emsc_key_cb(int emsc_type, const EmscriptenKeyboard
{
send_keyup_followup = true;
}
// only forward keys to the browser (can further be suppressed by sapp_consume_event())
// Only forward alpha-numeric keys to the browser (can further be suppressed by sapp_consume_event())
// NOTE: it should be possible to disable this behaviour via sapp_desc to give apps more
// controls over input event bubbling.
switch (_sapp.event.key_code) {
case SAPP_KEYCODE_WORLD_1:
case SAPP_KEYCODE_WORLD_2:
Expand Down Expand Up @@ -5494,34 +5422,34 @@ _SOKOL_PRIVATE EM_BOOL _sapp_emsc_key_cb(int emsc_type, const EmscriptenKeyboard
case SAPP_KEYCODE_RIGHT_ALT:
case SAPP_KEYCODE_RIGHT_SUPER:
case SAPP_KEYCODE_MENU:
/* consume the event */
// consume the event
consume_event = true;
break;
default:
/* forward key to browser */
retval = false;
// forward key to browser
consume_event = false;
break;
}
}
if (_sapp_call_event(&_sapp.event)) {
// event was consumed via sapp_consume_event()
retval = true;
consume_event = true;
}
if (send_keyup_followup) {
_sapp.event.type = SAPP_EVENTTYPE_KEY_UP;
if (_sapp_call_event(&_sapp.event)) {
retval = true;
consume_event = true;
}
}
}
}
_sapp_emsc_update_keyboard_state();
_sapp_emsc_update_mouse_lock_state();
return retval;
return consume_event;
}

_SOKOL_PRIVATE EM_BOOL _sapp_emsc_touch_cb(int emsc_type, const EmscriptenTouchEvent* emsc_event, void* user_data) {
_SOKOL_UNUSED(user_data);
bool retval = true;
bool consume_event = false;
if (_sapp_events_enabled()) {
sapp_event_type type;
switch (emsc_type) {
Expand All @@ -5539,7 +5467,6 @@ _SOKOL_PRIVATE EM_BOOL _sapp_emsc_touch_cb(int emsc_type, const EmscriptenTouchE
break;
default:
type = SAPP_EVENTTYPE_INVALID;
retval = false;
break;
}
if (type != SAPP_EVENTTYPE_INVALID) {
Expand All @@ -5557,11 +5484,10 @@ _SOKOL_PRIVATE EM_BOOL _sapp_emsc_touch_cb(int emsc_type, const EmscriptenTouchE
dst->pos_y = src->targetY * _sapp.dpi_scale;
dst->changed = src->isChanged;
}
_sapp_call_event(&_sapp.event);
consume_event = _sapp_call_event(&_sapp.event);
}
}
_sapp_emsc_update_keyboard_state();
return retval;
return consume_event;
}

_SOKOL_PRIVATE EM_BOOL _sapp_emsc_focus_cb(int emsc_type, const EmscriptenFocusEvent* emsc_event, void* user_data) {
Expand Down Expand Up @@ -5804,6 +5730,9 @@ _SOKOL_PRIVATE void _sapp_emsc_wgpu_frame(void) {
#endif // SOKOL_WGPU

_SOKOL_PRIVATE void _sapp_emsc_register_eventhandlers(void) {
// NOTE: HTML canvas doesn't receive input focus, this is why key event handlers are added
// to the window object (this could be worked around by adding a "tab index" to the
// canvas)
emscripten_set_mousedown_callback(_sapp.html5_canvas_selector, 0, true, _sapp_emsc_mouse_cb);
emscripten_set_mouseup_callback(_sapp.html5_canvas_selector, 0, true, _sapp_emsc_mouse_cb);
emscripten_set_mousemove_callback(_sapp.html5_canvas_selector, 0, true, _sapp_emsc_mouse_cb);
Expand Down Expand Up @@ -11309,8 +11238,6 @@ SOKOL_API_IMPL const void* sapp_egl_get_context(void) {
SOKOL_API_IMPL void sapp_show_keyboard(bool show) {
#if defined(_SAPP_IOS)
_sapp_ios_show_keyboard(show);
#elif defined(_SAPP_EMSCRIPTEN)
_sapp_emsc_show_keyboard(show);
#elif defined(_SAPP_ANDROID)
_sapp_android_show_keyboard(show);
#else
Expand Down

0 comments on commit c3ed0f9

Please # to comment.