Unlike the Key enum, which shows what a user would perceive as given key
in a particular layout, the scancode is a layout-independent identifier
for e.g. WASD movement in games.
Unfortunately the API availability is wildly different among the
toolkits -- SDL's is the most complete, GLFW is second, and then there's
Emscripten / HTML5 which provides just string identifiers. I tried to
add these for X11 as well, but quick googling led to a SO question where
it was left unanswered. Not worth my time.
There's the obvious advantage of them now being shorter to type, as one
no longer needs to prefix them with KeyEvent::. But the main reason I
did this was to allow various direct keyboard state queries to be
implemented, such as isKeyPressed(). With them being hidden in the event
class the only way would be to put the query directly there as well,
which isn't nice and is also not very discoverable.
A similar case was with mouse buttons, but that was already fixed with
the PointerEvent rework that happened in earlier commits. There the
additional complication was that MouseEvent::Button and
MouseMoveEvent::Button were incompatible enums. Application::Pointer
fixes that now as well.
Ubuntu 18.04 has 3.2 so this should be safe. Need to use
glfwGetKeyName() to undo keyboard layout weirdness, would be nasty to
have to make a fallback for older versions.
As usual, the most trash fire platform of them all. Ugh. I chose to
ignore certain aspects and suggestions and made it behave more like
Emscripten and SDL2, because that makes more sense to me.
Co-authored-by: nodoteve <nodoteve@yandex.com>
The impossible-to-reliably-disable behavior with compatibility mouse
events is quite a headache. I wish Emscripten implemented pointer events
already so I could ditch this mess -- especially the array of 32 touches
where all of them but one will be unchanged is stupid.
For the internals unfortunately, EmscriptenMouseEvent and
EmscriptenTouchEvent have no common base, so I had to give up on the
current way of querying the event struct directly from event getters, as
that'd be too nasty with the branching and casts. Instead the relevant
fields are put directly into the events themselves.
HTML5 also doesn't provide any relative pointer position. For the mouse
it was rather straightforward, but for the up-to-32 touches I have to
maintain an array of per-finger positions and match them by ID.
Hopefully the linear lookup is fine. I'll probably use the same approach
for the AndroidApplication.
This makes 2.0.6 as the oldest supported because in older versions it's
not possible to disable touch to mouse event translation, and it'd be
too annoying to have it special-cased there. The version bump should be
fine as Ubuntu 18.04 has 2.0.8.
All the new pointer events have float positions, this one was the odd one
out. And I didn't like the name anymore, so I took that as an opportunity
to change the position() data type without introducing a breaking change
for everyone.
Another considered change was adding Z offset to it, since HTML5 APIs
have that. However, all my googling led to just a single SO question from
2015, where someone said it's for trackballs that can navigate in 3D
space. I'm not sure if *scroll* is actually the best way to report those,
and since SDL3 didn't bother adding that and neither Android nor WINAPI
have anything like that, I'm not bothering either.
Unlike the previous commits, this is done for all apps at once, because
it's a comparatively simpler change. The only odd one out is
AbstractXApplication, where I introduced MouseScrollEvent just a few
commits back, so I simply renamed it without leaving a deprecated copy.
Then, ScreenedApplication needed some extra logic to handle the case of
apps not implementing any scroll event at all.
And thus also add actual support for finger and pen input, instead of
reporting them as Button::None. Something that needed fixing ever since
the initial implementation in 2014.
I *really* wanted to make a setup where mouse input would be recognized
as such and reported in the app, but wasted the whole day on that and got
only as far as having it recognized as a stylus input with hover (!!!),
when using some Android Desktop image. Not sure if that's some stupid
mislabeling (because middle and right mouse buttons are reported as such)
or it's just the emulation layer being crap.
While at it, I at least added support for hover events. I still have to
document all the newly found warts and hard-to-remember workflows with
getting a simulator running.
A special case here is that the event `state` doesn't yet include the
currently pressed button on press, and still includes the currently
release button on release. Which is the inverse of what the other
toolkits do, and contrary to the docs, so I patch it.
Furthermore, the buttons were originally reported on all input events,
but as the PointerEvent is now fired only when the first ever button is
pressed or the last remaining button is released, it doesn't make sense
to have a PointerEvent::pointers() getter, as it'd return always either
pointer() itself on pressed, or nothing at all on release. So the
pointers() getter is now moved directly to a KeyEvent, PointerMoveEvent
and MouseScrollEvent.
And deprecate WheelDown and WheelUp. Funnily enough a similar change was
done for *all other* applications including now-long-gone implementations
like NaClApplication back in 2a77856df2,
which was 2016!!
Frankly, I was first thinking that I'd just deprecate this thing and not
update it anymore, but it seems there's still a use case for a
lightweight wrapper sitting right on top of system APIs. SDL / GLFW is
too heavy for when one just needs to display stuff or debug GPU issues
for which it isn't clear whether they're the driver's fault or the
tookit's. And WindowlessApplication implementations proved very useful
for this, so I guess a similar windowed application still makes sense,
even if not very featureful. Additionally, for Vulkan I might take a stab
at implementing a WaylandApplication if even just an attempt to
understand how the swapchain works internally, and having an XApplication
available would be handy to compare the behavior.
For the most part is the same as in Sdl2Application, except that here
GLFW already returned floating-point coordinates, which this finally
makes use of.
Pointer events are an unified abstraction over mouse, touch, pen and
potential other yet-to-be-invented pointer-like input methods. Their goal
is to expose all such input methods under a single interface so the
application side doesn't need to explicitly make sure that it's
touch-aware or pen-aware. This abstraction is already present in HTML5,
in Qt6 and in WINAPI as well, and is also what I adopted for the new UI
library because it *just makes sense*.
Unfortunately not even SDL3 took the opportunity to introduce that and
instead added a *third* separate event type for pen input in SDL3. At
first I thought that I wouldn't introduce any extra abstractions in the
Application classes (because that's what they are designed to be, as
lightweight as possible), but midway through introducing TouchEvent
classes and fighting SDL's touch->mouse and mouse->touch compatibility
translation (yes, it's both ways, depending on the platform) I realized
that a much simpler solution that doesn't require any event translation
or the users duplicating their event handling logic for several possible
input types is to introduce a single new event type that covers all.
Which is what this commit does -- it doesn't introduce anything
touch-related so far, just creates a new PointerEvent and
PointerMoveEvent class and corresponding virtual functions. Additionally,
I took this as an opportunity to make the position floating-point, since
that's what SDL3 does now as well, and GLFW did so since ever.
Plus, the Pointer and Pointers enums are directly on the Sdl2Application
class, to allow me to *finally* introduce pointer state queries. Which
weren't possible until now, because there were mutually incompatible
MouseEvent::Button and MouseMoveEvent::Button enums and putting them on
the base class would mean one would have to be translated and the other
not. With Pointer it's translated always, because there isn't any similar
enumeration in SDL that would cover mouse, touch and pen at the same
time.
The distance reported by it is useless for any practical purpose because
it doesn't report a ratio of the current and previous radius between all
points, but rather the distance. Which, well, have fun using for any sort
of zooming.
(And yeah, given that the MultiGestureEvent is gone in SDL3, I spent
quite some time looking at what it actually did in order to reimplement
that functionality on my end, and it felt *extremely weird* to me that it
always considered just that single point, never the others in order to
calculate any sort of radius. This is why, because it never considered
any sort of radius between the points, so the "Multi" in there is highly
questionable!)
So this test is just to make the uselessness easy to verify, nothing
more.
I wanted to add this for GlfwApplication, only to realize the timer there
is a double, in seconds, so accepting *integral* milliseconds there felt
very weird. Let's use the fancy new time types instead.
Also updated the docs to (hopefully) clarify that setSwapInterval() has
to be called in order for the interaction between the two to work
properly.
As usual, the old variant taking untyped milliseconds is a deprecated
alias to this one.
And for Sdl2Application print both the keycode and keysym, as the
current way with a keycode seems different from what both GLFW and HTML5
does. But the SDL2 scancode also doesn't feel right because compared to
GLFW and HTML5 it swaps Y and Z on my keyboard. SIGH.
In the Emscripten build, accepting events in EmscriptenApplication
prevents them from propagating further to the page, such as F1 that
would open a browser help page. That's not the case with SDL as SDL has
no concept of "accepting an event", so just document that in the test
code.
This makes the minimal supported Emscripten version 1.39.5. With some
more effort this could be changed to 1.38.27, but I don't think anybody
needs that.
The whole class was a bad idea, why create something that's 99% similar
to another application and has just one platform-specific workaround? Of
course it resulted in this code being completely untested and not even
built anywhere, because it served a tiny insignificant use case.
To avoid losing all the code, I did my best in attempting to merge this
into the WindowlessEglApplication. But since, again, EGL isn't
really used on any Windows platform, I can't even say it builds
properly. Maybe not even the original code built.
Similar to the change done in Corrade, see the commit for details:
878624ac36
Wow, this is probably the most backwards-compatibility code I've ever
written. Can't wait until I can drop all that.
Which allows to get rid of a now-unneeded ArrayView include in the
header. Also, now that we're returning a StringView, it's useful to
have the view always null-terminated. In SDL2 and Emscripten it was
already like that, GLFW needed a minor change.
It limits the support for CMake 3.12+, but it's much less verbose and I
don't expect people to use ancient CMake versions with IDEs like Xcode
or VS anyway, so this should be fine.
The app does its own EGL-specific verbose printing and thus should
recognize this option the same way as GL::Context does. Right now it was
only taking into account the command-line parameters and not the new
Configuration.
Right now only the command-line variant of it was checked. Since on
some platforms this requires the app to explicitly request a debug
context, the app needs to handle the case when it's passed via a
Configuration as well.