The pointer store took a touch to be there when its packed position
was not 0. A contact at the window's origin packs to 0, so a finger
down at 0,0 was not a touch: the pointer read the mouse and was not
pressed, and a lightgun aiming at the first touch aimed at the mouse.
DirectInput, raw input and SDL3 went by whether the contact existed
before they published, so for them this was a regression.
Where a contact is, whether there is one and whether it is down are
three things, and input_driver_publish_touches() takes them
separately: a position, a bit in @present, a bit in @down. A contact
at 0,0 is one; one that has lifted may keep its place, there and not
down - a finger's last place under Wayland, a pen in the air under
SDL3. DirectInput, raw input and SDL3's fingers say each contact they
list is there. Wayland keeps the rule it had, which is its own and is
now written where it belongs: a place at 0,0 is how the desktop reports
a mouse button, and is not a touch.
pointer_frame_test: a touch down at the origin, one lifted there, a
place with none, the viewport's edges, sparse places, the mouse's
fallback, the lightgun's choice, a pen in the air at the origin.
The drivers the frontend does not answer for place a touch or a mouse
in the viewport themselves, and each asked the video driver for the
viewport every time: GameCube/Wii, PS3, PSP and the web on every read
of a pointer or lightgun value; Cocoa twice a touch a poll and once a
lightgun read; Switch once a touch a poll; Android and QNX once or
twice a touch event.
The frontend already keeps the viewport once a poll for the drivers
that publish. input_driver_poll_viewport() gives it to the others, with
two macros that take the place of video_driver_translate_coord_
viewport_wrap() and its confined twin, and those eight drivers use
them: one viewport a poll, however many touches and reads. How each
places its touches is unchanged. On the frontend's thread only, which
is where all eight do it; UWP, which may not, is left as it was.
pointer_frame_test checks the viewport is asked for once a poll and
afresh at the next.
SDL3 hands the frontend the mouse's frame, the fingers that are down
and the pen once a poll, and its own answers for the mouse, the pointer
and the lightgun's aim are deleted. Fingers are read before the pen and
the pen before the mouse, as before.
What the store learned for it:
- how many pointers are down (RETRO_DEVICE_ID_POINTER_COUNT): the
touches that are, else the mouse standing for one. SDL3 answered
this; the drivers converted before it gave 0, and now give the
count too;
- a pointer placed as the lightgun is, -0x8000 outside the viewport,
where the other drivers hold it to the edge
(INPUT_POINTERS_POINTER_OFFSCREEN);
- a touch read alone (INPUT_POINTERS_TOUCH_ALONE): a pen in the air is
a pointer that is not pressed, whatever the mouse's buttons say.
A touch is placed either way once a poll, as a mouse is.
pointer_frame_test covers the count and both flags.
The DirectInput driver hands the frontend its mouse's frame and its
touches, in the order they went down, once a poll, and its own answers
for the mouse, the pointer and the lightgun's aim are deleted.
Two things DirectInput does that the store now does for it, each a
flag a driver sets:
- the mouse is the port's whose Mouse Index is 0, while the pointer and
the lightgun's aim are every port's (INPUT_POINTERS_AIM_EVERY_PORT);
- the lightgun aims where the first touch is while there is one
(INPUT_POINTERS_GUN_AT_TOUCH), placed once a poll.
A wheel notch was kept until something read it, and the first read
used it up. It is the frame's now, as with the other drivers: cleared
at the next poll, and the same for every reader, a control bound to
the wheel included.
pointer_frame_test covers both flags.
The Windows raw input driver hands the frontend each mouse's frame and
its touches once a poll, and its own answers for the mouse, the pointer
and the lightgun's aim are deleted. Read by a core over a session of
moves, clicks and wheel turns under Wine it gives the same values as
before, line for line.
Three things the store needed for it:
- a port reads the mouse at its Mouse Index, or where its pinned mouse
is (INPUT_POINTERS_BY_MOUSE_INDEX): which mouse a port reads is
decided in the frontend, once, and no longer looked up by the driver
on every value;
- a mouse standing for one touch, its left button, as raw input had it.
The third argument of input_driver_publish_pointers() is flags now:
that, or three touches as X11 and Wayland have it;
- raw input takes a mouse's reports differently when it is read as a
pointer or as a lightgun. The frontend records what each published
device was last read as, and the driver asks at its poll
(input_driver_pointer_read_as()).
A port with no mouse still reads a real touch.
pointer_frame_test covers reading by Mouse Index, a port with no mouse,
and the record of what a device was read as. The raw input samples get
stand-ins for the three calls.
The Wayland driver hands the frontend its mouse's frame and its touches
once a poll, and its own answers for the mouse, the pointer and the
lightgun's aim are deleted; the lightgun's buttons, which are the
mouse's, stay. Read by a core over a session of moves, clicks and wheel
turns under Weston it gives the same values as before, but for a second
read of the wheel in a frame. With that core reading the pointer and
the lightgun's aim every frame, 300 frames took 2796 translations and
2798 viewport fetches before and take 600 and 302 now.
Three things change with it on Wayland. Relative motion adds up between
polls: each event used to replace the last, so only the last of a frame
counted. The motion and the wheel are taken once a poll, where the
first read cleared them. And with a real touch in a place, whether it
is off-screen goes by the touch, not by the mouse.
The frontend's store takes touches (input_driver_publish_touches()): a
place with a touch reads the touch, a place with none the mouse standing
for it. How many touches a mouse stands for is the driver's to say - 3
for X11 and Wayland, as they had it, 1 for the drivers that will take
the left button only - so input_driver_publish_pointers() gains that
argument.
The store moves to input/input_pointer_frame.h so that a test can drive
it: samples/input/pointer_frame, in the input samples job, counts the
viewport fetches and translations - eight pointer reads are one of each
- and covers touches, both ways a mouse stands for them, and the wheel.