floooh / sokol

minimal cross-platform standalone C headers
https://floooh.github.io/sokol-html5
zlib License
7.04k stars 494 forks source link

sokol_app: EMSCRIPTEN: can't write into a textarea while sapp is running #822

Closed marekmaskarinec closed 9 months ago

marekmaskarinec commented 1 year ago

Hello, I'm trying to run a program using sokol_app compiled to WASM using emscripten alongside a textarea. However I can't enter any input into the the textarea. I can normally select it and even use shortcuts like copy and paste, but entering keys is not possible. Is it possible that sokol_app somehow catches the keyboard input before it can be processed?

I use this shell file: https://git.sr.ht/~mrms/tophat/tree/main/item/playground.html The compiled result is available here: https://tophat2d.dev/playground/

floooh commented 1 year ago

There's a couple of issues in the sokol_app.h Emscripten backend which might interfere:

First, there's a hardwired table of key events that never bubble up, see this comment here: https://github.com/floooh/sokol/pull/801#issuecomment-1500246922

(all other events should bubble up though, unless sapp_consume_event() is called on them.

...and then there's a hidden text field here, but this shouldn't be focused unless sapp_show_keyboard() is called: https://github.com/floooh/sokol/blob/7373dda48c5e62953cc7ec942da90fc6a25989fa/sokol_app.h#L4712-L4730 (this whole mobile keyboard support will most likely be removed in the near future, I tinkered around with it a bit more recently but couldn't get it to work reliably across all mobile browsers)

You could try tinkering with the Emscripten keyboard callback here, most importantly, never return 'true' from this callback:

https://github.com/floooh/sokol/blob/7373dda48c5e62953cc7ec942da90fc6a25989fa/sokol_app.h#L5339-L5476

Another difference between the key callbacks and other input callbacks is that the key callbacks are attached to the DOM window object, not the canvas:

https://github.com/floooh/sokol/blob/7373dda48c5e62953cc7ec942da90fc6a25989fa/sokol_app.h#L5711-L5713

If you find a hack that works we can figure out how to solve the problem in a cleaner way.

marekmaskarinec commented 1 year ago

I've modified _sapp_emsc_key_cb to always return false. This fixed the issue, however it's not clear to me why normal key presses were consumed in the first place. I will use this as a hack until we can fix this issue.

In my opinion the hardcoded list of events that never bubble up should be cusomizable - in some cases it might be useful to let the user refresh etc.

Also this issue seems to be very similar to #800. Maybe consider merging these.

floooh commented 1 year ago

Ok good to know. I'll write a separate ticket. I think the hardwired table will definitely need to go, and then leave it to the application to decide what events should be consumed (by calling sapp_consume_event() from the event handler - which was a later addition).

floooh commented 10 months ago

This PR removes the hidden text input field in the sokol_app.h Emscripten backend, but I kept the key event bubbling behaviour for now. In my case the change fixes a problem I had in https://marketplace.visualstudio.com/items?itemName=floooh.vscode-kcide with Dear ImGui text input fields because the hidden HTML text input field generated a focus-in/out event which confused Dear ImGui.

I'm not sure if this changes anything for your use case, but it also can't make things worse at least. The PR will be merged shortly.

marekmaskarinec commented 10 months ago

This isn't really relevant for my use case, I'm only concerned with keyboard input.

However now that I'm looking at the code again, I think the main issue here is that all character key presses are automatically eaten. Is this even wanted?

https://github.com/floooh/sokol/blob/7373dda48c5e62953cc7ec942da90fc6a25989fa/sokol_app.h#L5363-L5370

vtereshkov commented 10 months ago

Something may have changed after a recent commit to master, as the return value is now false by default:

https://github.com/floooh/sokol/commit/f6aa4611b0cc656a32cf9a25f07b7f3a9f377ee4#diff-42747840ac0dd5aaeaa9368919646cc57e72a0bb54c03ad85c7eac18956ea584R5317

However, the commit message says there are no functional changes.

vtereshkov commented 10 months ago

After some testing, I found that the character keys were no longer eaten. However, all the functional keys still were:

https://github.com/floooh/sokol/blob/master/sokol_app.h#L5426

For example, I could type some text but could not delete it.

floooh commented 10 months ago

Yeah, the exception that non-alphanumeric key up/down events are consumed is still in place, but this hasn't changed from before. I need to do a bit more testing to figure out again why I added this hardwired key list in the first place.

One obvious reason for not letting function keys bubble up were things like F7 on Chrome turning on "caret browsing", and probably a couple of other hardwired function key things that don't make sense in many web apps which use a webgl canvas over the whole client area.

Removing that hardwired switch-case would require all applications which actually want that behaviour to call sapp_consume_event() in their event callback, which was a bit of a too drastic compatibility break for my taste.

One potential solution would be to add config booleans to sapp_desc to turn off some of that magic filtering (also for the wheel events), but I need to think about that a bit more.

marekmaskarinec commented 10 months ago

One potential solution would be to add config booleans to sapp_desc to turn off some of that magic filtering (also for the wheel events), but I need to think about that a bit more.

This would be ideal in my opinion.

floooh commented 9 months ago

This is now sort-of fixed via https://github.com/floooh/sokol/pull/975, with some caveats for key events (e.g. key up/down events which generate character events still need to bubble up by default). It's now possible to 'open the flood gates' and let all events bubble and then control bubbling for individual events by calling sapp_consume_event() inside the event callback.