When our keyboard grab hook is installed, GetKeyState() will return 0 for the
GUI keys even when they are pressed. This leads to spurious key up events when
holding down the GUI keys and the inability to use any key combos involving
those modifier keys.
Touching HID devices with keyboard usages will trigger a keyboard capture
permission prompt on macOS 11+. See #4887
Like the IOKit joystick backend, we accept HID devices that have joystick,
gamepad, or multi-axis controller usages. We also allow the Valve VID for
the Steam Controller, just like the Windows HIDAPI implementation does.
We can also ditch the lock in RAWINPUT_JoystickQuit() now that the joystick
subsystem quits drivers in reverse order. There's no chance of a racing call
to RAWINPUT_WindowProc() anymore.
SDL_WINDOWS_JoystickDriver depends on callbacks in SDL_RAWINPUT_JoystickDriver
and SDL_HIDAPI_JoystickDriver being available. It also manages the common
WindowProc used for joystick detection in both WINDOWS and RAWINPUT drivers.
If we don't tear them down backwards, there's a window of time where we could
invoke RAWINPUT_WindowProc() after RAWINPUT_JoystickQuit() was called.
- SDL_CLOCK_GETTIME now defaults to ON to match autotools build
- Add detection of float.h and Xdbe
- Fix detection of pthread_setname_np() (requires _GNU_SOURCE)
- Move SDL_USE_IME definition into SDL_config.h.cmake
Since the haptic subsystem is usually initialized after the joystick subsystem,
the initial calls to HapticMaybeAddDevice() from inside SDL_JoystickInit() will
arrive too early to be handled by the haptic subsystem. We need to add those
haptic devices for those already present joysticks ourselves.
The joystick subsystem has complex precedence logic to deal multiple competing
backends like XInput, RawInput, and WGI. Let it fire the MaybeAdd callbacks
for joystick devices, since it knows which backend will end up managing them.
This resolves a situation where the RawInput joystick backend would take
control of an XInput device but the XInput haptic backend would still create
a haptic device. Since the XInput joystick backend didn't own the underlying
joystick device, we'd end up with an orphaned haptic device that didn't work
with SDL_HapticOpenFromJoystick() on the associated joystick device.
A racing reader could read from our fd between SDL_IOReady()/X11_Pending()
and our call to XNextEvent() which will cause XNextEvent() to block for
more data. Avoid this by using XCheckIfEvent() which will never block.
This also fixes a bug where we could poll() for data, even when events were
already read and pending in the queue. Unlike the Wayland implementation,
this isn't totally thread-safe because nothing prevents a racing reader
from reading events into the queue between our XCheckIfEvent() and
SDL_IOReady() calls, but I think this is the best we can do with Xlib.
Enabling the RawInput backend causes SDL_XINPUT_Enabled() to return false.
That causes WGI and DInput backends to take ownership of XInput-compatible
controllers, because they think there's no XInput-specific backend enabled.
In WGI's case, it will actually race with RawInput to open the device. By
properly excluding XInput devices from WGI, we can ensure that the sets of
devices managed by WGI and RawInput don't intersect. This makes the race
harmless, since they'll never both go after the same device.
The Xbox One driver stack doesn't propagate the VID/PID down to the
HID devices that end up in the GetRawInputDeviceList() output. This
means we end up matching against the wrong VID/PID and can't properly
exclude Xbox One controllers from WGI.
Fortunately, it is possible to walk back up the device tree to find
the parent with the matching VID/PID.
__has_include() was added in VS 2017 15.3, so this works out to essentially
the same _MSC_VER >= 1911 check we had before for MSVC but works for non-MSVC
compilers also.
The D3D11 renderer requires Direct3D 11.1 (d3d11_1.h), not Direct3D 11.0
(d3d11.h). In terms of SDKs, that's the Windows 8 SDK or later.
We should probably rename HAVE_D3D11_H...
Add a new flag to avoid suppressing EINTR in SDL_IOReady(). Pass the
flag in WaitEventTimeout() to ensure that a SIGINT will wake up
SDL_WaitEvent() without another event coming in.
We can have spurious wakeups in WaitEventTimeout() due to Wayland events
that don't end up causing us to generate an SDL event. Fortunately for us,
SDL_WaitEventTimeout_Device() handles this situation properly by calling
WaitEventTimeout() again with an adjusted timeout.
Wayland provides the prepare_read()/read_events() family of APIs for
reading from the display fd in a deadlock-free manner across multiple
threads in a multi-threaded application. Let's use those instead of
trying to roll our own solution using a mutex.
This fixes an issue where a call to SDL_GL_SwapWindow() doesn't swap
buffers if it happens to collide with SDL_PumpEvents() in the main
thread. It also allows coexistence with other code or toolkits in
our process that may want read and dispatch events themselves.
Vista and later provide the SleepConditionVariableCS() function for this.
Since SDL_syscond_srw.c doesn't require SRW locks anymore, rename it to
SDL_syscond_cv.c which better reflects the implementation of condition
variables rather than the implementation of mutexes.
Fixes#4051.
b08b1bde introduced a subtle bug. Despite not using D-Bus types directly,
the code used the SDL_USE_LIBDBUS definition set by SDL_dbus.h to conditionally
compile calls SDL_DBus_ScreensaverTickle() and SDL_DBus_ScreensaverInhibit().
As a result, it still compiled without SDL_dbus.h included, but screensaver
suspension silently failed to work.
The D-Bus stuff could probably use some tweaks to be harder to accidentally
break, but for now just restore the header includes.
Not only is it more efficient to batch process pending events, it is
necessary for correctness with the Win32 backend. WIN_PumpEvents() runs
periodic updates of the cursor clip region and disambiguation of
left and right shift keys in addition to standard event processing.
We can be in a situation where we receive a win32 hook callback on the same
thread that is currently waiting. In that case, we do still need to trigger
a wakeup when an event is pushed because the hook itself won't necessarily
do that (depending on what we return from the hook).
In some cases, it can be useful to have the KMSDRM backend even if it cannot
be used for rendering. An app may want to use SDL for input processing while
using another rendering API (such as an MMAL overlay on Raspberry Pi) or
using its own code to render to DRM overlays that SDL doesn't support.
This also moves the check for DRM master to an earlier point where we can fail
initialization of the backend, rather than allowing the backend to initialize
then failing the creation of a window later.
Unlike Mutter and Sway, KWin actually checks the serial passed in
wl_pointer_set_cursor(). The serial provided is supposed to be the
serial of the pointer enter event, but We were always passing 0.
This caused KWin to drop our requests to hide the cursor.
Thanks to the KDE folks for spotting this in my debug logs.
Fixes#3576
When SleepConditionVariableSRW() releases the SRW lock internally, it causes
our SDL_mutex_srw state to become inconsistent. The lock is unowned yet inside,
the owner is still the sleeping thread and more importantly the owner count is
still 1.
The next time someone acquires the lock, they will bump the owner count from 1
to 2. At that point, the lock is hosed. From the internal lock state, it looks
to us like that owner has acquired the lock recursively, even though they have
not. When they call SDL_UnlockMutex(), it will see the owner count > 0 and not
call ReleaseSRWLockExclusive().
Now when someone calls SDL_CondSignal(), SleepConditionVariableSRW() will start
the wakeup process by attempting to re-acquire the SRW lock. This will deadlock
because the lock was never released after the other thread had used it. The
thread waiting on the condition variable will never be able to wake up, even if
the SDL_CondWaitTimeout() function is used and the timeout expires.
There were two different implementations of IsBluetoothXboxOneController(), one
in SDL_hidapi_xbox360.c and one in SDL_hidapi_xboxone.c. The latter had been
updated to include USB_PRODUCT_XBOX_ONE_SERIES_X_BLUETOOTH while the former had
not.
This mismatch led to the Xbox Series X failing on macOS only. We have special
code for handling the 360Controller driver for macOS which requires us to use
the Xbox 360 driver for wired Xbox One controllers, and the SDL_hidapi_xbox360
version of IsBluetoothXboxOneController() was used to determine which devices
were wired.
In addition to adding the missing USB_PRODUCT_XBOX_ONE_SERIES_X_BLUETOOTH, this
change moves IsBluetoothXboxOneController() into a single shared function which
will ensure this bug won't happen again.
By default, we will minimize the window when we receive Alt+Tab with a
full-screen keyboard grabbed window to allow the user to escape the
full-screen application.
Some applications like remote desktop clients may want to handle Alt+Tab
themselves, so provide an opt-out via SDL_HINT_ALLOW_ALT_TAB_WHILE_GRABBED=0.
For keys that are already down when we install the keyboard hook, we need to
allow the WM_KEYUP/WM_SYSKEYUP message to be processed normally. This ensures
that other applications see the key up, which prevents the key from being stuck
down from the perspective of other apps when our grab is released.
This adds SDL_SetWindowKeyboardGrab(), SDL_GetWindowKeyboardGrab(),
SDL_SetWindowMouseGrab(), SDL_GetWindowMouseGrab(), and new
SDL_WINDOW_KEYBOARD_GRABBED flag. It also updates the test harness to exercise
this functionality and makes a minor fix to X11 that I missed in
https://hg.libsdl.org/SDL/rev/02a2d609369b
To fit in with this new support, SDL_WINDOW_INPUT_CAPTURE has been renamed to
SDL_WINDOW_MOUSE_CAPTURE with the old name remaining as an alias for backwards
compatibility with older code.
We support both the org.freedesktop.ScreenSaver D-Bus API (same as the X11
backend) and the Wayland idle_inhibit_unstable_v1 protocol.
Some Wayland compositors only support one or the other, so we need both to
for broad compatibility.
This is implemented via a low-level keyboard hook. Unfortunately, this is
rather invasive, but it's how Microsoft recommends that it be done [0].
We want to do as little as possible in the hook, so we only intercept a few
crucial modifier keys there, while leaving other keys to the normal event
processing flow.
We will only install this hook if SDL_HINT_GRAB_KEYBOARD=1, which is not
the default. This will reduce any compatibility concerns to just the SDL
applications that explicitly ask for this behavior.
We also remove the hook when the grab is terminated to ensure that we're
not unnecessarily staying involved in key event processing when it's not
required anymore.
[0]: https://docs.microsoft.com/en-us/windows/win32/dxtecharts/disabling-shortcut-keys-in-games
Hiding the cursor doesn't appear to work reliably on GNOME when another window
steals mouse focus right as we call SDL_ShowCursor(SDL_DISABLE). This can happen
when the keyboard shortcut inhibition permission prompt appears in response to a
call to SDL_SetRelativeMouseMode() with SDL_HINT_GRAB_KEYBOARD=1. The result is
that the default cursor is stuck locked in position and visible on screen
indefinitely.
By redrawing the cursor on pointer focus enter, the cursor now disappears upon
the first mouse motion event. It's not perfect but it's way better than the
current behavior.
Existing SDL applications may not know about the need to set a specific
hint to enable rumble on PS5 controllers, even though they may already
set the equivalent SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE hint for PS4
controller rumble support.
Rather than requiring those developers update their apps, let's use the
SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE value as an indication of the behavior
they are expected for all PlayStation controllers.
__builtin_bswap32/64 were introduced in GCC 4.3. __builtin_bswap16 was
not available on x86 until GCC 4.8 due to a bug.
__builtin_bswap32/64 were introduced in Clang 2.6. __builtin_bswap16
was introduced in Clang 3.2.
_InterlockedExchange_rel() is required for correctness on ARM because
the _ReadWriteBarrier() macro is only a compiler memory barrier, not a
hardware memory barrier. Due to ARM's relaxed memory model, this means
the '*lock = 0' write may be observed before the operations inside the
lock, causing possible corruption of data protected by the lock.
_InterlockedExchange_acq() is more efficient on ARM because it avoids an
expensive full memory barrier that _InterlockedExchange() does.
This is unsafe because the event is auto-reset, therefore the call to
WaitForSingleObject() resets the event which GetOverlappedResult() will
try to wait on.
Even though the overlapped operation is guaranteed to be completed at
the point we call GetOverlappedResult(), it will still wait on the event
handle for a short time to trigger the reset for auto-reset events. This
amounts to roughly a 100 ms sleep each time GetOverlappedResult() is called
for a completed I/O with a non-signalled event.
In the context of HIDAPI, this extra sleep means that callers that loop
on hid_read_timeout() with timeout=0 will loop forever, since the 100 ms
sleep each iteration ensures ReadFile() will always have new data.
This can happen if the application has not yet processed SDL_JOYDEVICEADD when
the same joystick is removed. It may also happen if two joysticks are added
and the second joystick is removed before the first joystick's SDL_JOYDEVICEADD
has been processed by the application.
GetAsyncKeyState() and GetRawInputData() report the state of the physical
buttons without applying the user's primary/secondary mouse button swap
preference. Swap the buttons returned from these functions, so we expose a
consistent view of the buttons to SDL callers. This new behavior also matches
the behavior of macOS and X11 backends.
See the Remarks section of the GetAsyncKeyState() function on MSDN.
We should only perform the VK_LEFT, VK_UP, etc. mapping if none of the other
special mappings apply. This allows the scancode normalization for the number
pad to take place as intended.
SDL_cocoametalview was consuming the first click rather than passing it
through to the SDLView underneath which overrides [NSView acceptsFirstMouse]
based on the user's SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH preference.
It currently behaves like a locking key which is pressed
when Caps Lock is enabled and released when disabled. This
means that apps that trigger events on Caps Lock key down will
only fire these events every other time Caps Lock is pressed.
There are a number of poorly behaved HID devices that time out on attempts to
read various strings. Rather than end up on an endless treadmill of blacklisting
broken devices, reduce our risk by only querying devices that are gamepads.
SDL_hidapijoystick.c already checks these same usages, so we shouldn't
exclude any working HID devices (caveat below).
This also makes HidP_GetPreparsedData() and HidP_GetCaps() failure skip
the device entirely, but that seems desired. If a device can't even return basic
top-level collection data properly, we want nothing to do with that broken device.
If we do find devices that work with HIDAPI joystick and fail these calls, we can
add an exception via VID+PID matching.
Prior to this fix, we would hit the existing_instance >= 0 case and move the joystick
again to a different index than the one requested by the caller. It also breaks the assumption
that a SDL_JoystickID is only present in SDL_joystick_players at one location.
The function we currently use, IOHIDDeviceRegisterRemovalCallback(), often
fails on Catalina with a "__CFRunLoopModeFindSourceForMachPort returned NULL"
error message. Once a removal callback is missed, we will eventually crash when
the joystick is closed attempting to use the invalid IOHIDDeviceRef.
https://forums.developer.apple.com/thread/124444
Windows generates fake raw mouse events for touchscreens for compatibility
with legacy apps that predate touch support in Windows. We already handle
touch events explicitly, so drop the synthetic events to avoid duplicates.