Update SDL to 2.28.4

This commit is contained in:
Bloodknight 2023-10-16 16:51:30 +01:00
parent 4fb67ed618
commit 402f7aff99
182 changed files with 2763 additions and 222042 deletions

View file

@ -631,9 +631,9 @@ SDL_bool SDL_IsTablet(void)
#if defined(__WIN32__)
#if (!defined(HAVE_LIBC) || defined(__WATCOMC__)) && !defined(SDL_STATIC_LIB)
/* Need to include DllMain() on Watcom C for some reason.. */
/* FIXME: Still need to include DllMain() on Watcom C ? */
BOOL APIENTRY _DllMainCRTStartup(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
BOOL APIENTRY MINGW32_FORCEALIGN _DllMainCRTStartup(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH:

View file

@ -42,7 +42,15 @@
#endif
#if defined(__EMSCRIPTEN__)
#include <emscripten.h>
#include <emscripten.h>
/* older Emscriptens don't have this, but we need to for wasm64 compatibility. */
#ifndef MAIN_THREAD_EM_ASM_PTR
#ifdef __wasm64__
#error You need to upgrade your Emscripten compiler to support wasm64
#else
#define MAIN_THREAD_EM_ASM_PTR MAIN_THREAD_EM_ASM_INT
#endif
#endif
#endif
/* The size of the stack buffer to use for rendering assert messages. */
@ -251,7 +259,7 @@ static SDL_assert_state SDLCALL SDL_PromptAssertion(const SDL_assert_data *data,
for (;;) {
SDL_bool okay = SDL_TRUE;
/* *INDENT-OFF* */ /* clang-format off */
char *buf = (char *) EM_ASM_INT({
char *buf = (char *) MAIN_THREAD_EM_ASM_PTR({
var str =
UTF8ToString($0) + '\n\n' +
'Abort/Retry/Ignore/AlwaysIgnore? [ariA] :';

View file

@ -197,6 +197,8 @@ static void EMSCRIPTENAUDIO_CloseDevice(_THIS)
#endif
}
EM_JS_DEPS(sdlaudio, "$autoResumeAudioContext,$dynCall");
static int EMSCRIPTENAUDIO_OpenDevice(_THIS, const char *devname)
{
SDL_AudioFormat test_format;

View file

@ -30,17 +30,12 @@
#include "../SDL_audio_c.h"
#include "SDL_os2audio.h"
/*
void lockIncr(volatile int *piVal);
#pragma aux lockIncr = \
"lock add [eax], 1 "\
parm [eax];
void lockDecr(volatile int *piVal);
#pragma aux lockDecr = \
"lock sub [eax], 1 "\
parm [eax];
*/
static PMCI_MIX_BUFFER _getNextBuffer(SDL_PrivateAudioData *pAData, PMCI_MIX_BUFFER pBuffer)
{
PMCI_MIX_BUFFER pFirstBuffer = &pAData->aMixBuffers[0];
PMCI_MIX_BUFFER pLastBuffer = &pAData->aMixBuffers[pAData->cMixBuffers -1];
return (pBuffer == pLastBuffer ? pFirstBuffer : pBuffer+1);
}
static ULONG _getEnvULong(const char *name, ULONG ulMax, ULONG ulDefault)
{
@ -64,7 +59,7 @@ static int _MCIError(const char *func, ULONG ulResult)
static void _mixIOError(const char *function, ULONG ulRC)
{
debug_os2("%s() - failed, rc = 0x%X (%s)",
debug_os2("%s() - failed, rc = 0x%lX (%s)",
function, ulRC,
(ulRC == MCIERR_INVALID_MODE) ? "Mixer mode does not match request" :
(ulRC == MCIERR_INVALID_BUFFER) ? "Caller sent an invalid buffer" : "unknown");
@ -73,18 +68,33 @@ static void _mixIOError(const char *function, ULONG ulRC)
static LONG APIENTRY cbAudioWriteEvent(ULONG ulStatus, PMCI_MIX_BUFFER pBuffer,
ULONG ulFlags)
{
SDL_PrivateAudioData *pAData = (SDL_PrivateAudioData *)pBuffer->ulUserParm;
SDL_AudioDevice *_this = (SDL_AudioDevice *)pBuffer->ulUserParm;
SDL_PrivateAudioData *pAData = (SDL_PrivateAudioData *)_this->hidden;
ULONG ulRC;
if (ulFlags != MIX_WRITE_COMPLETE) {
debug_os2("flags = 0x%X", ulFlags);
debug_os2("cbAudioWriteEvent: ulStatus = %lu, pBuffer = %p, ulFlags = %#lX",ulStatus,pBuffer,ulFlags);
if (pAData->ulState == 2)
{
return 0;
}
if (ulFlags != MIX_WRITE_COMPLETE) {
debug_os2("flags = 0x%lX", ulFlags);
return 0;
}
pAData->pDrainBuffer = pBuffer;
ulRC = pAData->stMCIMixSetup.pmixWrite(pAData->stMCIMixSetup.ulMixHandle,
pAData->pDrainBuffer, 1);
if (ulRC != MCIERR_SUCCESS) {
_mixIOError("pmixWrite", ulRC);
return 0;
}
/*lockDecr((int *)&pAData->ulQueuedBuf);*/
ulRC = DosPostEventSem(pAData->hevBuf);
if (ulRC != NO_ERROR && ulRC != ERROR_ALREADY_POSTED) {
debug_os2("DosPostEventSem(), rc = %u", ulRC);
debug_os2("DosPostEventSem(), rc = %lu", ulRC);
}
return 1; /* return value doesn't seem to matter. */
@ -93,19 +103,36 @@ static LONG APIENTRY cbAudioWriteEvent(ULONG ulStatus, PMCI_MIX_BUFFER pBuffer,
static LONG APIENTRY cbAudioReadEvent(ULONG ulStatus, PMCI_MIX_BUFFER pBuffer,
ULONG ulFlags)
{
SDL_PrivateAudioData *pAData = (SDL_PrivateAudioData *)pBuffer->ulUserParm;
SDL_AudioDevice *_this = (SDL_AudioDevice *)pBuffer->ulUserParm;
SDL_PrivateAudioData *pAData = (SDL_PrivateAudioData *)_this->hidden;
ULONG ulRC;
if (ulFlags != MIX_READ_COMPLETE) {
debug_os2("flags = 0x%X", ulFlags);
debug_os2("cbAudioReadEvent: ulStatus = %lu, pBuffer = %p, ulFlags = %#lX",ulStatus,pBuffer,ulFlags);
if (pAData->ulState == 2)
{
return 0;
}
pAData->stMCIMixSetup.pmixRead(pAData->stMCIMixSetup.ulMixHandle, pBuffer, 1);
if (ulFlags != MIX_READ_COMPLETE) {
debug_os2("flags = 0x%lX", ulFlags);
return 0;
}
pAData->pFillBuffer = pBuffer;
if (pAData->pFillBuffer == pAData->aMixBuffers)
{
ulRC = pAData->stMCIMixSetup.pmixRead(pAData->stMCIMixSetup.ulMixHandle,
pAData->pFillBuffer, pAData->cMixBuffers);
if (ulRC != MCIERR_SUCCESS) {
_mixIOError("pmixRead", ulRC);
return 0;
}
}
ulRC = DosPostEventSem(pAData->hevBuf);
if (ulRC != NO_ERROR && ulRC != ERROR_ALREADY_POSTED) {
debug_os2("DosPostEventSem(), rc = %u", ulRC);
debug_os2("DosPostEventSem(), rc = %lu", ulRC);
}
return 1;
@ -120,31 +147,36 @@ static void OS2_DetectDevices(void)
MCI_SYSINFO_LOGDEVICE stLogDevice;
MCI_SYSINFO_PARMS stSysInfoParams;
ULONG ulRC;
ULONG ulHandle = 0;
ULONG ulNumber;
MCI_GETDEVCAPS_PARMS stDevCapsParams;
MCI_OPEN_PARMS stMCIOpen;
MCI_GENERIC_PARMS stMCIGenericParams;
SDL_memset(&stMCISysInfo, 0, sizeof(stMCISysInfo));
acBuf[0] = '\0';
stMCISysInfo.pszReturn = acBuf;
stMCISysInfo.ulRetSize = sizeof(acBuf);
stMCISysInfo.usDeviceType = MCI_DEVTYPE_AUDIO_AMPMIX;
ulRC = mciSendCommand(0, MCI_SYSINFO, MCI_WAIT | MCI_SYSINFO_QUANTITY,
&stMCISysInfo, 0);
if (ulRC != NO_ERROR) {
debug_os2("MCI_SYSINFO, MCI_SYSINFO_QUANTITY - failed, rc = 0x%X", ulRC);
if (LOUSHORT(ulRC) != MCIERR_SUCCESS) {
debug_os2("MCI_SYSINFO, MCI_SYSINFO_QUANTITY - failed, rc = 0x%hX", LOUSHORT(ulRC));
return;
}
ulDevicesNum = SDL_strtoul(stMCISysInfo.pszReturn, NULL, 10);
for (stSysInfoParams.ulNumber = 0; stSysInfoParams.ulNumber < ulDevicesNum;
stSysInfoParams.ulNumber++) {
for (ulNumber = 1; ulNumber <= ulDevicesNum;
ulNumber++) {
/* Get device install name. */
stSysInfoParams.ulNumber = ulNumber;
stSysInfoParams.pszReturn = acBuf;
stSysInfoParams.ulRetSize = sizeof(acBuf);
stSysInfoParams.usDeviceType = MCI_DEVTYPE_AUDIO_AMPMIX;
ulRC = mciSendCommand(0, MCI_SYSINFO, MCI_WAIT | MCI_SYSINFO_INSTALLNAME,
&stSysInfoParams, 0);
if (ulRC != NO_ERROR) {
debug_os2("MCI_SYSINFO, MCI_SYSINFO_INSTALLNAME - failed, rc = 0x%X", ulRC);
if (LOUSHORT(ulRC) != MCIERR_SUCCESS) {
debug_os2("MCI_SYSINFO, MCI_SYSINFO_INSTALLNAME - failed, rc = 0x%hX", LOUSHORT(ulRC));
continue;
}
@ -154,15 +186,45 @@ static void OS2_DetectDevices(void)
SDL_strlcpy(stLogDevice.szInstallName, stSysInfoParams.pszReturn, MAX_DEVICE_NAME);
ulRC = mciSendCommand(0, MCI_SYSINFO, MCI_WAIT | MCI_SYSINFO_ITEM,
&stSysInfoParams, 0);
if (ulRC != NO_ERROR) {
debug_os2("MCI_SYSINFO, MCI_SYSINFO_ITEM - failed, rc = 0x%X", ulRC);
if (LOUSHORT(ulRC) != MCIERR_SUCCESS) {
debug_os2("MCI_SYSINFO, MCI_SYSINFO_ITEM - failed, rc = 0x%hX", LOUSHORT(ulRC));
continue;
}
ulHandle++;
SDL_AddAudioDevice(0, stLogDevice.szProductInfo, NULL, (void *)(ulHandle));
ulHandle++;
SDL_AddAudioDevice(1, stLogDevice.szProductInfo, NULL, (void *)(ulHandle));
SDL_AddAudioDevice(0, stLogDevice.szProductInfo, NULL, (void *)ulNumber);
/* Open audio device for querying its capabilities */
/* at this point we HAVE TO OPEN the waveaudio device and not the ampmix device */
/* because only the waveaudio device (tied to the ampmix device) supports querying for playback/record capability */
SDL_memset(&stMCIOpen, 0, sizeof(stMCIOpen));
stMCIOpen.pszDeviceType = (PSZ)MAKEULONG(MCI_DEVTYPE_WAVEFORM_AUDIO,LOUSHORT(ulNumber));
ulRC = mciSendCommand(0, MCI_OPEN,MCI_WAIT | MCI_OPEN_TYPE_ID | MCI_OPEN_SHAREABLE,&stMCIOpen, 0);
if (LOUSHORT(ulRC) != MCIERR_SUCCESS) {
debug_os2("MCI_OPEN (getDevCaps) - failed");
continue;
}
/* check for recording capability */
SDL_memset(&stDevCapsParams, 0, sizeof(stDevCapsParams));
stDevCapsParams.ulItem = MCI_GETDEVCAPS_CAN_RECORD;
ulRC = mciSendCommand(stMCIOpen.usDeviceID, MCI_GETDEVCAPS, MCI_WAIT | MCI_GETDEVCAPS_ITEM,
&stDevCapsParams, 0);
if (LOUSHORT(ulRC) != MCIERR_SUCCESS) {
debug_os2("MCI_GETDEVCAPS, MCI_GETDEVCAPS_ITEM - failed, rc = 0x%hX", LOUSHORT(ulRC));
}
else {
if (stDevCapsParams.ulReturn) {
SDL_AddAudioDevice(1, stLogDevice.szProductInfo, NULL, (void *)(ulNumber | 0x80000000));
}
}
/* close the audio device, we are done querying its capabilities */
SDL_memset(&stMCIGenericParams, 0, sizeof(stMCIGenericParams));
ulRC = mciSendCommand(stMCIOpen.usDeviceID, MCI_CLOSE, MCI_WAIT,
&stMCIGenericParams, 0);
if (LOUSHORT(ulRC) != MCIERR_SUCCESS) {
debug_os2("MCI_CLOSE (getDevCaps) - failed");
}
}
}
@ -171,52 +233,145 @@ static void OS2_WaitDevice(_THIS)
SDL_PrivateAudioData *pAData = (SDL_PrivateAudioData *)_this->hidden;
ULONG ulRC;
debug_os2("Enter");
/* Wait for an audio chunk to finish */
ulRC = DosWaitEventSem(pAData->hevBuf, 5000);
if (ulRC != NO_ERROR) {
debug_os2("DosWaitEventSem(), rc = %u", ulRC);
debug_os2("DosWaitEventSem(), rc = %lu", ulRC);
}
}
static Uint8 *OS2_GetDeviceBuf(_THIS)
{
SDL_PrivateAudioData *pAData = (SDL_PrivateAudioData *)_this->hidden;
return (Uint8 *) pAData->aMixBuffers[pAData->ulNextBuf].pBuffer;
debug_os2("Enter");
return (Uint8 *) pAData->pFillBuffer->pBuffer;
}
static void OS2_PlayDevice(_THIS)
{
SDL_PrivateAudioData *pAData = (SDL_PrivateAudioData *)_this->hidden;
ULONG ulRC;
PMCI_MIX_BUFFER pMixBuffer = &pAData->aMixBuffers[pAData->ulNextBuf];
PMCI_MIX_BUFFER pMixBuffer = NULL;
/* Queue it up */
/*lockIncr((int *)&pAData->ulQueuedBuf);*/
ulRC = pAData->stMCIMixSetup.pmixWrite(pAData->stMCIMixSetup.ulMixHandle,
pMixBuffer, 1);
if (ulRC != MCIERR_SUCCESS) {
_mixIOError("pmixWrite", ulRC);
} else {
pAData->ulNextBuf = (pAData->ulNextBuf + 1) % pAData->cMixBuffers;
debug_os2("Enter");
pMixBuffer = pAData->pDrainBuffer;
pAData->pFillBuffer = _getNextBuffer(pAData, pAData->pFillBuffer);
if (!pAData->ulState && pAData->pFillBuffer != pMixBuffer)
{
/*
* this buffer was filled but we have not yet filled all buffers
* so just signal event sem so that OS2_WaitDevice does not need
* to block
*/
ulRC = DosPostEventSem(pAData->hevBuf);
}
if (!pAData->ulState && (pAData->pFillBuffer == pMixBuffer) )
{
debug_os2("!hasStarted");
pAData->ulState = 1;
/* Write buffers to kick off the amp mixer */
ulRC = pAData->stMCIMixSetup.pmixWrite(pAData->stMCIMixSetup.ulMixHandle,
pMixBuffer, pAData->cMixBuffers);
if (ulRC != MCIERR_SUCCESS) {
_mixIOError("pmixWrite", ulRC);
}
}
}
static int OS2_CaptureFromDevice(_THIS,void *buffer,int buflen)
{
SDL_PrivateAudioData *pAData = (SDL_PrivateAudioData *)_this->hidden;
ULONG ulRC;
PMCI_MIX_BUFFER pMixBuffer = NULL;
int len = 0;
if (!pAData->ulState)
{
pAData->ulState = 1;
ulRC = pAData->stMCIMixSetup.pmixRead(pAData->stMCIMixSetup.ulMixHandle,
pAData->aMixBuffers, pAData->cMixBuffers);
if (ulRC != MCIERR_SUCCESS) {
_mixIOError("pmixRead", ulRC);
return -1;
}
}
/* Wait for an audio chunk to finish */
ulRC = DosWaitEventSem(pAData->hevBuf, 5000);
if (ulRC != NO_ERROR)
{
debug_os2("DosWaitEventSem(), rc = %lu", ulRC);
return -1;
}
pMixBuffer = pAData->pDrainBuffer;
len = SDL_min((int)pMixBuffer->ulBufferLength, buflen);
SDL_memcpy(buffer,pMixBuffer->pBuffer, len);
pAData->pDrainBuffer = _getNextBuffer(pAData, pMixBuffer);
debug_os2("buflen = %u, ulBufferLength = %lu",buflen,pMixBuffer->ulBufferLength);
return len;
}
static void OS2_FlushCapture(_THIS)
{
SDL_PrivateAudioData *pAData = (SDL_PrivateAudioData *)_this->hidden;
ULONG ulIdx;
debug_os2("Enter");
/* Fill all device buffers with data */
for (ulIdx = 0; ulIdx < pAData->cMixBuffers; ulIdx++) {
pAData->aMixBuffers[ulIdx].ulFlags = 0;
pAData->aMixBuffers[ulIdx].ulBufferLength = _this->spec.size;
pAData->aMixBuffers[ulIdx].ulUserParm = (ULONG)_this;
SDL_memset(((PMCI_MIX_BUFFER)pAData->aMixBuffers)[ulIdx].pBuffer,
_this->spec.silence, _this->spec.size);
}
pAData->pFillBuffer = pAData->aMixBuffers;
pAData->pDrainBuffer = pAData->aMixBuffers;
}
static void OS2_CloseDevice(_THIS)
{
SDL_PrivateAudioData *pAData = (SDL_PrivateAudioData *)_this->hidden;
MCI_GENERIC_PARMS sMCIGenericParms;
ULONG ulRC;
debug_os2("Enter");
if (pAData == NULL)
return;
pAData->ulState = 2;
/* Close up audio */
if (pAData->usDeviceId != (USHORT)~0) { /* Device is open. */
SDL_zero(sMCIGenericParms);
ulRC = mciSendCommand(pAData->usDeviceId, MCI_STOP,
MCI_WAIT,
&sMCIGenericParms, 0);
if (LOUSHORT(ulRC) != MCIERR_SUCCESS) {
debug_os2("MCI_STOP - failed" );
}
if (pAData->stMCIMixSetup.ulBitsPerSample != 0) { /* Mixer was initialized. */
ulRC = mciSendCommand(pAData->usDeviceId, MCI_MIXSETUP,
MCI_WAIT | MCI_MIXSETUP_DEINIT,
&pAData->stMCIMixSetup, 0);
if (ulRC != MCIERR_SUCCESS) {
if (LOUSHORT(ulRC) != MCIERR_SUCCESS) {
debug_os2("MCI_MIXSETUP, MCI_MIXSETUP_DEINIT - failed");
}
}
@ -230,14 +385,14 @@ static void OS2_CloseDevice(_THIS)
ulRC = mciSendCommand(pAData->usDeviceId, MCI_BUFFER,
MCI_WAIT | MCI_DEALLOCATE_MEMORY, &stMCIBuffer, 0);
if (ulRC != MCIERR_SUCCESS) {
if (LOUSHORT(ulRC) != MCIERR_SUCCESS) {
debug_os2("MCI_BUFFER, MCI_DEALLOCATE_MEMORY - failed");
}
}
ulRC = mciSendCommand(pAData->usDeviceId, MCI_CLOSE, MCI_WAIT,
&sMCIGenericParms, 0);
if (ulRC != MCIERR_SUCCESS) {
if (LOUSHORT(ulRC) != MCIERR_SUCCESS) {
debug_os2("MCI_CLOSE - failed");
}
}
@ -257,6 +412,7 @@ static int OS2_OpenDevice(_THIS, const char *devname)
ULONG ulRC;
ULONG ulIdx;
BOOL new_freq;
ULONG ulHandle = (ULONG)_this->handle;
SDL_bool iscapture = _this->iscapture;
new_freq = FALSE;
@ -279,20 +435,21 @@ static int OS2_OpenDevice(_THIS, const char *devname)
ulRC = DosCreateEventSem(NULL, &pAData->hevBuf, DCE_AUTORESET, TRUE);
if (ulRC != NO_ERROR) {
debug_os2("DosCreateEventSem() failed, rc = %u", ulRC);
debug_os2("DosCreateEventSem() failed, rc = %lu", ulRC);
return -1;
}
/* Open audio device */
stMCIAmpOpen.usDeviceID = (_this->handle != NULL) ? ((ULONG)_this->handle - 1) : 0;
stMCIAmpOpen.pszDeviceType = (PSZ)MCI_DEVTYPE_AUDIO_AMPMIX;
stMCIAmpOpen.usDeviceID = 0;
stMCIAmpOpen.pszDeviceType = (PSZ)MAKEULONG(MCI_DEVTYPE_AUDIO_AMPMIX,LOUSHORT(ulHandle));
ulRC = mciSendCommand(0, MCI_OPEN,
(_getEnvULong("SDL_AUDIO_SHARE", 1, 0) != 0)?
MCI_WAIT | MCI_OPEN_TYPE_ID | MCI_OPEN_SHAREABLE :
MCI_WAIT | MCI_OPEN_TYPE_ID,
&stMCIAmpOpen, 0);
if (ulRC != MCIERR_SUCCESS) {
stMCIAmpOpen.usDeviceID = (USHORT)~0;
if (LOUSHORT(ulRC) != MCIERR_SUCCESS) {
DosCloseEventSem(pAData->hevBuf);
pAData->usDeviceId = (USHORT)~0;
return _MCIError("MCI_OPEN", ulRC);
}
pAData->usDeviceId = stMCIAmpOpen.usDeviceID;
@ -355,7 +512,7 @@ static int OS2_OpenDevice(_THIS, const char *devname)
ulRC = mciSendCommand(pAData->usDeviceId, MCI_MIXSETUP,
MCI_WAIT | MCI_MIXSETUP_INIT, &pAData->stMCIMixSetup, 0);
if (ulRC != MCIERR_SUCCESS && _this->spec.freq > 44100) {
if (LOUSHORT(ulRC) != MCIERR_SUCCESS && _this->spec.freq > 44100) {
new_freq = TRUE;
pAData->stMCIMixSetup.ulSamplesPerSec = 44100;
_this->spec.freq = 44100;
@ -363,7 +520,7 @@ static int OS2_OpenDevice(_THIS, const char *devname)
MCI_WAIT | MCI_MIXSETUP_INIT, &pAData->stMCIMixSetup, 0);
}
debug_os2("Setup mixer [BPS: %u, Freq.: %u, Channels: %u]: %s",
debug_os2("Setup mixer [BPS: %lu, Freq.: %lu, Channels: %lu]: %s",
pAData->stMCIMixSetup.ulBitsPerSample,
pAData->stMCIMixSetup.ulSamplesPerSec,
pAData->stMCIMixSetup.ulChannels,
@ -394,29 +551,25 @@ static int OS2_OpenDevice(_THIS, const char *devname)
ulRC = mciSendCommand(pAData->usDeviceId, MCI_BUFFER,
MCI_WAIT | MCI_ALLOCATE_MEMORY, &stMCIBuffer, 0);
if (ulRC != MCIERR_SUCCESS) {
if (LOUSHORT(ulRC) != MCIERR_SUCCESS) {
return _MCIError("MCI_BUFFER", ulRC);
}
pAData->cMixBuffers = stMCIBuffer.ulNumBuffers;
_this->spec.size = stMCIBuffer.ulBufferSize;
debug_os2("%s, number of mix buffers: %lu",iscapture ? "capture": "play",pAData->cMixBuffers);
/* Fill all device buffers with data */
for (ulIdx = 0; ulIdx < stMCIBuffer.ulNumBuffers; ulIdx++) {
pAData->aMixBuffers[ulIdx].ulFlags = 0;
pAData->aMixBuffers[ulIdx].ulBufferLength = stMCIBuffer.ulBufferSize;
pAData->aMixBuffers[ulIdx].ulUserParm = (ULONG)pAData;
pAData->aMixBuffers[ulIdx].ulUserParm = (ULONG)_this;
SDL_memset(((PMCI_MIX_BUFFER)stMCIBuffer.pBufList)[ulIdx].pBuffer,
_this->spec.silence, stMCIBuffer.ulBufferSize);
}
/* Write buffers to kick off the amp mixer */
ulRC = pAData->stMCIMixSetup.pmixWrite(pAData->stMCIMixSetup.ulMixHandle,
pAData->aMixBuffers, 1);
if (ulRC != MCIERR_SUCCESS) {
_mixIOError("pmixWrite", ulRC);
return -1;
}
pAData->pFillBuffer = pAData->aMixBuffers;
pAData->pDrainBuffer = pAData->aMixBuffers;
return 0;
}
@ -431,12 +584,10 @@ static SDL_bool OS2_Init(SDL_AudioDriverImpl * impl)
impl->WaitDevice = OS2_WaitDevice;
impl->GetDeviceBuf = OS2_GetDeviceBuf;
impl->CloseDevice = OS2_CloseDevice;
/* TODO: IMPLEMENT CAPTURE SUPPORT:
impl->CaptureFromDevice = ;
impl->FlushCapture = ;
impl->CaptureFromDevice = OS2_CaptureFromDevice ;
impl->FlushCapture = OS2_FlushCapture;
impl->HasCaptureSupport = SDL_TRUE;
*/
return SDL_TRUE; /* this audio target is available. */
}

View file

@ -43,10 +43,11 @@ typedef struct SDL_PrivateAudioData
BYTE _pad[2];
MCI_MIXSETUP_PARMS stMCIMixSetup;
HEV hevBuf;
ULONG ulNextBuf;
PMCI_MIX_BUFFER pFillBuffer;
PMCI_MIX_BUFFER pDrainBuffer;
ULONG ulState;
ULONG cMixBuffers;
MCI_MIX_BUFFER aMixBuffers[NUM_BUFFERS];
/* ULONG ulQueuedBuf;*/
} SDL_PrivateAudioData;
#endif /* SDL_os2mm_h_ */

View file

@ -233,6 +233,7 @@ static Uint8 *QSA_GetDeviceBuf(_THIS)
static void QSA_CloseDevice(_THIS)
{
if (this->hidden->audio_handle != NULL) {
#if _NTO_VERSION < 710
if (!this->iscapture) {
/* Finish playing available samples */
snd_pcm_plugin_flush(this->hidden->audio_handle,
@ -242,6 +243,7 @@ static void QSA_CloseDevice(_THIS)
snd_pcm_plugin_flush(this->hidden->audio_handle,
SND_PCM_CHANNEL_CAPTURE);
}
#endif
snd_pcm_close(this->hidden->audio_handle);
}

View file

@ -401,7 +401,6 @@ void SDL_Fcitx_SetFocus(SDL_bool focused)
void SDL_Fcitx_Reset(void)
{
FcitxClientICCallMethod(&fcitx_client, "Reset");
FcitxClientICCallMethod(&fcitx_client, "CloseIC");
}
SDL_bool SDL_Fcitx_ProcessKeyEvent(Uint32 keysym, Uint32 keycode, Uint8 state)

View file

@ -76,6 +76,19 @@
#define WINVER _WIN32_WINNT
#endif
/* See https://github.com/libsdl-org/SDL/pull/7607 */
/* force_align_arg_pointer attribute requires gcc >= 4.2.x. */
#if defined(__clang__)
#define HAVE_FORCE_ALIGN_ARG_POINTER
#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2))
#define HAVE_FORCE_ALIGN_ARG_POINTER
#endif
#if defined(__GNUC__) && defined(__i386__) && defined(HAVE_FORCE_ALIGN_ARG_POINTER)
#define MINGW32_FORCEALIGN __attribute__((force_align_arg_pointer))
#else
#define MINGW32_FORCEALIGN
#endif
#include <windows.h>
#include <basetyps.h> /* for REFIID with broken mingw.org headers */

View file

@ -34,7 +34,8 @@
/* Global keyboard information */
#define KEYBOARD_HARDWARE 0x01
#define KEYBOARD_AUTORELEASE 0x02
#define KEYBOARD_VIRTUAL 0x02
#define KEYBOARD_AUTORELEASE 0x04
typedef struct SDL_Keyboard SDL_Keyboard;
@ -47,6 +48,7 @@ struct SDL_Keyboard
Uint8 keystate[SDL_NUM_SCANCODES];
SDL_Keycode keymap[SDL_NUM_SCANCODES];
SDL_bool autorelease_pending;
Uint32 hardware_timestamp;
};
static SDL_Keyboard SDL_keyboard;
@ -865,7 +867,9 @@ static int SDL_SendKeyboardKeyInternal(Uint8 source, Uint8 state, SDL_Scancode s
keycode = keyboard->keymap[scancode];
}
if (source == KEYBOARD_AUTORELEASE) {
if (source == KEYBOARD_HARDWARE) {
keyboard->hardware_timestamp = SDL_GetTicks();
} else if (source == KEYBOARD_AUTORELEASE) {
keyboard->autorelease_pending = SDL_TRUE;
}
@ -965,20 +969,25 @@ int SDL_SendKeyboardUnicodeKey(Uint32 ch)
if (mod & KMOD_SHIFT) {
/* If the character uses shift, press shift down */
SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_LSHIFT);
SDL_SendKeyboardKeyInternal(KEYBOARD_VIRTUAL, SDL_PRESSED, SDL_SCANCODE_LSHIFT, SDLK_UNKNOWN);
}
/* Send a keydown and keyup for the character */
SDL_SendKeyboardKey(SDL_PRESSED, code);
SDL_SendKeyboardKey(SDL_RELEASED, code);
SDL_SendKeyboardKeyInternal(KEYBOARD_VIRTUAL, SDL_PRESSED, code, SDLK_UNKNOWN);
SDL_SendKeyboardKeyInternal(KEYBOARD_VIRTUAL, SDL_RELEASED, code, SDLK_UNKNOWN);
if (mod & KMOD_SHIFT) {
/* If the character uses shift, release shift */
SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_LSHIFT);
SDL_SendKeyboardKeyInternal(KEYBOARD_VIRTUAL, SDL_RELEASED, SDL_SCANCODE_LSHIFT, SDLK_UNKNOWN);
}
return 0;
}
int SDL_SendVirtualKeyboardKey(Uint8 state, SDL_Scancode scancode)
{
return SDL_SendKeyboardKeyInternal(KEYBOARD_VIRTUAL, state, scancode, SDLK_UNKNOWN);
}
int SDL_SendKeyboardKey(Uint8 state, SDL_Scancode scancode)
{
return SDL_SendKeyboardKeyInternal(KEYBOARD_HARDWARE, state, scancode, SDLK_UNKNOWN);
@ -1007,6 +1016,13 @@ void SDL_ReleaseAutoReleaseKeys(void)
}
keyboard->autorelease_pending = SDL_FALSE;
}
if (keyboard->hardware_timestamp) {
/* Keep hardware keyboard "active" for 250 ms */
if (SDL_TICKS_PASSED(SDL_GetTicks(), keyboard->hardware_timestamp + 250)) {
keyboard->hardware_timestamp = 0;
}
}
}
SDL_bool SDL_HardwareKeyboardKeyPressed(void)
@ -1019,7 +1035,8 @@ SDL_bool SDL_HardwareKeyboardKeyPressed(void)
return SDL_TRUE;
}
}
return SDL_FALSE;
return keyboard->hardware_timestamp ? SDL_TRUE : SDL_FALSE;
}
int SDL_SendKeyboardText(const char *text)

View file

@ -52,6 +52,9 @@ extern void SDL_SetKeyboardFocus(SDL_Window *window);
*/
extern int SDL_SendKeyboardUnicodeKey(Uint32 ch);
/* Send a key from a virtual key source, like an on-screen keyboard */
extern int SDL_SendVirtualKeyboardKey(Uint8 state, SDL_Scancode scancode);
/* Send a keyboard key event */
extern int SDL_SendKeyboardKey(Uint8 state, SDL_Scancode scancode);
extern int SDL_SendKeyboardKeyAutoRelease(SDL_Scancode scancode);

View file

@ -648,7 +648,7 @@ SDL_RWops *SDL_RWFromMem(void *mem, int size)
SDL_InvalidParamError("mem");
return rwops;
}
if (!size) {
if (size <= 0) {
SDL_InvalidParamError("size");
return rwops;
}
@ -675,7 +675,7 @@ SDL_RWops *SDL_RWFromConstMem(const void *mem, int size)
SDL_InvalidParamError("mem");
return rwops;
}
if (!size) {
if (size <= 0) {
SDL_InvalidParamError("size");
return rwops;
}

View file

@ -884,9 +884,9 @@ int HID_API_EXPORT hid_get_feature_report(hid_device *dev, unsigned char *data,
unsigned char report = data[0];
res = ioctl(dev->device_handle, HIDIOCGFEATURE(length), data);
if (res < 0)
perror("ioctl (GFEATURE)");
else if (dev->needs_ble_hack) {
if (res < 0) {
/* perror("ioctl (GFEATURE)"); */
} else if (dev->needs_ble_hack) {
/* Versions of BlueZ before 5.56 don't include the report in the data,
* and versions of BlueZ >= 5.56 include 2 copies of the report.
* We'll fix it so that there is a single copy of the report in both cases

View file

@ -586,6 +586,7 @@ static ControllerMapping_t *SDL_CreateMappingForHIDAPIController(SDL_JoystickGUI
switch (guid.data[15]) {
case k_eSwitchDeviceInfoControllerType_HVCLeft:
SDL_strlcat(mapping_string, "a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,rightshoulder:b10,start:b6,", sizeof(mapping_string));
break;
case k_eSwitchDeviceInfoControllerType_HVCRight:
SDL_strlcat(mapping_string, "a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,rightshoulder:b10,", sizeof(mapping_string));
break;

View file

@ -134,9 +134,7 @@ static const char *s_ControllerMappings[] = {
"03000000b80500000610000000000000,Elecom Gamepad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,",
"03000000852100000201000000000000,FF-GP1,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"030000000d0f00002700000000000000,FIGHTING STICK V3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
"03000000151900004000000000000000,Flydigi Vader 2,a:b27,b:b26,back:b19,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b23,leftstick:b17,lefttrigger:b21,leftx:a0,lefty:a1,misc1:b15,paddle1:b11,paddle2:b10,paddle3:b13,paddle4:b12,rightshoulder:b22,rightstick:b16,righttrigger:b20,rightx:a3,righty:a4,start:b18,x:b25,y:b24,", /* Bluetooth */
"03000000b40400001124000000000000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b14,paddle1:b4,paddle2:b5,paddle3:b16,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b2,y:b3,", /* Dongle */
"03000000b40400001224000000000000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b2,paddle1:b16,paddle2:b17,paddle3:b14,paddle4:b15,rightshoulder:b7,rightstick:b13,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,", /* Wired */
"03000000790000000600000000000000,G-Shark GS-GP702,crc:8e4f,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
"030000008f0e00000d31000000000000,GAMEPAD 3 TURBO,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"03000000300f00000b01000000000000,GGE909 Recoil Pad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,",
"03000000790000002201000000000000,Game Controller for PC,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
@ -416,9 +414,6 @@ static const char *s_ControllerMappings[] = {
"03000000a306000022f6000001030000,Cyborg V.3 Rumble Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,",
"030000000d0f00008400000000010000,Fighting Commander,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"030000000d0f00008500000000010000,Fighting Commander,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"03000000151900004000000001000000,Flydigi Vader 2,a:b14,b:b15,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b2,paddle2:b5,paddle3:b16,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b0,y:b1,", /* Bluetooth */
"03000000b40400001124000001040000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b14,paddle1:b2,paddle2:b5,paddle3:b16,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,", /* Dongle */
"03000000b40400001224000003030000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b2,paddle1:b16,paddle2:b17,paddle3:b14,paddle4:b15,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,", /* Wired */
"03000000ac0500001a06000002020000,GameSir-T3 2.02,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
"0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
"03000000c01100000140000000010000,GameStop PS4 Fun Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
@ -610,9 +605,6 @@ static const char *s_ControllerMappings[] = {
"050000004c050000f20d000000010000,DualSense Edge Wireless Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"030000006f0e00003001000001010000,EA Sports PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"03000000790000001100000010010000,Elecom Gamepad,crc:e86c,a:b2,b:b3,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b0,y:b1,",
"03000000b40400001124000011010000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b14,paddle1:b2,paddle2:b5,paddle3:b16,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,", /* Dongle */
"03000000b40400001224000011010000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b2,paddle1:b16,paddle2:b17,paddle3:b14,paddle4:b15,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,", /* Wired */
"05000000151900004000000001000000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b14,paddle1:b2,paddle2:b5,paddle3:b16,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,", /* Bluetooth */
"0300000079000000d418000000010000,GPD Win 2 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"0500000047532067616d657061640000,GS Gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
"03000000341a000005f7000010010000,GameCube {HuiJia USB box},a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,",
@ -824,6 +816,7 @@ static const char *s_ControllerMappings[] = {
"05000000de2800000212000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,",
"05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,",
"05000000de2800000611000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,",
"03000000de2800000512000011010000,Steam Deck,a:b3,b:b4,back:b11,dpdown:b17,dpleft:b18,dpright:b19,dpup:b16,guide:b13,leftshoulder:b7,leftstick:b14,lefttrigger:a9,leftx:a0,lefty:a1,misc1:b2,paddle1:b21,paddle2:b20,paddle3:b23,paddle4:b22,rightshoulder:b8,rightstick:b15,righttrigger:a8,rightx:a2,righty:a3,start:b12,x:b5,y:b6,",
"03000000de280000ff11000001000000,Steam Virtual Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"0500000011010000311400001b010000,SteelSeries Stratus Duo,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b32,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
"05000000110100001914000009010000,SteelSeries Stratus XL,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b18,leftshoulder:b6,leftstick:b13,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:+a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
@ -856,6 +849,8 @@ static const char *s_ControllerMappings[] = {
"0000000058626f782033363020576900,Xbox 360 Wireless Controller,a:b0,b:b1,back:b14,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,guide:b7,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,",
"030000005e040000a102000014010000,Xbox 360 Wireless Receiver (XBOX),a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"0000000058626f782047616d65706100,Xbox Gamepad (userspace driver),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,",
"050000005e040000e002000003090000,Xbox One Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"050000005e040000fd02000003090000,Xbox One Wireless Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,guide:b16,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
"05000000172700004431000029010000,XiaoMi Game Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b6,leftstick:b13,lefttrigger:a7,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,",
"03000000c0160000e105000010010000,Xin-Mo Dual Arcade,crc:82d5,a:b1,b:b2,back:b9,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b4,righttrigger:b5,start:b8,x:b0,y:b3,", /* Ultimate Atari Fight Stick */
"03000000120c0000100e000011010000,ZEROPLUS P4 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
@ -907,7 +902,6 @@ static const char *s_ControllerMappings[] = {
"05000000c82d000018900000ffff0f00,8BitDo Zero 2,a:b1,b:b0,back:b4,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"05000000c82d000030320000ffff0f00,8BitDo Zero 2,a:b0,b:b1,back:b4,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b2,y:b3,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"05000000c82d000030320000ffff0f00,8BitDo Zero 2,a:b1,b:b0,back:b4,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"05000000b404000011240000dfff3f00,Flydigi Vader 2,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,paddle1:b17,paddle2:b18,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
"05000000d6020000e5890000dfff3f80,GPD XD Plus,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a3,rightx:a4,righty:a5,start:b6,x:b2,y:b3,",
"0500000031366332860c44aadfff0f00,GS Gamepad,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b15,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b16,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
"05000000bc20000000550000ffff3f00,GameSir G3w,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",

View file

@ -1906,7 +1906,7 @@ void SDL_GetJoystickGUIDInfo(SDL_JoystickGUID guid, Uint16 *vendor, Uint16 *prod
if (crc16) {
*crc16 = SDL_SwapLE16(guid16[1]);
}
} else if (bus < ' ') {
} else if (bus < ' ' || bus == SDL_HARDWARE_BUS_VIRTUAL) {
/* This GUID fits the unknown VID/PID form:
* 16-bit bus
* 16-bit CRC16 of the joystick name (can be zero)
@ -2479,8 +2479,11 @@ static SDL_bool SDL_IsJoystickProductWheel(Uint32 vidpid)
MAKE_VIDPID(0x046d, 0xc262), /* Logitech G920 (active mode) */
MAKE_VIDPID(0x046d, 0xc268), /* Logitech PRO Racing Wheel (PC mode) */
MAKE_VIDPID(0x046d, 0xc269), /* Logitech PRO Racing Wheel (PS4/PS5 mode) */
MAKE_VIDPID(0x046d, 0xc272), /* Logitech PRO Racing Wheel for Xbox (PC mode) */
MAKE_VIDPID(0x046d, 0xc26d), /* Logitech G923 (Xbox) */
MAKE_VIDPID(0x046d, 0xc26e), /* Logitech G923 */
MAKE_VIDPID(0x046d, 0xc266), /* Logitech G923 for Playstation 4 and PC (PC mode) */
MAKE_VIDPID(0x046d, 0xc267), /* Logitech G923 for Playstation 4 and PC (PS4 mode)*/
MAKE_VIDPID(0x046d, 0xca03), /* Logitech Momo Racing */
MAKE_VIDPID(0x044f, 0xb65d), /* Thrustmaster Wheel FFB */
MAKE_VIDPID(0x044f, 0xb66d), /* Thrustmaster Wheel FFB */
@ -2492,6 +2495,17 @@ static SDL_bool SDL_IsJoystickProductWheel(Uint32 vidpid)
MAKE_VIDPID(0x044f, 0xb65e), /* Thrustmaster T500RS */
MAKE_VIDPID(0x044f, 0xb664), /* Thrustmaster TX (initial mode) */
MAKE_VIDPID(0x044f, 0xb669), /* Thrustmaster TX (active mode) */
MAKE_VIDPID(0x0483, 0x0522), /* Simagic Wheelbase (including M10, Alpha Mini, Alpha, Alpha U) */
MAKE_VIDPID(0x0eb7, 0x0001), /* Fanatec ClubSport Wheel Base V2 */
MAKE_VIDPID(0x0eb7, 0x0004), /* Fanatec ClubSport Wheel Base V2.5 */
MAKE_VIDPID(0x0eb7, 0x0005), /* Fanatec CSL Elite Wheel Base+ (PS4) */
MAKE_VIDPID(0x0eb7, 0x0006), /* Fanatec Podium Wheel Base DD1 */
MAKE_VIDPID(0x0eb7, 0x0007), /* Fanatec Podium Wheel Base DD2 */
MAKE_VIDPID(0x0eb7, 0x0011), /* Fanatec Forza Motorsport (CSR Wheel / CSR Elite Wheel) */
MAKE_VIDPID(0x0eb7, 0x0020), /* Fanatec generic wheel / CSL DD / GT DD Pro */
MAKE_VIDPID(0x0eb7, 0x0197), /* Fanatec Porsche Wheel (Turbo / GT3 RS / Turbo S / GT3 V2 / GT2) */
MAKE_VIDPID(0x0eb7, 0x038e), /* Fanatec ClubSport Wheel Base V1 */
MAKE_VIDPID(0x0eb7, 0x0e03), /* Fanatec CSL Elite Wheel Base */
MAKE_VIDPID(0x11ff, 0x0511), /* DragonRise Inc. Wired Wheel (initial mode) (also known as PXN V900 (PS3), Superdrive SV-750, or a Genesis Seaborg 400) */
};
int i;

View file

@ -320,81 +320,83 @@ static SDL_bool HIDAPI_DriverPS4_InitDevice(SDL_HIDAPI_Device *device)
SDL_Log("PS4 dongle = %s, bluetooth = %s\n", ctx->is_dongle ? "TRUE" : "FALSE", device->is_bluetooth ? "TRUE" : "FALSE");
#endif
size = ReadFeatureReport(device->dev, k_ePS4FeatureReportIdCapabilities, data, sizeof(data));
/* Get the device capabilities */
if (size == 48 && data[2] == 0x27) {
Uint8 capabilities = data[4];
Uint8 device_type = data[5];
Uint16 gyro_numerator = LOAD16(data[10], data[11]);
Uint16 gyro_denominator = LOAD16(data[12], data[13]);
Uint16 accel_numerator = LOAD16(data[14], data[15]);
Uint16 accel_denominator = LOAD16(data[16], data[17]);
#ifdef DEBUG_PS4_PROTOCOL
HIDAPI_DumpPacket("PS4 capabilities: size = %d", data, size);
#endif
if (capabilities & 0x02) {
ctx->sensors_supported = SDL_TRUE;
}
if (capabilities & 0x04) {
ctx->lightbar_supported = SDL_TRUE;
}
if (capabilities & 0x08) {
ctx->vibration_supported = SDL_TRUE;
}
if (capabilities & 0x40) {
ctx->touchpad_supported = SDL_TRUE;
}
switch (device_type) {
case 0x00:
joystick_type = SDL_JOYSTICK_TYPE_GAMECONTROLLER;
break;
case 0x01:
joystick_type = SDL_JOYSTICK_TYPE_GUITAR;
break;
case 0x02:
joystick_type = SDL_JOYSTICK_TYPE_DRUM_KIT;
break;
case 0x04:
joystick_type = SDL_JOYSTICK_TYPE_DANCE_PAD;
break;
case 0x06:
joystick_type = SDL_JOYSTICK_TYPE_WHEEL;
break;
case 0x07:
joystick_type = SDL_JOYSTICK_TYPE_ARCADE_STICK;
break;
case 0x08:
joystick_type = SDL_JOYSTICK_TYPE_FLIGHT_STICK;
break;
default:
joystick_type = SDL_JOYSTICK_TYPE_UNKNOWN;
break;
}
if (gyro_numerator && gyro_denominator) {
ctx->gyro_numerator = gyro_numerator;
ctx->gyro_denominator = gyro_denominator;
}
if (accel_numerator && accel_denominator) {
ctx->accel_numerator = accel_numerator;
ctx->accel_denominator = accel_denominator;
}
} else if (device->vendor_id == USB_VENDOR_SONY) {
if (device->vendor_id == USB_VENDOR_SONY) {
ctx->official_controller = SDL_TRUE;
ctx->sensors_supported = SDL_TRUE;
ctx->lightbar_supported = SDL_TRUE;
ctx->vibration_supported = SDL_TRUE;
ctx->touchpad_supported = SDL_TRUE;
} else if (device->vendor_id == USB_VENDOR_RAZER) {
/* The Razer Raiju doesn't respond to the detection protocol, but has a touchpad and vibration */
ctx->vibration_supported = SDL_TRUE;
ctx->touchpad_supported = SDL_TRUE;
} else {
size = ReadFeatureReport(device->dev, k_ePS4FeatureReportIdCapabilities, data, sizeof(data));
/* Get the device capabilities */
if (size == 48 && data[2] == 0x27) {
Uint8 capabilities = data[4];
Uint8 device_type = data[5];
Uint16 gyro_numerator = LOAD16(data[10], data[11]);
Uint16 gyro_denominator = LOAD16(data[12], data[13]);
Uint16 accel_numerator = LOAD16(data[14], data[15]);
Uint16 accel_denominator = LOAD16(data[16], data[17]);
if (device->product_id == USB_PRODUCT_RAZER_TOURNAMENT_EDITION_BLUETOOTH ||
device->product_id == USB_PRODUCT_RAZER_ULTIMATE_EDITION_BLUETOOTH) {
device->is_bluetooth = SDL_TRUE;
#ifdef DEBUG_PS4_PROTOCOL
HIDAPI_DumpPacket("PS4 capabilities: size = %d", data, size);
#endif
if (capabilities & 0x02) {
ctx->sensors_supported = SDL_TRUE;
}
if (capabilities & 0x04) {
ctx->lightbar_supported = SDL_TRUE;
}
if (capabilities & 0x08) {
ctx->vibration_supported = SDL_TRUE;
}
if (capabilities & 0x40) {
ctx->touchpad_supported = SDL_TRUE;
}
switch (device_type) {
case 0x00:
joystick_type = SDL_JOYSTICK_TYPE_GAMECONTROLLER;
break;
case 0x01:
joystick_type = SDL_JOYSTICK_TYPE_GUITAR;
break;
case 0x02:
joystick_type = SDL_JOYSTICK_TYPE_DRUM_KIT;
break;
case 0x04:
joystick_type = SDL_JOYSTICK_TYPE_DANCE_PAD;
break;
case 0x06:
joystick_type = SDL_JOYSTICK_TYPE_WHEEL;
break;
case 0x07:
joystick_type = SDL_JOYSTICK_TYPE_ARCADE_STICK;
break;
case 0x08:
joystick_type = SDL_JOYSTICK_TYPE_FLIGHT_STICK;
break;
default:
joystick_type = SDL_JOYSTICK_TYPE_UNKNOWN;
break;
}
if (gyro_numerator && gyro_denominator) {
ctx->gyro_numerator = gyro_numerator;
ctx->gyro_denominator = gyro_denominator;
}
if (accel_numerator && accel_denominator) {
ctx->accel_numerator = accel_numerator;
ctx->accel_denominator = accel_denominator;
}
} else if (device->vendor_id == USB_VENDOR_RAZER) {
/* The Razer Raiju doesn't respond to the detection protocol, but has a touchpad and vibration */
ctx->vibration_supported = SDL_TRUE;
ctx->touchpad_supported = SDL_TRUE;
if (device->product_id == USB_PRODUCT_RAZER_TOURNAMENT_EDITION_BLUETOOTH ||
device->product_id == USB_PRODUCT_RAZER_ULTIMATE_EDITION_BLUETOOTH) {
device->is_bluetooth = SDL_TRUE;
}
}
}
ctx->effects_supported = (ctx->lightbar_supported || ctx->vibration_supported);
@ -660,16 +662,25 @@ static int HIDAPI_DriverPS4_UpdateEffects(SDL_HIDAPI_Device *device)
static void HIDAPI_DriverPS4_TickleBluetooth(SDL_HIDAPI_Device *device)
{
/* This is just a dummy packet that should have no effect, since we don't set the CRC */
Uint8 data[78];
SDL_DriverPS4_Context *ctx = (SDL_DriverPS4_Context *)device->context;
SDL_zeroa(data);
if (ctx->enhanced_mode) {
/* This is just a dummy packet that should have no effect, since we don't set the CRC */
Uint8 data[78];
data[0] = k_EPS4ReportIdBluetoothEffects;
data[1] = 0xC0; /* Magic value HID + CRC */
SDL_zeroa(data);
if (SDL_HIDAPI_LockRumble() == 0) {
SDL_HIDAPI_SendRumbleAndUnlock(device, data, sizeof(data));
data[0] = k_EPS4ReportIdBluetoothEffects;
data[1] = 0xC0; /* Magic value HID + CRC */
if (SDL_HIDAPI_LockRumble() == 0) {
SDL_HIDAPI_SendRumbleAndUnlock(device, data, sizeof(data));
}
} else {
/* We can't even send an invalid effects packet, or it will put the controller in enhanced mode */
if (device->num_joysticks > 0) {
HIDAPI_JoystickDisconnected(device, device->joysticks[0]);
}
}
}

View file

@ -102,7 +102,7 @@ typedef struct
Uint8 rgucAccelX[2]; /* 21 */
Uint8 rgucAccelY[2]; /* 23 */
Uint8 rgucAccelZ[2]; /* 25 */
Uint8 rgucSensorTimestamp[4]; /* 27 - 32 bit little endian */
Uint8 rgucSensorTimestamp[4]; /* 27 - 16/32 bit little endian */
} PS5StatePacketCommon_t;
@ -154,7 +154,9 @@ typedef struct
Uint8 rgucAccelX[2]; /* 21 */
Uint8 rgucAccelY[2]; /* 23 */
Uint8 rgucAccelZ[2]; /* 25 */
Uint8 rgucSensorTimestamp[4]; /* 27 - 32 bit little endian */
Uint8 rgucSensorTimestamp[2]; /* 27 - 16 bit little endian */
Uint8 ucBatteryLevel; /* 29 */
Uint8 ucUnknown; /* 30 */
Uint8 ucTouchpadCounter1; /* 31 - high bit clear + counter */
Uint8 rgucTouchpadData1[3]; /* 32 - X/Y, 12 bits per axis */
Uint8 ucTouchpadCounter2; /* 35 - high bit clear + counter */
@ -421,7 +423,6 @@ static SDL_bool HIDAPI_DriverPS5_InitDevice(SDL_HIDAPI_Device *device)
}
}
size = ReadFeatureReport(device->dev, k_EPS5FeatureReportIdCapabilities, data, sizeof(data));
/* Get the device capabilities */
if (device->vendor_id == USB_VENDOR_SONY) {
ctx->sensors_supported = SDL_TRUE;
@ -429,61 +430,66 @@ static SDL_bool HIDAPI_DriverPS5_InitDevice(SDL_HIDAPI_Device *device)
ctx->vibration_supported = SDL_TRUE;
ctx->playerled_supported = SDL_TRUE;
ctx->touchpad_supported = SDL_TRUE;
} else if (size == 48 && data[2] == 0x28) {
Uint8 capabilities = data[4];
Uint8 capabilities2 = data[20];
Uint8 device_type = data[5];
} else {
/* Third party controller capability request */
size = ReadFeatureReport(device->dev, k_EPS5FeatureReportIdCapabilities, data, sizeof(data));
if (size == 48 && data[2] == 0x28) {
Uint8 capabilities = data[4];
Uint8 capabilities2 = data[20];
Uint8 device_type = data[5];
#ifdef DEBUG_PS5_PROTOCOL
HIDAPI_DumpPacket("PS5 capabilities: size = %d", data, size);
HIDAPI_DumpPacket("PS5 capabilities: size = %d", data, size);
#endif
if (capabilities & 0x02) {
if (capabilities & 0x02) {
ctx->sensors_supported = SDL_TRUE;
}
if (capabilities & 0x04) {
ctx->lightbar_supported = SDL_TRUE;
}
if (capabilities & 0x08) {
ctx->vibration_supported = SDL_TRUE;
}
if (capabilities & 0x40) {
ctx->touchpad_supported = SDL_TRUE;
}
if (capabilities2 & 0x80) {
ctx->playerled_supported = SDL_TRUE;
}
switch (device_type) {
case 0x00:
joystick_type = SDL_JOYSTICK_TYPE_GAMECONTROLLER;
break;
case 0x01:
joystick_type = SDL_JOYSTICK_TYPE_GUITAR;
break;
case 0x02:
joystick_type = SDL_JOYSTICK_TYPE_DRUM_KIT;
break;
case 0x06:
joystick_type = SDL_JOYSTICK_TYPE_WHEEL;
break;
case 0x07:
joystick_type = SDL_JOYSTICK_TYPE_ARCADE_STICK;
break;
case 0x08:
joystick_type = SDL_JOYSTICK_TYPE_FLIGHT_STICK;
break;
default:
joystick_type = SDL_JOYSTICK_TYPE_UNKNOWN;
break;
}
ctx->use_alternate_report = SDL_TRUE;
} else if (device->vendor_id == USB_VENDOR_RAZER &&
(device->product_id == USB_PRODUCT_RAZER_WOLVERINE_V2_PRO_PS5_WIRED ||
device->product_id == USB_PRODUCT_RAZER_WOLVERINE_V2_PRO_PS5_WIRELESS)) {
/* The Razer Wolverine V2 Pro doesn't respond to the detection protocol, but has a touchpad and sensors, but no vibration */
ctx->sensors_supported = SDL_TRUE;
}
if (capabilities & 0x04) {
ctx->lightbar_supported = SDL_TRUE;
}
if (capabilities & 0x08) {
ctx->vibration_supported = SDL_TRUE;
}
if (capabilities & 0x40) {
ctx->touchpad_supported = SDL_TRUE;
ctx->use_alternate_report = SDL_TRUE;
}
if (capabilities2 & 0x80) {
ctx->playerled_supported = SDL_TRUE;
}
switch (device_type) {
case 0x00:
joystick_type = SDL_JOYSTICK_TYPE_GAMECONTROLLER;
break;
case 0x01:
joystick_type = SDL_JOYSTICK_TYPE_GUITAR;
break;
case 0x02:
joystick_type = SDL_JOYSTICK_TYPE_DRUM_KIT;
break;
case 0x06:
joystick_type = SDL_JOYSTICK_TYPE_WHEEL;
break;
case 0x07:
joystick_type = SDL_JOYSTICK_TYPE_ARCADE_STICK;
break;
case 0x08:
joystick_type = SDL_JOYSTICK_TYPE_FLIGHT_STICK;
break;
default:
joystick_type = SDL_JOYSTICK_TYPE_UNKNOWN;
break;
}
ctx->use_alternate_report = SDL_TRUE;
} else if (device->vendor_id == USB_VENDOR_RAZER &&
(device->product_id == USB_PRODUCT_RAZER_WOLVERINE_V2_PRO_PS5_WIRED ||
device->product_id == USB_PRODUCT_RAZER_WOLVERINE_V2_PRO_PS5_WIRELESS)) {
/* The Razer Wolverine V2 Pro doesn't respond to the detection protocol, but has a touchpad and sensors, but no vibration */
ctx->sensors_supported = SDL_TRUE;
ctx->touchpad_supported = SDL_TRUE;
}
ctx->effects_supported = (ctx->lightbar_supported || ctx->vibration_supported || ctx->playerled_supported);
@ -717,7 +723,7 @@ static void HIDAPI_DriverPS5_CheckPendingLEDReset(SDL_HIDAPI_Device *device)
SDL_DriverPS5_Context *ctx = (SDL_DriverPS5_Context *)device->context;
SDL_bool led_reset_complete = SDL_FALSE;
if (ctx->sensors_supported) {
if (ctx->enhanced_mode && ctx->sensors_supported && !ctx->use_alternate_report) {
const PS5StatePacketCommon_t *packet = &ctx->last_state.state;
/* Check the timer to make sure the Bluetooth connection LED animation is complete */
@ -726,7 +732,7 @@ static void HIDAPI_DriverPS5_CheckPendingLEDReset(SDL_HIDAPI_Device *device)
packet->rgucSensorTimestamp[1],
packet->rgucSensorTimestamp[2],
packet->rgucSensorTimestamp[3]);
if (SDL_TICKS_PASSED(timestamp, connection_complete)) {
if (timestamp >= connection_complete) {
led_reset_complete = SDL_TRUE;
}
} else {
@ -745,16 +751,25 @@ static void HIDAPI_DriverPS5_CheckPendingLEDReset(SDL_HIDAPI_Device *device)
static void HIDAPI_DriverPS5_TickleBluetooth(SDL_HIDAPI_Device *device)
{
/* This is just a dummy packet that should have no effect, since we don't set the CRC */
Uint8 data[78];
SDL_DriverPS5_Context *ctx = (SDL_DriverPS5_Context *)device->context;
SDL_zeroa(data);
if (ctx->enhanced_mode) {
/* This is just a dummy packet that should have no effect, since we don't set the CRC */
Uint8 data[78];
data[0] = k_EPS5ReportIdBluetoothEffects;
data[1] = 0x02; /* Magic value */
SDL_zeroa(data);
if (SDL_HIDAPI_LockRumble() == 0) {
SDL_HIDAPI_SendRumbleAndUnlock(device, data, sizeof(data));
data[0] = k_EPS5ReportIdBluetoothEffects;
data[1] = 0x02; /* Magic value */
if (SDL_HIDAPI_LockRumble() == 0) {
SDL_HIDAPI_SendRumbleAndUnlock(device, data, sizeof(data));
}
} else {
/* We can't even send an invalid effects packet, or it will put the controller in enhanced mode */
if (device->num_joysticks > 0) {
HIDAPI_JoystickDisconnected(device, device->joysticks[0]);
}
}
}
@ -1216,30 +1231,56 @@ static void HIDAPI_DriverPS5_HandleStatePacketCommon(SDL_Joystick *joystick, SDL
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, axis);
if (ctx->report_sensors) {
Uint32 timestamp;
Uint64 timestamp_us;
float data[3];
Uint64 timestamp_us;
timestamp = LOAD32(packet->rgucSensorTimestamp[0],
packet->rgucSensorTimestamp[1],
packet->rgucSensorTimestamp[2],
packet->rgucSensorTimestamp[3]);
if (ctx->timestamp) {
Uint32 delta;
if (ctx->use_alternate_report) {
/* 16-bit timestamp */
Uint16 timestamp;
if (ctx->last_timestamp > timestamp) {
delta = (SDL_MAX_UINT32 - ctx->last_timestamp + timestamp + 1);
timestamp = LOAD16(packet->rgucSensorTimestamp[0],
packet->rgucSensorTimestamp[1]);
if (ctx->timestamp) {
Uint16 delta;
if (ctx->last_timestamp > timestamp) {
delta = (SDL_MAX_UINT16 - ctx->last_timestamp + timestamp + 1);
} else {
delta = (timestamp - ctx->last_timestamp);
}
ctx->timestamp += delta;
} else {
delta = (timestamp - ctx->last_timestamp);
ctx->timestamp = timestamp;
}
ctx->timestamp += delta;
} else {
ctx->timestamp = timestamp;
}
ctx->last_timestamp = timestamp;
ctx->last_timestamp = timestamp;
/* Sensor timestamp is in 0.33us units */
timestamp_us = ctx->timestamp / 3;
/* Sensor timestamp is in 1us units */
timestamp_us = ctx->timestamp;
} else {
/* 32-bit timestamp */
Uint32 timestamp;
timestamp = LOAD32(packet->rgucSensorTimestamp[0],
packet->rgucSensorTimestamp[1],
packet->rgucSensorTimestamp[2],
packet->rgucSensorTimestamp[3]);
if (ctx->timestamp) {
Uint32 delta;
if (ctx->last_timestamp > timestamp) {
delta = (SDL_MAX_UINT32 - ctx->last_timestamp + timestamp + 1);
} else {
delta = (timestamp - ctx->last_timestamp);
}
ctx->timestamp += delta;
} else {
ctx->timestamp = timestamp;
}
ctx->last_timestamp = timestamp;
/* Sensor timestamp is in 0.33us units */
timestamp_us = ctx->timestamp / 3;
}
data[0] = HIDAPI_DriverPS5_ApplyCalibrationData(ctx, 0, LOAD16(packet->rgucGyroX[0], packet->rgucGyroX[1]));
data[1] = HIDAPI_DriverPS5_ApplyCalibrationData(ctx, 1, LOAD16(packet->rgucGyroY[0], packet->rgucGyroY[1]));
@ -1395,15 +1436,15 @@ static SDL_bool HIDAPI_DriverPS5_UpdateDevice(SDL_HIDAPI_Device *device)
/* This is the extended report, we can enable effects now */
HIDAPI_DriverPS5_SetEnhancedMode(device, joystick);
}
if (ctx->led_reset_state == k_EDS5LEDResetStatePending) {
HIDAPI_DriverPS5_CheckPendingLEDReset(device);
}
HIDAPI_DriverPS5_HandleStatePacketCommon(joystick, device->dev, ctx, (PS5StatePacketCommon_t *)&data[2]);
if (ctx->use_alternate_report) {
HIDAPI_DriverPS5_HandleStatePacketAlt(joystick, device->dev, ctx, (PS5StatePacketAlt_t *)&data[2]);
} else {
HIDAPI_DriverPS5_HandleStatePacket(joystick, device->dev, ctx, (PS5StatePacket_t *)&data[2]);
}
if (ctx->led_reset_state == k_EDS5LEDResetStatePending) {
HIDAPI_DriverPS5_CheckPendingLEDReset(device);
}
break;
default:
#ifdef DEBUG_JOYSTICK

View file

@ -1041,7 +1041,7 @@ static void ConfigJoystick(SDL_Joystick *joystick, int fd)
}
for (i = 0; i < ABS_MAX; ++i) {
/* Skip digital hats */
if (joystick->hwdata->has_hat[(i - ABS_HAT0X) / 2]) {
if (i >= ABS_HAT0X && i <= ABS_HAT3Y && joystick->hwdata->has_hat[(i - ABS_HAT0X) / 2]) {
continue;
}
if (test_bit(i, absbit)) {
@ -1752,11 +1752,11 @@ static SDL_bool LINUX_JoystickGetGamepadMapping(int device_index, SDL_GamepadMap
/* We temporarily open the device to check how it's configured. Make
a fake SDL_Joystick object to do so. */
joystick = (SDL_Joystick *)SDL_calloc(sizeof(*joystick), 1);
joystick->magic = &SDL_joystick_magic;
if (joystick == NULL) {
SDL_OutOfMemory();
return SDL_FALSE;
}
joystick->magic = &SDL_joystick_magic;
SDL_memcpy(&joystick->guid, &item->guid, sizeof(item->guid));
joystick->hwdata = (struct joystick_hwdata *)
@ -2026,7 +2026,7 @@ static SDL_bool LINUX_JoystickGetGamepadMapping(int device_index, SDL_GamepadMap
#endif
}
if (!(mapped & MAPPED_TRIGGER_LEFT) && joystick->hwdata->has_key[BTN_TR2]) {
if (!(mapped & MAPPED_TRIGGER_RIGHT) && joystick->hwdata->has_key[BTN_TR2]) {
out->righttrigger.kind = EMappingKind_Button;
out->righttrigger.target = joystick->hwdata->key_map[BTN_TR2];
mapped |= MAPPED_TRIGGER_RIGHT;

File diff suppressed because it is too large Load diff

View file

@ -22,6 +22,7 @@ standard_guid_pattern = re.compile(r'^([0-9a-fA-F]{4})([0-9a-fA-F]{2})([0-9a-fA-
invalid_controllers = (
('0079', '0006', '0000'), # DragonRise Inc. Generic USB Joystick
('0079', '0006', '6120'), # DragonRise Inc. Generic USB Joystick
('04b4', '2412', 'c529'), # Flydigi Vader 2, Vader 2 Pro, Apex 2, Apex 3
('16c0', '05e1', '0000'), # Xinmotek Controller
)

View file

@ -33,6 +33,7 @@
#if SDL_JOYSTICK_RAWINPUT
#include "SDL_atomic.h"
#include "SDL_endian.h"
#include "SDL_events.h"
#include "SDL_hints.h"
@ -47,7 +48,7 @@
raw input will turn off the Xbox Series X controller when it is connected via the
Xbox One Wireless Adapter.
*/
#if 0 /*def HAVE_XINPUT_H*/
#ifdef HAVE_XINPUT_H
#define SDL_JOYSTICK_RAWINPUT_XINPUT
#endif
#ifdef HAVE_WINDOWS_GAMING_INPUT_H
@ -78,7 +79,9 @@ typedef struct WindowsGamingInputGamepadState WindowsGamingInputGamepadState;
#endif
#endif
/*#define DEBUG_RAWINPUT*/
#if 0
#define DEBUG_RAWINPUT
#endif
#ifndef RIDEV_EXINPUTSINK
#define RIDEV_EXINPUTSINK 0x00001000
@ -401,6 +404,21 @@ static SDL_bool RAWINPUT_GuessXInputSlot(const WindowsMatchState *state, Uint8 *
int user_index;
int match_count;
/* If there is only one available slot, let's use that
* That will be right most of the time, and uncorrelation will fix any bad guesses
*/
match_count = 0;
for (user_index = 0; user_index < XUSER_MAX_COUNT; ++user_index) {
if (xinput_state[user_index].connected && !xinput_state[user_index].used) {
*slot_idx = user_index;
++match_count;
}
}
if (match_count == 1) {
*correlation_id = ++xinput_state[*slot_idx].correlation_id;
return SDL_TRUE;
}
*slot_idx = 0;
match_count = 0;
@ -445,8 +463,86 @@ static struct
SDL_bool need_device_list_update;
int ref_count;
__x_ABI_CWindows_CGaming_CInput_CIGamepadStatics *gamepad_statics;
EventRegistrationToken gamepad_added_token;
EventRegistrationToken gamepad_removed_token;
} wgi_state;
typedef struct GamepadDelegate
{
__FIEventHandler_1_Windows__CGaming__CInput__CGamepad iface;
SDL_atomic_t refcount;
} GamepadDelegate;
static const IID IID_IEventHandler_Gamepad = { 0x8a7639ee, 0x624a, 0x501a, { 0xbb, 0x53, 0x56, 0x2d, 0x1e, 0xc1, 0x1b, 0x52 } };
static HRESULT STDMETHODCALLTYPE IEventHandler_CGamepadVtbl_QueryInterface(__FIEventHandler_1_Windows__CGaming__CInput__CGamepad *This, REFIID riid, void **ppvObject)
{
if (ppvObject == NULL) {
return E_INVALIDARG;
}
*ppvObject = NULL;
if (WIN_IsEqualIID(riid, &IID_IUnknown) || WIN_IsEqualIID(riid, &IID_IAgileObject) || WIN_IsEqualIID(riid, &IID_IEventHandler_Gamepad)) {
*ppvObject = This;
__FIEventHandler_1_Windows__CGaming__CInput__CGamepad_AddRef(This);
return S_OK;
} else if (WIN_IsEqualIID(riid, &IID_IMarshal)) {
/* This seems complicated. Let's hope it doesn't happen. */
return E_OUTOFMEMORY;
} else {
return E_NOINTERFACE;
}
}
static ULONG STDMETHODCALLTYPE IEventHandler_CGamepadVtbl_AddRef(__FIEventHandler_1_Windows__CGaming__CInput__CGamepad *This)
{
GamepadDelegate *self = (GamepadDelegate *)This;
return SDL_AtomicAdd(&self->refcount, 1) + 1UL;
}
static ULONG STDMETHODCALLTYPE IEventHandler_CGamepadVtbl_Release(__FIEventHandler_1_Windows__CGaming__CInput__CGamepad *This)
{
GamepadDelegate *self = (GamepadDelegate *)This;
int rc = SDL_AtomicAdd(&self->refcount, -1) - 1;
/* Should never free the static delegate objects */
SDL_assert(rc > 0);
return rc;
}
static HRESULT STDMETHODCALLTYPE IEventHandler_CGamepadVtbl_InvokeAdded(__FIEventHandler_1_Windows__CGaming__CInput__CGamepad *This, IInspectable *sender, __x_ABI_CWindows_CGaming_CInput_CIGamepad *e)
{
wgi_state.need_device_list_update = SDL_TRUE;
return S_OK;
}
static HRESULT STDMETHODCALLTYPE IEventHandler_CGamepadVtbl_InvokeRemoved(__FIEventHandler_1_Windows__CGaming__CInput__CGamepad *This, IInspectable *sender, __x_ABI_CWindows_CGaming_CInput_CIGamepad *e)
{
wgi_state.need_device_list_update = SDL_TRUE;
return S_OK;
}
static __FIEventHandler_1_Windows__CGaming__CInput__CGamepadVtbl gamepad_added_vtbl = {
IEventHandler_CGamepadVtbl_QueryInterface,
IEventHandler_CGamepadVtbl_AddRef,
IEventHandler_CGamepadVtbl_Release,
IEventHandler_CGamepadVtbl_InvokeAdded
};
static GamepadDelegate gamepad_added = {
{ &gamepad_added_vtbl },
{ 1 }
};
static __FIEventHandler_1_Windows__CGaming__CInput__CGamepadVtbl gamepad_removed_vtbl = {
IEventHandler_CGamepadVtbl_QueryInterface,
IEventHandler_CGamepadVtbl_AddRef,
IEventHandler_CGamepadVtbl_Release,
IEventHandler_CGamepadVtbl_InvokeRemoved
};
static GamepadDelegate gamepad_removed = {
{ &gamepad_removed_vtbl },
{ 1 }
};
static void RAWINPUT_MarkWindowsGamingInputSlotUsed(WindowsGamingInputGamepadState *wgi_slot, RAWINPUT_DeviceContext *ctx)
{
wgi_slot->used = SDL_TRUE;
@ -564,7 +660,10 @@ static void RAWINPUT_UpdateWindowsGamingInput()
}
static void RAWINPUT_InitWindowsGamingInput(RAWINPUT_DeviceContext *ctx)
{
wgi_state.need_device_list_update = SDL_TRUE;
if (!SDL_GetHintBoolean(SDL_HINT_JOYSTICK_WGI, SDL_TRUE)) {
return;
}
wgi_state.ref_count++;
if (!wgi_state.initialized) {
static const IID SDL_IID_IGamepadStatics = { 0x8BBCE529, 0xD49C, 0x39E9, { 0x95, 0x60, 0xE4, 0x7D, 0xDE, 0x96, 0xB7, 0xC8 } };
@ -596,6 +695,20 @@ static void RAWINPUT_InitWindowsGamingInput(RAWINPUT_DeviceContext *ctx)
if (SUCCEEDED(hr)) {
RoGetActivationFactoryFunc(hNamespaceString, &SDL_IID_IGamepadStatics, (void **)&wgi_state.gamepad_statics);
}
if (wgi_state.gamepad_statics) {
wgi_state.need_device_list_update = SDL_TRUE;
hr = __x_ABI_CWindows_CGaming_CInput_CIGamepadStatics_add_GamepadAdded(wgi_state.gamepad_statics, &gamepad_added.iface, &wgi_state.gamepad_added_token);
if (!SUCCEEDED(hr)) {
SDL_SetError("add_GamepadAdded() failed: 0x%lx\n", hr);
}
hr = __x_ABI_CWindows_CGaming_CInput_CIGamepadStatics_add_GamepadRemoved(wgi_state.gamepad_statics, &gamepad_removed.iface, &wgi_state.gamepad_removed_token);
if (!SUCCEEDED(hr)) {
SDL_SetError("add_GamepadRemoved() failed: 0x%lx\n", hr);
}
}
}
}
}
@ -621,10 +734,27 @@ static SDL_bool RAWINPUT_WindowsGamingInputSlotMatches(const WindowsMatchState *
static SDL_bool RAWINPUT_GuessWindowsGamingInputSlot(const WindowsMatchState *state, Uint8 *correlation_id, WindowsGamingInputGamepadState **slot, SDL_bool xinput_correlated)
{
int match_count, user_index;
WindowsGamingInputGamepadState *gamepad_state = NULL;
/* If there is only one available slot, let's use that
* That will be right most of the time, and uncorrelation will fix any bad guesses
*/
match_count = 0;
for (user_index = 0; user_index < wgi_state.per_gamepad_count; ++user_index) {
gamepad_state = wgi_state.per_gamepad[user_index];
if (gamepad_state->connected && !gamepad_state->used) {
*slot = gamepad_state;
++match_count;
}
}
if (match_count == 1) {
*correlation_id = ++gamepad_state->correlation_id;
return SDL_TRUE;
}
match_count = 0;
for (user_index = 0; user_index < wgi_state.per_gamepad_count; ++user_index) {
WindowsGamingInputGamepadState *gamepad_state = wgi_state.per_gamepad[user_index];
gamepad_state = wgi_state.per_gamepad[user_index];
if (RAWINPUT_WindowsGamingInputSlotMatches(state, gamepad_state, xinput_correlated)) {
++match_count;
*slot = gamepad_state;
@ -643,7 +773,6 @@ static SDL_bool RAWINPUT_GuessWindowsGamingInputSlot(const WindowsMatchState *st
static void RAWINPUT_QuitWindowsGamingInput(RAWINPUT_DeviceContext *ctx)
{
wgi_state.need_device_list_update = SDL_TRUE;
--wgi_state.ref_count;
if (!wgi_state.ref_count && wgi_state.initialized) {
int ii;
@ -656,6 +785,8 @@ static void RAWINPUT_QuitWindowsGamingInput(RAWINPUT_DeviceContext *ctx)
}
wgi_state.per_gamepad_count = 0;
if (wgi_state.gamepad_statics) {
__x_ABI_CWindows_CGaming_CInput_CIGamepadStatics_remove_GamepadAdded(wgi_state.gamepad_statics, wgi_state.gamepad_added_token);
__x_ABI_CWindows_CGaming_CInput_CIGamepadStatics_remove_GamepadRemoved(wgi_state.gamepad_statics, wgi_state.gamepad_removed_token);
__x_ABI_CWindows_CGaming_CInput_CIGamepadStatics_Release(wgi_state.gamepad_statics);
wgi_state.gamepad_statics = NULL;
}
@ -879,12 +1010,12 @@ static int RAWINPUT_JoystickInit(void)
{
SDL_assert(!SDL_RAWINPUT_inited);
if (!WIN_IsWindowsVistaOrGreater()) {
/* According to bug 6400, this doesn't work on Windows XP */
return -1;
if (!SDL_GetHintBoolean(SDL_HINT_JOYSTICK_RAWINPUT, SDL_TRUE)) {
return 0;
}
if (!SDL_GetHintBoolean(SDL_HINT_JOYSTICK_RAWINPUT, SDL_TRUE)) {
if (!WIN_IsWindowsVistaOrGreater()) {
/* According to bug 6400, this doesn't work on Windows XP */
return -1;
}
@ -917,9 +1048,6 @@ SDL_bool RAWINPUT_IsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 ve
#ifdef SDL_JOYSTICK_RAWINPUT_XINPUT
xinput_device_change = SDL_TRUE;
#endif
#ifdef SDL_JOYSTICK_RAWINPUT_WGI
wgi_state.need_device_list_update = SDL_TRUE;
#endif
device = SDL_RAWINPUT_devices;
while (device) {
@ -1008,8 +1136,13 @@ static void RAWINPUT_PostUpdate(void)
static void RAWINPUT_JoystickDetect(void)
{
SDL_bool remote_desktop = GetSystemMetrics(SM_REMOTESESSION) ? SDL_TRUE : SDL_FALSE;
SDL_bool remote_desktop;
if (!SDL_RAWINPUT_inited) {
return;
}
remote_desktop = GetSystemMetrics(SM_REMOTESESSION) ? SDL_TRUE : SDL_FALSE;
if (remote_desktop != SDL_RAWINPUT_remote_desktop) {
SDL_RAWINPUT_remote_desktop = remote_desktop;
@ -1281,20 +1414,8 @@ static int RAWINPUT_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_
#endif
SDL_bool rumbled = SDL_FALSE;
#ifdef SDL_JOYSTICK_RAWINPUT_WGI
if (!rumbled && ctx->wgi_correlated) {
WindowsGamingInputGamepadState *gamepad_state = ctx->wgi_slot;
HRESULT hr;
gamepad_state->vibration.LeftMotor = (DOUBLE)low_frequency_rumble / SDL_MAX_UINT16;
gamepad_state->vibration.RightMotor = (DOUBLE)high_frequency_rumble / SDL_MAX_UINT16;
hr = __x_ABI_CWindows_CGaming_CInput_CIGamepad_put_Vibration(gamepad_state->gamepad, gamepad_state->vibration);
if (SUCCEEDED(hr)) {
rumbled = SDL_TRUE;
}
}
#endif
#ifdef SDL_JOYSTICK_RAWINPUT_XINPUT
/* Prefer XInput over WGI because it allows rumble in the background */
if (!rumbled && ctx->xinput_correlated) {
XINPUT_VIBRATION XVibration;
@ -1312,6 +1433,19 @@ static int RAWINPUT_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_
}
#endif /* SDL_JOYSTICK_RAWINPUT_XINPUT */
#ifdef SDL_JOYSTICK_RAWINPUT_WGI
if (!rumbled && ctx->wgi_correlated) {
WindowsGamingInputGamepadState *gamepad_state = ctx->wgi_slot;
HRESULT hr;
gamepad_state->vibration.LeftMotor = (DOUBLE)low_frequency_rumble / SDL_MAX_UINT16;
gamepad_state->vibration.RightMotor = (DOUBLE)high_frequency_rumble / SDL_MAX_UINT16;
hr = __x_ABI_CWindows_CGaming_CInput_CIGamepad_put_Vibration(gamepad_state->gamepad, gamepad_state->vibration);
if (SUCCEEDED(hr)) {
rumbled = SDL_TRUE;
}
}
#endif
if (!rumbled) {
#if defined(SDL_JOYSTICK_RAWINPUT_WGI) || defined(SDL_JOYSTICK_RAWINPUT_XINPUT)
return SDL_SetError("Controller isn't correlated yet, try hitting a button first");
@ -1911,10 +2045,14 @@ static void RAWINPUT_JoystickClose(SDL_Joystick *joystick)
}
}
SDL_bool RAWINPUT_RegisterNotifications(HWND hWnd)
int RAWINPUT_RegisterNotifications(HWND hWnd)
{
RAWINPUTDEVICE rid[SDL_arraysize(subscribed_devices)];
int i;
RAWINPUTDEVICE rid[SDL_arraysize(subscribed_devices)];
if (!SDL_RAWINPUT_inited) {
return 0;
}
for (i = 0; i < SDL_arraysize(subscribed_devices); i++) {
rid[i].usUsagePage = USB_USAGEPAGE_GENERIC_DESKTOP;
@ -1924,17 +2062,20 @@ SDL_bool RAWINPUT_RegisterNotifications(HWND hWnd)
}
if (!RegisterRawInputDevices(rid, SDL_arraysize(rid), sizeof(RAWINPUTDEVICE))) {
SDL_SetError("Couldn't register for raw input events");
return SDL_FALSE;
return SDL_SetError("Couldn't register for raw input events");
}
return SDL_TRUE;
return 0;
}
void RAWINPUT_UnregisterNotifications()
int RAWINPUT_UnregisterNotifications()
{
int i;
RAWINPUTDEVICE rid[SDL_arraysize(subscribed_devices)];
if (!SDL_RAWINPUT_inited) {
return 0;
}
for (i = 0; i < SDL_arraysize(subscribed_devices); i++) {
rid[i].usUsagePage = USB_USAGEPAGE_GENERIC_DESKTOP;
rid[i].usUsage = subscribed_devices[i];
@ -1943,9 +2084,9 @@ void RAWINPUT_UnregisterNotifications()
}
if (!RegisterRawInputDevices(rid, SDL_arraysize(rid), sizeof(RAWINPUTDEVICE))) {
SDL_SetError("Couldn't unregister for raw input events");
return;
return SDL_SetError("Couldn't unregister for raw input events");
}
return 0;
}
LRESULT CALLBACK

View file

@ -28,8 +28,8 @@ extern SDL_bool RAWINPUT_IsEnabled();
extern SDL_bool RAWINPUT_IsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 version, const char *name);
/* Registers for input events */
extern SDL_bool RAWINPUT_RegisterNotifications(HWND hWnd);
extern void RAWINPUT_UnregisterNotifications();
extern int RAWINPUT_RegisterNotifications(HWND hWnd);
extern int RAWINPUT_UnregisterNotifications();
/* Returns 0 if message was handled */
extern LRESULT CALLBACK RAWINPUT_WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);

View file

@ -101,6 +101,9 @@ static const IID IID_IRacingWheelStatics = { 0x3AC12CD5, 0x581B, 0x4936, { 0x9F,
static const IID IID_IRacingWheelStatics2 = { 0xE666BCAA, 0xEDFD, 0x4323, { 0xA9, 0xF6, 0x3C, 0x38, 0x40, 0x48, 0xD1, 0xED } };
/*static const IID IID_IRacingWheel = { 0xF546656F, 0xE106, 0x4C82, { 0xA9, 0x0F, 0x55, 0x40, 0x12, 0x90, 0x4B, 0x85 } };*/
typedef HRESULT(WINAPI *WindowsCreateStringReference_t)(PCWSTR sourceString, UINT32 length, HSTRING_HEADER *hstringHeader, HSTRING *string);
typedef HRESULT(WINAPI *RoGetActivationFactory_t)(HSTRING activatableClassId, REFIID iid, void **factory);
extern SDL_bool SDL_XINPUT_Enabled(void);
extern SDL_bool SDL_DINPUT_JoystickPresent(Uint16 vendor, Uint16 product, Uint16 version);
@ -211,6 +214,136 @@ static SDL_bool SDL_IsXInputDevice(Uint16 vendor, Uint16 product)
return SDL_FALSE;
}
static void WGI_LoadRawGameControllerStatics()
{
WindowsCreateStringReference_t WindowsCreateStringReferenceFunc = NULL;
RoGetActivationFactory_t RoGetActivationFactoryFunc = NULL;
HRESULT hr;
#ifdef __WINRT__
WindowsCreateStringReferenceFunc = WindowsCreateStringReference;
RoGetActivationFactoryFunc = RoGetActivationFactory;
#else
{
WindowsCreateStringReferenceFunc = (WindowsCreateStringReference_t)WIN_LoadComBaseFunction("WindowsCreateStringReference");
RoGetActivationFactoryFunc = (RoGetActivationFactory_t)WIN_LoadComBaseFunction("RoGetActivationFactory");
}
#endif /* __WINRT__ */
if (WindowsCreateStringReferenceFunc && RoGetActivationFactoryFunc) {
PCWSTR pNamespace;
HSTRING_HEADER hNamespaceStringHeader;
HSTRING hNamespaceString;
pNamespace = L"Windows.Gaming.Input.RawGameController";
hr = WindowsCreateStringReferenceFunc(pNamespace, (UINT32)SDL_wcslen(pNamespace), &hNamespaceStringHeader, &hNamespaceString);
if (SUCCEEDED(hr)) {
hr = RoGetActivationFactoryFunc(hNamespaceString, &IID_IRawGameControllerStatics, (void **)&wgi.statics);
if (!SUCCEEDED(hr)) {
SDL_SetError("Couldn't find IRawGameControllerStatics: 0x%lx", hr);
}
}
}
}
static void WGI_LoadOtherControllerStatics()
{
WindowsCreateStringReference_t WindowsCreateStringReferenceFunc = NULL;
RoGetActivationFactory_t RoGetActivationFactoryFunc = NULL;
HRESULT hr;
#ifdef __WINRT__
WindowsCreateStringReferenceFunc = WindowsCreateStringReference;
RoGetActivationFactoryFunc = RoGetActivationFactory;
#else
{
WindowsCreateStringReferenceFunc = (WindowsCreateStringReference_t)WIN_LoadComBaseFunction("WindowsCreateStringReference");
RoGetActivationFactoryFunc = (RoGetActivationFactory_t)WIN_LoadComBaseFunction("RoGetActivationFactory");
}
#endif /* __WINRT__ */
if (WindowsCreateStringReferenceFunc && RoGetActivationFactoryFunc) {
PCWSTR pNamespace;
HSTRING_HEADER hNamespaceStringHeader;
HSTRING hNamespaceString;
pNamespace = L"Windows.Gaming.Input.ArcadeStick";
hr = WindowsCreateStringReferenceFunc(pNamespace, (UINT32)SDL_wcslen(pNamespace), &hNamespaceStringHeader, &hNamespaceString);
if (SUCCEEDED(hr)) {
hr = RoGetActivationFactoryFunc(hNamespaceString, &IID_IArcadeStickStatics, (void **)&wgi.arcade_stick_statics);
if (SUCCEEDED(hr)) {
__x_ABI_CWindows_CGaming_CInput_CIArcadeStickStatics_QueryInterface(wgi.arcade_stick_statics, &IID_IArcadeStickStatics2, (void **)&wgi.arcade_stick_statics2);
} else {
SDL_SetError("Couldn't find IID_IArcadeStickStatics: 0x%lx", hr);
}
}
pNamespace = L"Windows.Gaming.Input.FlightStick";
hr = WindowsCreateStringReferenceFunc(pNamespace, (UINT32)SDL_wcslen(pNamespace), &hNamespaceStringHeader, &hNamespaceString);
if (SUCCEEDED(hr)) {
hr = RoGetActivationFactoryFunc(hNamespaceString, &IID_IFlightStickStatics, (void **)&wgi.flight_stick_statics);
if (!SUCCEEDED(hr)) {
SDL_SetError("Couldn't find IID_IFlightStickStatics: 0x%lx", hr);
}
}
pNamespace = L"Windows.Gaming.Input.Gamepad";
hr = WindowsCreateStringReferenceFunc(pNamespace, (UINT32)SDL_wcslen(pNamespace), &hNamespaceStringHeader, &hNamespaceString);
if (SUCCEEDED(hr)) {
hr = RoGetActivationFactoryFunc(hNamespaceString, &IID_IGamepadStatics, (void **)&wgi.gamepad_statics);
if (SUCCEEDED(hr)) {
__x_ABI_CWindows_CGaming_CInput_CIGamepadStatics_QueryInterface(wgi.gamepad_statics, &IID_IGamepadStatics2, (void **)&wgi.gamepad_statics2);
} else {
SDL_SetError("Couldn't find IGamepadStatics: 0x%lx", hr);
}
}
pNamespace = L"Windows.Gaming.Input.RacingWheel";
hr = WindowsCreateStringReferenceFunc(pNamespace, (UINT32)SDL_wcslen(pNamespace), &hNamespaceStringHeader, &hNamespaceString);
if (SUCCEEDED(hr)) {
hr = RoGetActivationFactoryFunc(hNamespaceString, &IID_IRacingWheelStatics, (void **)&wgi.racing_wheel_statics);
if (SUCCEEDED(hr)) {
__x_ABI_CWindows_CGaming_CInput_CIRacingWheelStatics_QueryInterface(wgi.racing_wheel_statics, &IID_IRacingWheelStatics2, (void **)&wgi.racing_wheel_statics2);
} else {
SDL_SetError("Couldn't find IRacingWheelStatics: 0x%lx", hr);
}
}
}
}
static SDL_JoystickType GetGameControllerType(__x_ABI_CWindows_CGaming_CInput_CIGameController *gamecontroller)
{
__x_ABI_CWindows_CGaming_CInput_CIArcadeStick *arcade_stick = NULL;
__x_ABI_CWindows_CGaming_CInput_CIFlightStick *flight_stick = NULL;
__x_ABI_CWindows_CGaming_CInput_CIGamepad *gamepad = NULL;
__x_ABI_CWindows_CGaming_CInput_CIRacingWheel *racing_wheel = NULL;
/* Wait to initialize these interfaces until we need them.
* Initializing the gamepad interface will switch Bluetooth PS4 controllers into enhanced mode, breaking DirectInput
*/
WGI_LoadOtherControllerStatics();
if (wgi.gamepad_statics2 && SUCCEEDED(__x_ABI_CWindows_CGaming_CInput_CIGamepadStatics2_FromGameController(wgi.gamepad_statics2, gamecontroller, &gamepad)) && gamepad) {
__x_ABI_CWindows_CGaming_CInput_CIGamepad_Release(gamepad);
return SDL_JOYSTICK_TYPE_GAMECONTROLLER;
}
if (wgi.arcade_stick_statics2 && SUCCEEDED(__x_ABI_CWindows_CGaming_CInput_CIArcadeStickStatics2_FromGameController(wgi.arcade_stick_statics2, gamecontroller, &arcade_stick)) && arcade_stick) {
__x_ABI_CWindows_CGaming_CInput_CIArcadeStick_Release(arcade_stick);
return SDL_JOYSTICK_TYPE_ARCADE_STICK;
}
if (wgi.flight_stick_statics && SUCCEEDED(__x_ABI_CWindows_CGaming_CInput_CIFlightStickStatics_FromGameController(wgi.flight_stick_statics, gamecontroller, &flight_stick)) && flight_stick) {
__x_ABI_CWindows_CGaming_CInput_CIFlightStick_Release(flight_stick);
return SDL_JOYSTICK_TYPE_FLIGHT_STICK;
}
if (wgi.racing_wheel_statics2 && SUCCEEDED(__x_ABI_CWindows_CGaming_CInput_CIRacingWheelStatics2_FromGameController(wgi.racing_wheel_statics2, gamecontroller, &racing_wheel)) && racing_wheel) {
__x_ABI_CWindows_CGaming_CInput_CIRacingWheel_Release(racing_wheel);
return SDL_JOYSTICK_TYPE_WHEEL;
}
return SDL_JOYSTICK_TYPE_UNKNOWN;
}
typedef struct RawGameControllerDelegate
{
__FIEventHandler_1_Windows__CGaming__CInput__CRawGameController iface;
@ -226,7 +359,7 @@ static HRESULT STDMETHODCALLTYPE IEventHandler_CRawGameControllerVtbl_QueryInter
*ppvObject = NULL;
if (WIN_IsEqualIID(riid, &IID_IUnknown) || WIN_IsEqualIID(riid, &IID_IAgileObject) || WIN_IsEqualIID(riid, &IID_IEventHandler_RawGameController)) {
*ppvObject = This;
__x_ABI_CWindows_CGaming_CInput_CIRawGameControllerStatics_AddRef(This);
__FIEventHandler_1_Windows__CGaming__CInput__CRawGameController_AddRef(This);
return S_OK;
} else if (WIN_IsEqualIID(riid, &IID_IMarshal)) {
/* This seems complicated. Let's hope it doesn't happen. */
@ -313,38 +446,6 @@ static HRESULT STDMETHODCALLTYPE IEventHandler_CRawGameControllerVtbl_InvokeAdde
name = SDL_strdup("");
}
hr = __x_ABI_CWindows_CGaming_CInput_CIRawGameController_QueryInterface(controller, &IID_IGameController, (void **)&gamecontroller);
if (SUCCEEDED(hr)) {
__x_ABI_CWindows_CGaming_CInput_CIArcadeStick *arcade_stick = NULL;
__x_ABI_CWindows_CGaming_CInput_CIFlightStick *flight_stick = NULL;
__x_ABI_CWindows_CGaming_CInput_CIGamepad *gamepad = NULL;
__x_ABI_CWindows_CGaming_CInput_CIRacingWheel *racing_wheel = NULL;
boolean wireless;
if (wgi.gamepad_statics2 && SUCCEEDED(__x_ABI_CWindows_CGaming_CInput_CIGamepadStatics2_FromGameController(wgi.gamepad_statics2, gamecontroller, &gamepad)) && gamepad) {
type = SDL_JOYSTICK_TYPE_GAMECONTROLLER;
__x_ABI_CWindows_CGaming_CInput_CIGamepad_Release(gamepad);
} else if (wgi.arcade_stick_statics2 && SUCCEEDED(__x_ABI_CWindows_CGaming_CInput_CIArcadeStickStatics2_FromGameController(wgi.arcade_stick_statics2, gamecontroller, &arcade_stick)) && arcade_stick) {
type = SDL_JOYSTICK_TYPE_ARCADE_STICK;
__x_ABI_CWindows_CGaming_CInput_CIArcadeStick_Release(arcade_stick);
} else if (wgi.flight_stick_statics && SUCCEEDED(__x_ABI_CWindows_CGaming_CInput_CIFlightStickStatics_FromGameController(wgi.flight_stick_statics, gamecontroller, &flight_stick)) && flight_stick) {
type = SDL_JOYSTICK_TYPE_FLIGHT_STICK;
__x_ABI_CWindows_CGaming_CInput_CIFlightStick_Release(flight_stick);
} else if (wgi.racing_wheel_statics2 && SUCCEEDED(__x_ABI_CWindows_CGaming_CInput_CIRacingWheelStatics2_FromGameController(wgi.racing_wheel_statics2, gamecontroller, &racing_wheel)) && racing_wheel) {
type = SDL_JOYSTICK_TYPE_WHEEL;
__x_ABI_CWindows_CGaming_CInput_CIRacingWheel_Release(racing_wheel);
}
hr = __x_ABI_CWindows_CGaming_CInput_CIGameController_get_IsWireless(gamecontroller, &wireless);
if (SUCCEEDED(hr) && wireless) {
bus = SDL_HARDWARE_BUS_BLUETOOTH;
}
__x_ABI_CWindows_CGaming_CInput_CIGameController_Release(gamecontroller);
}
guid = SDL_CreateJoystickGUID(bus, vendor, product, version, name, 'w', (Uint8)type);
#ifdef SDL_JOYSTICK_HIDAPI
if (!ignore_joystick && HIDAPI_IsDevicePresent(vendor, product, version, name)) {
ignore_joystick = SDL_TRUE;
@ -365,13 +466,29 @@ static HRESULT STDMETHODCALLTYPE IEventHandler_CRawGameControllerVtbl_InvokeAdde
ignore_joystick = SDL_TRUE;
}
if (!ignore_joystick && SDL_ShouldIgnoreJoystick(name, guid)) {
ignore_joystick = SDL_TRUE;
if (!ignore_joystick) {
hr = __x_ABI_CWindows_CGaming_CInput_CIRawGameController_QueryInterface(controller, &IID_IGameController, (void **)&gamecontroller);
if (SUCCEEDED(hr)) {
boolean wireless;
type = GetGameControllerType(gamecontroller);
hr = __x_ABI_CWindows_CGaming_CInput_CIGameController_get_IsWireless(gamecontroller, &wireless);
if (SUCCEEDED(hr) && wireless) {
bus = SDL_HARDWARE_BUS_BLUETOOTH;
}
__x_ABI_CWindows_CGaming_CInput_CIGameController_Release(gamecontroller);
}
guid = SDL_CreateJoystickGUID(bus, vendor, product, version, name, 'w', (Uint8)type);
if (SDL_ShouldIgnoreJoystick(name, guid)) {
ignore_joystick = SDL_TRUE;
}
}
if (ignore_joystick) {
SDL_free(name);
} else {
if (!ignore_joystick) {
/* New device, add it */
WindowsGamingInputControllerState *controllers = SDL_realloc(wgi.controllers, sizeof(wgi.controllers[0]) * (wgi.controller_count + 1));
if (controllers) {
@ -398,6 +515,8 @@ static HRESULT STDMETHODCALLTYPE IEventHandler_CRawGameControllerVtbl_InvokeAdde
} else {
SDL_free(name);
}
} else {
SDL_free(name);
}
__x_ABI_CWindows_CGaming_CInput_CIRawGameController_Release(controller);
@ -476,13 +595,12 @@ static RawGameControllerDelegate controller_removed = {
static int WGI_JoystickInit(void)
{
typedef HRESULT(WINAPI * WindowsCreateStringReference_t)(PCWSTR sourceString, UINT32 length, HSTRING_HEADER * hstringHeader, HSTRING * string);
typedef HRESULT(WINAPI * RoGetActivationFactory_t)(HSTRING activatableClassId, REFIID iid, void **factory);
WindowsCreateStringReference_t WindowsCreateStringReferenceFunc = NULL;
RoGetActivationFactory_t RoGetActivationFactoryFunc = NULL;
HRESULT hr;
if (!SDL_GetHintBoolean(SDL_HINT_JOYSTICK_WGI, SDL_TRUE)) {
return 0;
}
if (FAILED(WIN_RoInitialize())) {
return SDL_SetError("RoInitialize() failed");
}
@ -511,71 +629,7 @@ static int WGI_JoystickInit(void)
}
#endif
#ifdef __WINRT__
WindowsCreateStringReferenceFunc = WindowsCreateStringReference;
RoGetActivationFactoryFunc = RoGetActivationFactory;
#else
{
WindowsCreateStringReferenceFunc = (WindowsCreateStringReference_t)WIN_LoadComBaseFunction("WindowsCreateStringReference");
RoGetActivationFactoryFunc = (RoGetActivationFactory_t)WIN_LoadComBaseFunction("RoGetActivationFactory");
}
#endif /* __WINRT__ */
if (WindowsCreateStringReferenceFunc && RoGetActivationFactoryFunc) {
PCWSTR pNamespace;
HSTRING_HEADER hNamespaceStringHeader;
HSTRING hNamespaceString;
pNamespace = L"Windows.Gaming.Input.RawGameController";
hr = WindowsCreateStringReferenceFunc(pNamespace, (UINT32)SDL_wcslen(pNamespace), &hNamespaceStringHeader, &hNamespaceString);
if (SUCCEEDED(hr)) {
hr = RoGetActivationFactoryFunc(hNamespaceString, &IID_IRawGameControllerStatics, (void **)&wgi.statics);
if (!SUCCEEDED(hr)) {
SDL_SetError("Couldn't find IRawGameControllerStatics: 0x%lx", hr);
}
}
pNamespace = L"Windows.Gaming.Input.ArcadeStick";
hr = WindowsCreateStringReferenceFunc(pNamespace, (UINT32)SDL_wcslen(pNamespace), &hNamespaceStringHeader, &hNamespaceString);
if (SUCCEEDED(hr)) {
hr = RoGetActivationFactoryFunc(hNamespaceString, &IID_IArcadeStickStatics, (void **)&wgi.arcade_stick_statics);
if (SUCCEEDED(hr)) {
__x_ABI_CWindows_CGaming_CInput_CIArcadeStickStatics_QueryInterface(wgi.arcade_stick_statics, &IID_IArcadeStickStatics2, (void **)&wgi.arcade_stick_statics2);
} else {
SDL_SetError("Couldn't find IID_IArcadeStickStatics: 0x%lx", hr);
}
}
pNamespace = L"Windows.Gaming.Input.FlightStick";
hr = WindowsCreateStringReferenceFunc(pNamespace, (UINT32)SDL_wcslen(pNamespace), &hNamespaceStringHeader, &hNamespaceString);
if (SUCCEEDED(hr)) {
hr = RoGetActivationFactoryFunc(hNamespaceString, &IID_IFlightStickStatics, (void **)&wgi.flight_stick_statics);
if (!SUCCEEDED(hr)) {
SDL_SetError("Couldn't find IID_IFlightStickStatics: 0x%lx", hr);
}
}
pNamespace = L"Windows.Gaming.Input.Gamepad";
hr = WindowsCreateStringReferenceFunc(pNamespace, (UINT32)SDL_wcslen(pNamespace), &hNamespaceStringHeader, &hNamespaceString);
if (SUCCEEDED(hr)) {
hr = RoGetActivationFactoryFunc(hNamespaceString, &IID_IGamepadStatics, (void **)&wgi.gamepad_statics);
if (SUCCEEDED(hr)) {
__x_ABI_CWindows_CGaming_CInput_CIGamepadStatics_QueryInterface(wgi.gamepad_statics, &IID_IGamepadStatics2, (void **)&wgi.gamepad_statics2);
} else {
SDL_SetError("Couldn't find IGamepadStatics: 0x%lx", hr);
}
}
pNamespace = L"Windows.Gaming.Input.RacingWheel";
hr = WindowsCreateStringReferenceFunc(pNamespace, (UINT32)SDL_wcslen(pNamespace), &hNamespaceStringHeader, &hNamespaceString);
if (SUCCEEDED(hr)) {
hr = RoGetActivationFactoryFunc(hNamespaceString, &IID_IRacingWheelStatics, (void **)&wgi.racing_wheel_statics);
if (SUCCEEDED(hr)) {
__x_ABI_CWindows_CGaming_CInput_CIRacingWheelStatics_QueryInterface(wgi.racing_wheel_statics, &IID_IRacingWheelStatics2, (void **)&wgi.racing_wheel_statics2);
} else {
SDL_SetError("Couldn't find IRacingWheelStatics: 0x%lx", hr);
}
}
}
WGI_LoadRawGameControllerStatics();
if (wgi.statics) {
__FIVectorView_1_Windows__CGaming__CInput__CRawGameController *controllers;

View file

@ -235,6 +235,20 @@ static void AddXInputDevice(Uint8 userid, BYTE SubType, JoyStick_DeviceData **pC
JoyStick_DeviceData *pPrevJoystick = NULL;
JoyStick_DeviceData *pNewJoystick = *pContext;
#ifdef SDL_JOYSTICK_RAWINPUT
if (RAWINPUT_IsEnabled()) {
/* The raw input driver handles more than 4 controllers, so prefer that when available */
/* We do this check here rather than at the top of SDL_XINPUT_JoystickDetect() because
we need to check XInput state before RAWINPUT gets a hold of the device, otherwise
when a controller is connected via the wireless adapter, it will shut down at the
first subsequent XInput call. This seems like a driver stack bug?
Reference: https://github.com/libsdl-org/SDL/issues/3468
*/
return;
}
#endif
if (SDL_XInputUseOldJoystickMapping() && SubType != XINPUT_DEVSUBTYPE_GAMEPAD) {
return;
}
@ -322,13 +336,6 @@ void SDL_XINPUT_JoystickDetect(JoyStick_DeviceData **pContext)
return;
}
#ifdef SDL_JOYSTICK_RAWINPUT
if (RAWINPUT_IsEnabled()) {
/* The raw input driver handles more than 4 controllers, so prefer that when available */
return;
}
#endif
/* iterate in reverse, so these are in the final list in ascending numeric order. */
for (iuserid = XUSER_MAX_COUNT - 1; iuserid >= 0; iuserid--) {
const Uint8 userid = (Uint8)iuserid;

View file

@ -103,7 +103,7 @@ int console_wmain(int argc, wchar_t *wargv[], wchar_t *wenvp)
#endif
/* This is where execution begins [windowed apps] */
int WINAPI
int WINAPI MINGW32_FORCEALIGN
WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw) /* NOLINT(readability-inconsistent-declaration-parameter-name) */
{
return main_getcmdline();

View file

@ -9,8 +9,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 2,28,1,0
PRODUCTVERSION 2,28,1,0
FILEVERSION 2,28,4,0
PRODUCTVERSION 2,28,4,0
FILEFLAGSMASK 0x3fL
FILEFLAGS 0x0L
FILEOS 0x40004L
@ -23,12 +23,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "\0"
VALUE "FileDescription", "SDL\0"
VALUE "FileVersion", "2, 28, 1, 0\0"
VALUE "FileVersion", "2, 28, 4, 0\0"
VALUE "InternalName", "SDL\0"
VALUE "LegalCopyright", "Copyright (C) 2023 Sam Lantinga\0"
VALUE "OriginalFilename", "SDL2.dll\0"
VALUE "ProductName", "Simple DirectMedia Layer\0"
VALUE "ProductVersion", "2, 28, 1, 0\0"
VALUE "ProductVersion", "2, 28, 4, 0\0"
END
END
BLOCK "VarFileInfo"

View file

@ -23,13 +23,11 @@
#include <emscripten/emscripten.h>
EM_JS_DEPS(sdlsysurl, "$UTF8ToString");
int SDL_SYS_OpenURL(const char *url)
{
EM_ASM({
window.open(UTF8ToString($0), "_blank");
},
url);
EM_ASM(window.open(UTF8ToString($0), "_blank"), url);
return 0;
}

View file

@ -32,6 +32,18 @@ int SDL_SYS_OpenURL(const char *url)
{
const pid_t pid1 = fork();
if (pid1 == 0) { /* child process */
#ifdef USE_POSIX_SPAWN
pid_t pid2;
const char *args[] = { "xdg-open", url, NULL };
/* Clear LD_PRELOAD so Chrome opens correctly when this application is launched by Steam */
unsetenv("LD_PRELOAD");
if (posix_spawnp(&pid2, args[0], NULL, NULL, (char **)args, environ) == 0) {
/* Child process doesn't wait for possibly-blocking grandchild. */
_exit(EXIT_SUCCESS);
} else {
_exit(EXIT_FAILURE);
}
#else
pid_t pid2;
/* Clear LD_PRELOAD so Chrome opens correctly when this application is launched by Steam */
unsetenv("LD_PRELOAD");
@ -46,6 +58,7 @@ int SDL_SYS_OpenURL(const char *url)
/* Child process doesn't wait for possibly-blocking grandchild. */
_exit(EXIT_SUCCESS);
}
#endif /* USE_POSIX_SPAWN */
} else if (pid1 < 0) {
return SDL_SetError("fork() failed: %s", strerror(errno));
} else {

View file

@ -2481,7 +2481,7 @@ int SDL_RenderSetClipRect(SDL_Renderer *renderer, const SDL_Rect *rect)
int retval;
CHECK_RENDERER_MAGIC(renderer, -1)
if (rect && rect->w > 0 && rect->h > 0) {
if (rect && rect->w >= 0 && rect->h >= 0) {
renderer->clipping_enabled = SDL_TRUE;
renderer->clip_rect.x = (double)rect->x * renderer->scale.x;
renderer->clip_rect.y = (double)rect->y * renderer->scale.y;

View file

@ -2143,7 +2143,7 @@ static int D3D11_RenderReadPixels(SDL_Renderer *renderer, const SDL_Rect *rect,
D3D11_BOX srcBox;
D3D11_MAPPED_SUBRESOURCE textureMemory;
ID3D11DeviceContext_OMGetRenderTargets(data->d3dContext, 1, &renderTargetView, NULL);
renderTargetView = D3D11_GetCurrentRenderTargetView(renderer);
if (renderTargetView == NULL) {
SDL_SetError("%s, ID3D11DeviceContext::OMGetRenderTargets failed", __FUNCTION__);
goto done;

View file

@ -2609,6 +2609,7 @@ static int D3D12_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd,
case SDL_RENDERCMD_SETCLIPRECT:
{
const SDL_Rect *rect = &cmd->data.cliprect.rect;
SDL_Rect viewport_cliprect;
if (rendererData->currentCliprectEnabled != cmd->data.cliprect.enabled) {
rendererData->currentCliprectEnabled = cmd->data.cliprect.enabled;
rendererData->cliprectDirty = SDL_TRUE;
@ -2616,7 +2617,11 @@ static int D3D12_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd,
if (!rendererData->currentCliprectEnabled) {
/* If the clip rect is disabled, then the scissor rect should be the whole viewport,
since direct3d12 doesn't allow disabling the scissor rectangle */
rect = &rendererData->currentViewport;
viewport_cliprect.x = 0;
viewport_cliprect.y = 0;
viewport_cliprect.w = rendererData->currentViewport.w;
viewport_cliprect.h = rendererData->currentViewport.h;
rect = &viewport_cliprect;
}
if (SDL_memcmp(&rendererData->currentCliprect, rect, sizeof(*rect)) != 0) {
SDL_copyp(&rendererData->currentCliprect, rect);

View file

@ -1654,8 +1654,22 @@ static SDL_Renderer *METAL_CreateRenderer(SDL_Window * window, Uint32 flags)
return NULL;
}
// !!! FIXME: MTLCopyAllDevices() can find other GPUs on macOS...
mtldevice = MTLCreateSystemDefaultDevice();
#ifdef __MACOSX__
if (SDL_GetHintBoolean(SDL_HINT_RENDER_METAL_PREFER_LOW_POWER_DEVICE, SDL_TRUE)) {
NSArray<id<MTLDevice>> *devices = MTLCopyAllDevices();
for (id<MTLDevice> device in devices) {
if (device.isLowPower) {
mtldevice = device;
break;
}
}
}
#endif
if (mtldevice == nil) {
mtldevice = MTLCreateSystemDefaultDevice();
}
if (mtldevice == nil) {
SDL_free(renderer);

View file

@ -795,17 +795,13 @@ char *SDL_iconv_string(const char *tocode, const char *fromcode, const char *inb
size_t outbytesleft;
size_t retCode = 0;
cd = SDL_iconv_open(tocode, fromcode);
if (cd == (SDL_iconv_t)-1) {
/* See if we can recover here (fixes iconv on Solaris 11) */
if (tocode == NULL || !*tocode) {
tocode = "UTF-8";
}
if (fromcode == NULL || !*fromcode) {
fromcode = "UTF-8";
}
cd = SDL_iconv_open(tocode, fromcode);
if (tocode == NULL || !*tocode) {
tocode = "UTF-8";
}
if (fromcode == NULL || !*fromcode) {
fromcode = "UTF-8";
}
cd = SDL_iconv_open(tocode, fromcode);
if (cd == (SDL_iconv_t)-1) {
return NULL;
}

View file

@ -1190,7 +1190,9 @@ int SDL_vsscanf(const char *text, const char *fmt, va_list ap)
suppress = SDL_TRUE;
break;
case 'h':
if (inttype > DO_SHORT) {
if (inttype == DO_INT) {
inttype = DO_SHORT;
} else if (inttype > DO_SHORT) {
++inttype;
}
break;

View file

@ -36,6 +36,25 @@
/* Counter for _CompareSurface calls; used for filename creation when comparisons fail */
static int _CompareSurfaceCount = 0;
static Uint32
GetPixel(Uint8 *p, size_t bytes_per_pixel)
{
Uint32 ret = 0;
SDL_assert(bytes_per_pixel <= sizeof(ret));
/* Fill the appropriate number of least-significant bytes of ret,
* leaving the most-significant bytes set to zero, so that ret can
* be decoded with SDL_GetRGBA afterwards. */
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
SDL_memcpy(((Uint8 *) &ret) + (sizeof(ret) - bytes_per_pixel), p, bytes_per_pixel);
#else
SDL_memcpy(&ret, p, bytes_per_pixel);
#endif
return ret;
}
/* Compare surfaces */
int SDLTest_CompareSurfaces(SDL_Surface *surface, SDL_Surface *referenceSurface, int allowable_error)
{
@ -74,11 +93,14 @@ int SDLTest_CompareSurfaces(SDL_Surface *surface, SDL_Surface *referenceSurface,
/* Compare image - should be same format. */
for (j = 0; j < surface->h; j++) {
for (i = 0; i < surface->w; i++) {
Uint32 pixel;
p = (Uint8 *)surface->pixels + j * surface->pitch + i * bpp;
p_reference = (Uint8 *)referenceSurface->pixels + j * referenceSurface->pitch + i * bpp_reference;
SDL_GetRGBA(*(Uint32 *)p, surface->format, &R, &G, &B, &A);
SDL_GetRGBA(*(Uint32 *)p_reference, referenceSurface->format, &Rd, &Gd, &Bd, &Ad);
pixel = GetPixel(p, bpp);
SDL_GetRGBA(pixel, surface->format, &R, &G, &B, &A);
pixel = GetPixel(p_reference, bpp_reference);
SDL_GetRGBA(pixel, referenceSurface->format, &Rd, &Gd, &Bd, &Ad);
dist = 0;
dist += (R - Rd) * (R - Rd);

View file

@ -71,10 +71,8 @@ static SDL_mutex *SDL_CreateMutex_srw(void)
static void SDL_DestroyMutex_srw(SDL_mutex *mutex)
{
if (mutex != NULL) {
/* There are no kernel allocated resources */
SDL_free(mutex);
}
/* There are no kernel allocated resources */
SDL_free(mutex);
}
static int SDL_LockMutex_srw(SDL_mutex *_mutex) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doesn't know about NULL mutexes */
@ -82,10 +80,6 @@ static int SDL_LockMutex_srw(SDL_mutex *_mutex) SDL_NO_THREAD_SAFETY_ANALYSIS /*
SDL_mutex_srw *mutex = (SDL_mutex_srw *)_mutex;
DWORD this_thread;
if (mutex == NULL) {
return 0;
}
this_thread = GetCurrentThreadId();
if (mutex->owner == this_thread) {
++mutex->count;
@ -108,10 +102,6 @@ static int SDL_TryLockMutex_srw(SDL_mutex *_mutex)
DWORD this_thread;
int retval = 0;
if (mutex == NULL) {
return 0;
}
this_thread = GetCurrentThreadId();
if (mutex->owner == this_thread) {
++mutex->count;
@ -131,10 +121,6 @@ static int SDL_UnlockMutex_srw(SDL_mutex *_mutex) SDL_NO_THREAD_SAFETY_ANALYSIS
{
SDL_mutex_srw *mutex = (SDL_mutex_srw *)_mutex;
if (mutex == NULL) {
return 0;
}
if (mutex->owner == GetCurrentThreadId()) {
if (--mutex->count == 0) {
mutex->owner = 0;
@ -185,19 +171,15 @@ static SDL_mutex *SDL_CreateMutex_cs(void)
static void SDL_DestroyMutex_cs(SDL_mutex *mutex_)
{
SDL_mutex_cs *mutex = (SDL_mutex_cs *)mutex_;
if (mutex != NULL) {
DeleteCriticalSection(&mutex->cs);
SDL_free(mutex);
}
DeleteCriticalSection(&mutex->cs);
SDL_free(mutex);
}
/* Lock the mutex */
static int SDL_LockMutex_cs(SDL_mutex *mutex_) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doesn't know about NULL mutexes */
{
SDL_mutex_cs *mutex = (SDL_mutex_cs *)mutex_;
if (mutex == NULL) {
return 0;
}
EnterCriticalSection(&mutex->cs);
return 0;
@ -208,9 +190,6 @@ static int SDL_TryLockMutex_cs(SDL_mutex *mutex_)
{
SDL_mutex_cs *mutex = (SDL_mutex_cs *)mutex_;
int retval = 0;
if (mutex == NULL) {
return 0;
}
if (TryEnterCriticalSection(&mutex->cs) == 0) {
retval = SDL_MUTEX_TIMEDOUT;
@ -222,9 +201,6 @@ static int SDL_TryLockMutex_cs(SDL_mutex *mutex_)
static int SDL_UnlockMutex_cs(SDL_mutex *mutex_) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doesn't know about NULL mutexes */
{
SDL_mutex_cs *mutex = (SDL_mutex_cs *)mutex_;
if (mutex == NULL) {
return 0;
}
LeaveCriticalSection(&mutex->cs);
return 0;
@ -277,21 +253,35 @@ SDL_mutex *SDL_CreateMutex(void)
void SDL_DestroyMutex(SDL_mutex *mutex)
{
SDL_mutex_impl_active.Destroy(mutex);
if (mutex) {
SDL_mutex_impl_active.Destroy(mutex);
}
}
int SDL_LockMutex(SDL_mutex *mutex)
{
if (mutex == NULL) {
return 0;
}
return SDL_mutex_impl_active.Lock(mutex);
}
int SDL_TryLockMutex(SDL_mutex *mutex)
{
if (mutex == NULL) {
return 0;
}
return SDL_mutex_impl_active.TryLock(mutex);
}
int SDL_UnlockMutex(SDL_mutex *mutex)
{
if (mutex == NULL) {
return 0;
}
return SDL_mutex_impl_active.Unlock(mutex);
}

View file

@ -55,12 +55,12 @@ static DWORD RunThread(void *data)
return 0;
}
static DWORD WINAPI RunThreadViaCreateThread(LPVOID data)
static DWORD WINAPI MINGW32_FORCEALIGN RunThreadViaCreateThread(LPVOID data)
{
return RunThread(data);
}
static unsigned __stdcall RunThreadViaBeginThreadEx(void *data)
static unsigned __stdcall MINGW32_FORCEALIGN RunThreadViaBeginThreadEx(void *data)
{
return (unsigned)RunThread(data);
}

View file

@ -18,6 +18,7 @@
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "../SDL_internal.h"
/* The high-level video driver subsystem */
@ -127,15 +128,15 @@ static VideoBootStrap *bootstrap[] = {
#if SDL_VIDEO_DRIVER_QNX
&QNX_bootstrap,
#endif
#if SDL_VIDEO_DRIVER_OFFSCREEN
&OFFSCREEN_bootstrap,
#if SDL_VIDEO_DRIVER_OS2
&OS2DIVE_bootstrap,
&OS2VMAN_bootstrap,
#endif
#if SDL_VIDEO_DRIVER_NGAGE
&NGAGE_bootstrap,
#endif
#if SDL_VIDEO_DRIVER_OS2
&OS2DIVE_bootstrap,
&OS2VMAN_bootstrap,
#if SDL_VIDEO_DRIVER_OFFSCREEN
&OFFSCREEN_bootstrap,
#endif
#if SDL_VIDEO_DRIVER_DUMMY
&DUMMY_bootstrap,
@ -1398,6 +1399,9 @@ static int SDL_UpdateFullscreenMode(SDL_Window *window, SDL_bool fullscreen)
#endif
display = SDL_GetDisplayForWindow(window);
if (display == NULL) { /* No display connected, nothing to do. */
return 0;
}
if (fullscreen) {
/* Hide any other fullscreen windows */

View file

@ -40,6 +40,8 @@ typedef struct {
/* What location we last saw the cursor move to. */
CGFloat lastMoveX;
CGFloat lastMoveY;
/* If we just turned on relative mode, and should skip a single mouse motion event. */
SDL_bool justEnabledRelative;
} SDL_MouseData;
@interface NSCursor (InvisibleCursor)

View file

@ -293,8 +293,11 @@ static int Cocoa_SetRelativeMouseMode(SDL_bool enabled)
if (enabled) {
if (window) {
/* make sure the mouse isn't at the corner of the window, as this can confuse things if macOS thinks a window resize is happening on the first click. */
SDL_MouseData *mousedriverdata = (SDL_MouseData*)SDL_GetMouse()->driverdata;
const CGPoint point = CGPointMake((float)(window->x + (window->w / 2)), (float)(window->y + (window->h / 2)));
Cocoa_HandleMouseWarp(point.x, point.y);
if (mousedriverdata) {
mousedriverdata->justEnabledRelative = SDL_TRUE;
}
CGWarpMouseCursorPosition(point);
}
DLog("Turning on.");
@ -465,6 +468,11 @@ void Cocoa_HandleMouseEvent(_THIS, NSEvent *event)
seenWarp = driverdata->seenWarp;
driverdata->seenWarp = NO;
if (driverdata->justEnabledRelative) {
driverdata->justEnabledRelative = SDL_FALSE;
return; // dump the first event back.
}
location = [NSEvent mouseLocation];
lastMoveX = driverdata->lastMoveX;
lastMoveY = driverdata->lastMoveY;

View file

@ -31,6 +31,15 @@
#include "../../events/SDL_mouse_c.h"
/* older Emscriptens don't have this, but we need to for wasm64 compatibility. */
#ifndef MAIN_THREAD_EM_ASM_PTR
#ifdef __wasm64__
#error You need to upgrade your Emscripten compiler to support wasm64
#else
#define MAIN_THREAD_EM_ASM_PTR MAIN_THREAD_EM_ASM_INT
#endif
#endif
static SDL_Cursor *Emscripten_CreateCursorFromString(const char *cursor_str, SDL_bool is_custom)
{
SDL_Cursor *cursor;
@ -60,6 +69,8 @@ static SDL_Cursor *Emscripten_CreateDefaultCursor()
return Emscripten_CreateCursorFromString("default", SDL_FALSE);
}
EM_JS_DEPS(sdlmouse, "$stringToUTF8,$UTF8ToString");
static SDL_Cursor *Emscripten_CreateCursor(SDL_Surface *surface, int hot_x, int hot_y)
{
const char *cursor_url = NULL;
@ -72,7 +83,7 @@ static SDL_Cursor *Emscripten_CreateCursor(SDL_Surface *surface, int hot_x, int
}
/* *INDENT-OFF* */ /* clang-format off */
cursor_url = (const char *)MAIN_THREAD_EM_ASM_INT({
cursor_url = (const char *)MAIN_THREAD_EM_ASM_PTR({
var w = $0;
var h = $1;
var hot_x = $2;

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -412,6 +412,9 @@ extern int SDL_AppleTVRemoteOpenedAsJoystick;
SDL_SendKeyboardKey(SDL_PRESSED, scancode);
}
}
if (SDL_IsTextInputActive()) {
[super pressesBegan:presses withEvent:event];
}
}
- (void)pressesEnded:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event
@ -422,6 +425,9 @@ extern int SDL_AppleTVRemoteOpenedAsJoystick;
SDL_SendKeyboardKey(SDL_RELEASED, scancode);
}
}
if (SDL_IsTextInputActive()) {
[super pressesEnded:presses withEvent:event];
}
}
- (void)pressesCancelled:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event
@ -432,11 +438,17 @@ extern int SDL_AppleTVRemoteOpenedAsJoystick;
SDL_SendKeyboardKey(SDL_RELEASED, scancode);
}
}
if (SDL_IsTextInputActive()) {
[super pressesCancelled:presses withEvent:event];
}
}
- (void)pressesChanged:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event
{
/* This is only called when the force of a press changes. */
if (SDL_IsTextInputActive()) {
[super pressesChanged:presses withEvent:event];
}
}
#endif /* TARGET_OS_TV || defined(__IPHONE_9_1) */

View file

@ -74,6 +74,7 @@ SDL_HideHomeIndicatorHintChanged(void *userdata, const char *name, const char *o
UITextField *textField;
BOOL hardwareKeyboard;
BOOL showingKeyboard;
BOOL hidingKeyboard;
BOOL rotatingOrientation;
NSString *committedText;
NSString *obligateForBackspace;
@ -91,6 +92,7 @@ SDL_HideHomeIndicatorHintChanged(void *userdata, const char *name, const char *o
[self initKeyboard];
hardwareKeyboard = NO;
showingKeyboard = NO;
hidingKeyboard = NO;
rotatingOrientation = NO;
#endif
@ -277,8 +279,22 @@ SDL_HideHomeIndicatorHintChanged(void *userdata, const char *name, const char *o
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
#if !TARGET_OS_TV
[center addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[center addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
[center addObserver:self
selector:@selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil];
[center addObserver:self
selector:@selector(keyboardDidShow:)
name:UIKeyboardDidShowNotification
object:nil];
[center addObserver:self
selector:@selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification
object:nil];
[center addObserver:self
selector:@selector(keyboardDidHide:)
name:UIKeyboardDidHideNotification
object:nil];
#endif
[center addObserver:self selector:@selector(textFieldTextDidChange:) name:UITextFieldTextDidChangeNotification object:nil];
}
@ -341,8 +357,18 @@ SDL_HideHomeIndicatorHintChanged(void *userdata, const char *name, const char *o
{
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
#if !TARGET_OS_TV
[center removeObserver:self name:UIKeyboardWillShowNotification object:nil];
[center removeObserver:self name:UIKeyboardWillHideNotification object:nil];
[center removeObserver:self
name:UIKeyboardWillShowNotification
object:nil];
[center removeObserver:self
name:UIKeyboardDidShowNotification
object:nil];
[center removeObserver:self
name:UIKeyboardWillHideNotification
object:nil];
[center removeObserver:self
name:UIKeyboardDidHideNotification
object:nil];
#endif
[center removeObserver:self name:UITextFieldTextDidChangeNotification object:nil];
}
@ -350,23 +376,40 @@ SDL_HideHomeIndicatorHintChanged(void *userdata, const char *name, const char *o
/* reveal onscreen virtual keyboard */
- (void)showKeyboard
{
if (keyboardVisible) {
return;
}
keyboardVisible = YES;
if (textField.window) {
showingKeyboard = YES;
[textField becomeFirstResponder];
showingKeyboard = NO;
}
}
/* hide onscreen virtual keyboard */
- (void)hideKeyboard
{
if (!keyboardVisible) {
return;
}
keyboardVisible = NO;
[textField resignFirstResponder];
if (textField.window) {
hidingKeyboard = YES;
[textField resignFirstResponder];
}
}
- (void)keyboardWillShow:(NSNotification *)notification
{
BOOL shouldStartTextInput = NO;
if (!SDL_IsTextInputActive() && !hidingKeyboard && !rotatingOrientation) {
shouldStartTextInput = YES;
}
showingKeyboard = YES;
#if !TARGET_OS_TV
CGRect kbrect = [[notification userInfo][UIKeyboardFrameEndUserInfoKey] CGRectValue];
@ -376,14 +419,36 @@ SDL_HideHomeIndicatorHintChanged(void *userdata, const char *name, const char *o
[self setKeyboardHeight:(int)kbrect.size.height];
#endif
if (shouldStartTextInput) {
SDL_StartTextInput();
}
}
- (void)keyboardDidShow:(NSNotification *)notification
{
showingKeyboard = NO;
}
- (void)keyboardWillHide:(NSNotification *)notification
{
if (!showingKeyboard && !rotatingOrientation) {
BOOL shouldStopTextInput = NO;
if (SDL_IsTextInputActive() && !showingKeyboard && !rotatingOrientation) {
shouldStopTextInput = YES;
}
hidingKeyboard = YES;
[self setKeyboardHeight:0];
if (shouldStopTextInput) {
SDL_StopTextInput();
}
[self setKeyboardHeight:0];
}
- (void)keyboardDidHide:(NSNotification *)notification
{
hidingKeyboard = NO;
}
- (void)textFieldTextDidChange:(NSNotification *)notification
@ -402,8 +467,8 @@ SDL_HideHomeIndicatorHintChanged(void *userdata, const char *name, const char *o
size_t deleteLength = SDL_utf8strlen([[committedText substringFromIndex:matchLength] UTF8String]);
while (deleteLength > 0) {
/* Send distinct down and up events for each backspace action */
SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_BACKSPACE);
SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_BACKSPACE);
SDL_SendVirtualKeyboardKey(SDL_PRESSED, SDL_SCANCODE_BACKSPACE);
SDL_SendVirtualKeyboardKey(SDL_RELEASED, SDL_SCANCODE_BACKSPACE);
--deleteLength;
}
}

View file

@ -37,34 +37,30 @@ typedef struct
const char *libname;
} waylanddynlib;
#ifndef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_EGL
#define SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_EGL NULL
#endif
#ifndef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_CURSOR
#define SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_CURSOR NULL
#endif
#ifndef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_XKBCOMMON
#define SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_XKBCOMMON NULL
#endif
#ifndef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_LIBDECOR
#define SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_LIBDECOR NULL
#endif
static waylanddynlib waylandlibs[] = {
{ NULL, SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC },
#ifdef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_EGL
{ NULL, SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_EGL },
#endif
#ifdef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_CURSOR
{ NULL, SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_CURSOR },
#endif
#ifdef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_XKBCOMMON
{ NULL, SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_XKBCOMMON },
{ NULL, SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_LIBDECOR }
#endif
#ifdef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_LIBDECOR
{ NULL, SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_LIBDECOR },
#endif
{ NULL, NULL }
};
static void *WAYLAND_GetSym(const char *fnname, int *pHasModule, SDL_bool required)
{
int i;
void *fn = NULL;
for (i = 0; i < SDL_TABLESIZE(waylandlibs); i++) {
if (waylandlibs[i].lib != NULL) {
fn = SDL_LoadFunction(waylandlibs[i].lib, fnname);
waylanddynlib *dynlib;
for (dynlib = waylandlibs; dynlib->libname; dynlib++) {
if (dynlib->lib != NULL) {
fn = SDL_LoadFunction(dynlib->lib, fnname);
if (fn != NULL) {
break;
}
@ -72,10 +68,11 @@ static void *WAYLAND_GetSym(const char *fnname, int *pHasModule, SDL_bool requir
}
#if DEBUG_DYNAMIC_WAYLAND
if (fn != NULL)
SDL_Log("WAYLAND: Found '%s' in %s (%p)\n", fnname, waylandlibs[i].libname, fn);
else
if (fn != NULL) {
SDL_Log("WAYLAND: Found '%s' in %s (%p)\n", fnname, dynlib->libname, fn);
} else {
SDL_Log("WAYLAND: Symbol '%s' NOT FOUND!\n", fnname);
}
#endif
if (fn == NULL && required) {

View file

@ -33,162 +33,220 @@
#include "SDL_waylandmessagebox.h"
#define ZENITY_VERSION_LEN 32 /* Number of bytes to read from zenity --version (including NUL)*/
#define MAX_BUTTONS 8 /* Maximum number of buttons supported */
int Wayland_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
{
int fd_pipe[2]; /* fd_pipe[0]: read end of pipe, fd_pipe[1]: write end of pipe */
static int run_zenity(const char **args, int fd_pipe[2]) {
int status;
pid_t pid1;
if (messageboxdata->numbuttons > MAX_BUTTONS) {
return SDL_SetError("Too many buttons (%d max allowed)", MAX_BUTTONS);
}
if (pipe(fd_pipe) != 0) { /* create a pipe */
return SDL_SetError("pipe() failed: %s", strerror(errno));
}
pid1 = fork();
if (pid1 == 0) { /* child process */
int argc = 5, i;
const char *argv[5 + 2 /* icon name */ + 2 /* title */ + 2 /* message */ + 2 * MAX_BUTTONS + 1 /* NULL */] = {
"zenity", "--question", "--switch", "--no-wrap", "--no-markup"
};
close(fd_pipe[0]); /* no reading from pipe */
/* write stdout in pipe */
if (dup2(fd_pipe[1], STDOUT_FILENO) == -1) {
_exit(128);
}
argv[argc++] = "--icon-name";
switch (messageboxdata->flags) {
case SDL_MESSAGEBOX_ERROR:
argv[argc++] = "dialog-error";
break;
case SDL_MESSAGEBOX_WARNING:
argv[argc++] = "dialog-warning";
break;
case SDL_MESSAGEBOX_INFORMATION:
default:
argv[argc++] = "dialog-information";
break;
}
if (messageboxdata->title && messageboxdata->title[0]) {
argv[argc++] = "--title";
argv[argc++] = messageboxdata->title;
} else {
argv[argc++] = "--title=\"\"";
}
if (messageboxdata->message && messageboxdata->message[0]) {
argv[argc++] = "--text";
argv[argc++] = messageboxdata->message;
} else {
argv[argc++] = "--text=\"\"";
}
for (i = 0; i < messageboxdata->numbuttons; ++i) {
if (messageboxdata->buttons[i].text && messageboxdata->buttons[i].text[0]) {
argv[argc++] = "--extra-button";
argv[argc++] = messageboxdata->buttons[i].text;
} else {
argv[argc++] = "--extra-button=\"\"";
}
}
argv[argc] = NULL;
/* const casting argv is fine:
* https://pubs.opengroup.org/onlinepubs/9699919799/functions/fexecve.html -> rational
*/
execvp("zenity", (char **)argv);
execvp("zenity", (char **)args);
_exit(129);
} else if (pid1 < 0) {
close(fd_pipe[0]);
close(fd_pipe[1]);
} else if (pid1 < 0) { /* fork() failed */
return SDL_SetError("fork() failed: %s", strerror(errno));
} else {
int status;
if (waitpid(pid1, &status, 0) == pid1) {
if (WIFEXITED(status)) {
if (WEXITSTATUS(status) < 128) {
int i;
size_t output_len = 1;
char *output = NULL;
char *tmp = NULL;
FILE *outputfp = NULL;
close(fd_pipe[1]); /* no writing to pipe */
/* At this point, if no button ID is needed, we can just bail as soon as the
* process has completed.
*/
if (buttonid == NULL) {
close(fd_pipe[0]);
return 0;
}
*buttonid = -1;
/* find button with longest text */
for (i = 0; i < messageboxdata->numbuttons; ++i) {
if (messageboxdata->buttons[i].text != NULL) {
const size_t button_len = SDL_strlen(messageboxdata->buttons[i].text);
if (button_len > output_len) {
output_len = button_len;
}
}
}
output = SDL_malloc(output_len + 1);
if (output == NULL) {
close(fd_pipe[0]);
return SDL_OutOfMemory();
}
output[0] = '\0';
outputfp = fdopen(fd_pipe[0], "r");
if (outputfp == NULL) {
SDL_free(output);
close(fd_pipe[0]);
return SDL_SetError("Couldn't open pipe for reading: %s", strerror(errno));
}
tmp = fgets(output, output_len + 1, outputfp);
(void)fclose(outputfp);
if ((tmp == NULL) || (*tmp == '\0') || (*tmp == '\n')) {
SDL_free(output);
return 0; /* User simply closed the dialog */
}
/* It likes to add a newline... */
tmp = SDL_strrchr(output, '\n');
if (tmp != NULL) {
*tmp = '\0';
}
/* Check which button got pressed */
for (i = 0; i < messageboxdata->numbuttons; i += 1) {
if (messageboxdata->buttons[i].text != NULL) {
if (SDL_strcmp(output, messageboxdata->buttons[i].text) == 0) {
*buttonid = messageboxdata->buttons[i].buttonid;
break;
}
}
}
SDL_free(output);
return 0; /* success! */
} else {
return SDL_SetError("zenity reported error or failed to launch: %d", WEXITSTATUS(status));
}
} else {
return SDL_SetError("zenity failed for some reason");
}
} else {
} else { /* parent process */
close(fd_pipe[1]); /* no writing to the pipe */
if (waitpid(pid1, &status, 0) != pid1) {
return SDL_SetError("Waiting on zenity failed: %s", strerror(errno));
}
if (!WIFEXITED(status)) {
return SDL_SetError("zenity failed for some reason");
}
if (WEXITSTATUS(status) >= 128) {
return SDL_SetError("zenity reported error or failed to launch: %d", WEXITSTATUS(status));
}
return 0; /* success! */
}
}
static int get_zenity_version(int *major, int *minor) {
int fd_pipe[2]; /* fd_pipe[0]: read end of pipe, fd_pipe[1]: write end of pipe */
const char *argv[] = { "zenity", "--version", NULL };
if (pipe(fd_pipe) != 0) { /* create a pipe */
return SDL_SetError("pipe() failed: %s", strerror(errno));
}
if (run_zenity(argv, fd_pipe) == 0) {
FILE *outputfp = NULL;
char version_str[ZENITY_VERSION_LEN];
char *version_ptr = NULL, *end_ptr = NULL;
int tmp;
outputfp = fdopen(fd_pipe[0], "r");
if (outputfp == NULL) {
close(fd_pipe[0]);
return SDL_SetError("failed to open pipe for reading: %s", strerror(errno));
}
version_ptr = fgets(version_str, ZENITY_VERSION_LEN, outputfp);
(void)fclose(outputfp); /* will close underlying fd */
/* we expect the version string is in the form of MAJOR.MINOR.MICRO
* as described in meson.build. We'll ignore everything after that.
*/
tmp = (int) SDL_strtol(version_ptr, &end_ptr, 10);
if (tmp == 0 && end_ptr == version_ptr) {
return SDL_SetError("failed to get zenity major version number");
}
*major = tmp;
version_ptr = end_ptr + 1; /* skip the dot */
tmp = (int) SDL_strtol(version_ptr, &end_ptr, 10);
if (tmp == 0 && end_ptr == version_ptr) {
return SDL_SetError("failed to get zenity minor version number");
}
*minor = tmp;
return 0; /* success */
}
close(fd_pipe[0]);
close(fd_pipe[1]);
return -1; /* run_zenity should've called SDL_SetError() */
}
int Wayland_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid) {
int fd_pipe[2]; /* fd_pipe[0]: read end of pipe, fd_pipe[1]: write end of pipe */
int zenity_major = 0, zenity_minor = 0, output_len = 0;
int argc = 5, i;
const char *argv[5 + 2 /* icon name */ + 2 /* title */ + 2 /* message */ + 2 * MAX_BUTTONS + 1 /* NULL */] = {
"zenity", "--question", "--switch", "--no-wrap", "--no-markup"
};
if (messageboxdata->numbuttons > MAX_BUTTONS) {
return SDL_SetError("Too many buttons (%d max allowed)", MAX_BUTTONS);
}
/* get zenity version so we know which arg to use */
if (get_zenity_version(&zenity_major, &zenity_minor) != 0) {
return -1; /* get_zenity_version() calls SDL_SetError(), so message is already set */
}
if (pipe(fd_pipe) != 0) { /* create a pipe */
return SDL_SetError("pipe() failed: %s", strerror(errno));
}
/* https://gitlab.gnome.org/GNOME/zenity/-/commit/c686bdb1b45e95acf010efd9ca0c75527fbb4dea
* This commit removed --icon-name without adding a deprecation notice.
* We need to handle it gracefully, otherwise no message box will be shown.
*/
argv[argc++] = zenity_major > 3 || (zenity_major == 3 && zenity_minor >= 90) ? "--icon" : "--icon-name";
switch (messageboxdata->flags) {
case SDL_MESSAGEBOX_ERROR:
argv[argc++] = "dialog-error";
break;
case SDL_MESSAGEBOX_WARNING:
argv[argc++] = "dialog-warning";
break;
case SDL_MESSAGEBOX_INFORMATION:
default:
argv[argc++] = "dialog-information";
break;
}
if (messageboxdata->title && messageboxdata->title[0]) {
argv[argc++] = "--title";
argv[argc++] = messageboxdata->title;
} else {
argv[argc++] = "--title=\"\"";
}
if (messageboxdata->message && messageboxdata->message[0]) {
argv[argc++] = "--text";
argv[argc++] = messageboxdata->message;
} else {
argv[argc++] = "--text=\"\"";
}
for (i = 0; i < messageboxdata->numbuttons; ++i) {
if (messageboxdata->buttons[i].text && messageboxdata->buttons[i].text[0]) {
int len = SDL_strlen(messageboxdata->buttons[i].text);
if (len > output_len) {
output_len = len;
}
argv[argc++] = "--extra-button";
argv[argc++] = messageboxdata->buttons[i].text;
} else {
argv[argc++] = "--extra-button=\"\"";
}
}
argv[argc] = NULL;
if (run_zenity(argv, fd_pipe) == 0) {
FILE *outputfp = NULL;
char *output = NULL;
char *tmp = NULL;
if (buttonid == NULL) {
/* if we don't need buttonid, we can return immediately */
close(fd_pipe[0]);
return 0; /* success */
}
*buttonid = -1;
output = SDL_malloc(output_len + 1);
if (output == NULL) {
close(fd_pipe[0]);
return SDL_OutOfMemory();
}
output[0] = '\0';
outputfp = fdopen(fd_pipe[0], "r");
if (outputfp == NULL) {
SDL_free(output);
close(fd_pipe[0]);
return SDL_SetError("Couldn't open pipe for reading: %s", strerror(errno));
}
tmp = fgets(output, output_len + 1, outputfp);
(void)fclose(outputfp);
if ((tmp == NULL) || (*tmp == '\0') || (*tmp == '\n')) {
SDL_free(output);
return 0; /* User simply closed the dialog */
}
/* It likes to add a newline... */
tmp = SDL_strrchr(output, '\n');
if (tmp != NULL) {
*tmp = '\0';
}
/* Check which button got pressed */
for (i = 0; i < messageboxdata->numbuttons; i += 1) {
if (messageboxdata->buttons[i].text != NULL) {
if (SDL_strcmp(output, messageboxdata->buttons[i].text) == 0) {
*buttonid = messageboxdata->buttons[i].buttonid;
break;
}
}
}
SDL_free(output);
return 0; /* success! */
}
close(fd_pipe[0]);
close(fd_pipe[1]);
return -1; /* run_zenity() calls SDL_SetError(), so message is already set */
}
#endif /* SDL_VIDEO_DRIVER_WAYLAND */
/* vi: set ts=4 sw=4 expandtab: */

View file

@ -59,12 +59,13 @@ SDL_FORCE_INLINE SDL_bool FloatEqual(float a, float b)
static void GetFullScreenDimensions(SDL_Window *window, int *width, int *height, int *drawable_width, int *drawable_height)
{
SDL_WindowData *wind = (SDL_WindowData *)window->driverdata;
SDL_WaylandOutputData *output = (SDL_WaylandOutputData *)SDL_GetDisplayForWindow(window)->driverdata;
SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
SDL_WaylandOutputData *output = display ? (SDL_WaylandOutputData *)display->driverdata : NULL;
int fs_width, fs_height;
int buf_width, buf_height;
const int output_width = wind->fs_output_width ? wind->fs_output_width : output->width;
const int output_height = wind->fs_output_height ? wind->fs_output_height : output->height;
const int output_width = wind->fs_output_width ? wind->fs_output_width : (output ? output->width : wind->window_width);
const int output_height = wind->fs_output_height ? wind->fs_output_height : (output ? output->height : wind->window_height);
/*
* Fullscreen desktop mandates a desktop sized window, so that's what applications will get.
@ -133,7 +134,10 @@ static SDL_bool NeedViewport(SDL_Window *window)
{
SDL_WindowData *wind = window->driverdata;
SDL_VideoData *video = wind->waylandData;
SDL_WaylandOutputData *output = ((SDL_WaylandOutputData *)SDL_GetDisplayForWindow(window)->driverdata);
SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
SDL_WaylandOutputData *output = display ? ((SDL_WaylandOutputData *)display->driverdata) : NULL;
const int output_width = wind->fs_output_width ? wind->fs_output_width : (output ? output->width : wind->window_width);
const int output_height = wind->fs_output_height ? wind->fs_output_height : (output ? output->height : wind->window_height);
int fs_width, fs_height;
/*
@ -144,7 +148,7 @@ static SDL_bool NeedViewport(SDL_Window *window)
if (video->viewporter != NULL) {
if (FullscreenModeEmulation(window)) {
GetFullScreenDimensions(window, &fs_width, &fs_height, NULL, NULL);
if (fs_width != output->width || fs_height != output->height) {
if (fs_width != output_width || fs_height != output_height) {
return SDL_TRUE;
}
} else if (SurfaceScaleIsFractional(window) && (window->flags & SDL_WINDOW_ALLOW_HIGHDPI)) {
@ -217,7 +221,8 @@ static void ConfigureWindowGeometry(SDL_Window *window)
{
SDL_WindowData *data = window->driverdata;
SDL_VideoData *viddata = data->waylandData;
SDL_WaylandOutputData *output = (SDL_WaylandOutputData *)SDL_GetDisplayForWindow(window)->driverdata;
SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
SDL_WaylandOutputData *output = display ? (SDL_WaylandOutputData *)display->driverdata : NULL;
struct wl_region *region;
const int old_dw = data->drawable_width;
const int old_dh = data->drawable_height;
@ -237,8 +242,8 @@ static void ConfigureWindowGeometry(SDL_Window *window)
if (FullscreenModeEmulation(window) && NeedViewport(window)) {
int fs_width, fs_height;
const int output_width = data->fs_output_width ? data->fs_output_width : output->width;
const int output_height = data->fs_output_height ? data->fs_output_height : output->height;
const int output_width = data->fs_output_width ? data->fs_output_width : (output ? output->width : data->window_width);
const int output_height = data->fs_output_height ? data->fs_output_height : (output ? output->height : data->window_height);
window_size_changed = data->window_width != output_width || data->window_height != output_height;
@ -559,7 +564,6 @@ static void handle_configure_xdg_toplevel(void *data,
{
SDL_WindowData *wind = (SDL_WindowData *)data;
SDL_Window *window = wind->sdlwindow;
SDL_WaylandOutputData *driverdata;
enum xdg_toplevel_state *state;
SDL_bool fullscreen = SDL_FALSE;
@ -586,8 +590,6 @@ static void handle_configure_xdg_toplevel(void *data,
}
}
driverdata = (SDL_WaylandOutputData *)SDL_GetDisplayForWindow(window)->driverdata;
UpdateWindowFullscreen(window, fullscreen);
if (!fullscreen) {
@ -664,12 +666,6 @@ static void handle_configure_xdg_toplevel(void *data,
window->h = height;
wind->needs_resize_event = SDL_TRUE;
}
/* This part is good though. */
if ((window->flags & SDL_WINDOW_ALLOW_HIGHDPI) && !FloatEqual(wind->scale_factor, driverdata->scale_factor)) {
wind->scale_factor = driverdata->scale_factor;
wind->needs_resize_event = SDL_TRUE;
}
}
}
@ -819,12 +815,10 @@ static void decoration_frame_configure(struct libdecor_frame *frame,
{
SDL_WindowData *wind = (SDL_WindowData *)user_data;
SDL_Window *window = wind->sdlwindow;
SDL_WaylandOutputData *driverdata;
struct libdecor_state *state;
enum libdecor_window_state window_state;
int width, height;
float scale_factor = wind->scale_factor;
SDL_bool focused = SDL_FALSE;
SDL_bool fullscreen = SDL_FALSE;
@ -844,8 +838,6 @@ static void decoration_frame_configure(struct libdecor_frame *frame,
}
floating = !(fullscreen || maximized || tiled);
driverdata = (SDL_WaylandOutputData *)SDL_GetDisplayForWindow(window)->driverdata;
UpdateWindowFullscreen(window, fullscreen);
if (!fullscreen) {
@ -887,11 +879,6 @@ static void decoration_frame_configure(struct libdecor_frame *frame,
if (FullscreenModeEmulation(window)) {
GetFullScreenDimensions(window, &width, &height, NULL, NULL);
}
/* This part is good though. */
if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) {
scale_factor = driverdata->scale_factor;
}
} else if (!(window->flags & SDL_WINDOW_RESIZABLE) || (floating && wind->floating_resize_pending)) {
width = window->windowed.w;
height = window->windowed.h;
@ -936,7 +923,7 @@ static void decoration_frame_configure(struct libdecor_frame *frame,
wind->was_floating = floating;
/* Do the resize on the SDL side (this will set window->w/h)... */
Wayland_HandleResize(window, width, height, scale_factor);
Wayland_HandleResize(window, width, height, wind->scale_factor);
/* ... then commit the changes on the libdecor side. */
state = libdecor_state_new(wind->window_width, wind->window_height);
@ -1003,7 +990,7 @@ static const struct qt_extended_surface_listener extended_surface_listener = {
static void update_scale_factor(SDL_WindowData *window)
{
float old_factor = window->scale_factor;
const float old_factor = window->scale_factor;
float new_factor;
int i;
@ -1012,14 +999,18 @@ static void update_scale_factor(SDL_WindowData *window)
return;
}
if (FULLSCREEN_VISIBLE(window->sdlwindow)) {
if (window->num_outputs == 0) {
/* No display connected, just fall back. */
new_factor = old_factor;
} else if (FULLSCREEN_VISIBLE(window->sdlwindow)) {
/* For fullscreen, use the active display's scale factor */
SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window->sdlwindow);
SDL_WaylandOutputData *driverdata = display->driverdata;
new_factor = driverdata->scale_factor;
} else if (window->num_outputs == 0) {
/* No monitor (somehow)? Just fall back. */
new_factor = old_factor;
if (display) {
SDL_WaylandOutputData *driverdata = display->driverdata;
new_factor = driverdata->scale_factor;
} else {
new_factor = old_factor;
}
} else {
/* Check every display's factor, use the highest */
new_factor = 0.0f;

View file

@ -24,6 +24,7 @@
#include "SDL_windowsvideo.h"
#include "SDL_windowswindow.h"
#include "SDL_timer.h"
#include "../../events/SDL_clipboardevents_c.h"
#ifdef UNICODE
@ -102,23 +103,31 @@ int WIN_SetClipboardText(_THIS, const char *text)
char *WIN_GetClipboardText(_THIS)
{
char *text;
char *text = NULL;
text = NULL;
if (IsClipboardFormatAvailable(TEXT_FORMAT) &&
OpenClipboard(GetWindowHandle(_this))) {
HANDLE hMem;
LPTSTR tstr;
if (IsClipboardFormatAvailable(TEXT_FORMAT)) {
/* Retry to open the clipboard in case another application has it open */
const int MAX_ATTEMPTS = 3;
int attempt;
hMem = GetClipboardData(TEXT_FORMAT);
if (hMem) {
tstr = (LPTSTR)GlobalLock(hMem);
text = WIN_StringToUTF8(tstr);
GlobalUnlock(hMem);
} else {
WIN_SetError("Couldn't get clipboard data");
for (attempt = 0; attempt < MAX_ATTEMPTS; ++attempt) {
if (OpenClipboard(GetWindowHandle(_this))) {
HANDLE hMem;
LPTSTR tstr;
hMem = GetClipboardData(TEXT_FORMAT);
if (hMem) {
tstr = (LPTSTR)GlobalLock(hMem);
text = WIN_StringToUTF8(tstr);
GlobalUnlock(hMem);
} else {
WIN_SetError("Couldn't get clipboard data");
}
CloseClipboard();
break;
}
SDL_Delay(10);
}
CloseClipboard();
}
if (text == NULL) {
text = SDL_strdup("");

View file

@ -318,10 +318,13 @@ static void WIN_AddDisplay(_THIS, HMONITOR hMonitor, const MONITORINFOEXW *info,
if (SDL_wcscmp(driverdata->DeviceName, info->szDevice) == 0) {
SDL_bool moved = (index != i);
if (index >= _this->num_displays) {
return;
}
if (moved) {
SDL_VideoDisplay tmp;
SDL_assert(index < _this->num_displays);
SDL_memcpy(&tmp, &_this->displays[index], sizeof(tmp));
SDL_memcpy(&_this->displays[index], &_this->displays[i], sizeof(tmp));
SDL_memcpy(&_this->displays[i], &tmp, sizeof(tmp));

View file

@ -132,10 +132,7 @@ static int SetSelectionText(_THIS, const char *text, Atom selection_type)
X11_GetSDLCutBufferClipboardInternalFormat(display, SDL_X11_CLIPBOARD_MIME_TYPE_STRING), 8, PropModeReplace,
(const unsigned char *)text, SDL_strlen(text));
if (X11_XGetSelectionOwner(display, selection_type) != window) {
X11_XSetSelectionOwner(display, selection_type, window, CurrentTime);
}
X11_XSetSelectionOwner(display, selection_type, window, CurrentTime);
return 0;
}

View file

@ -643,8 +643,9 @@ int X11_InitModes(_THIS)
int xrandr_major, xrandr_minor;
/* require at least XRandR v1.3 */
if (CheckXRandR(data->display, &xrandr_major, &xrandr_minor) &&
(xrandr_major >= 2 || (xrandr_major == 1 && xrandr_minor >= 3))) {
return X11_InitModes_XRandR(_this);
(xrandr_major >= 2 || (xrandr_major == 1 && xrandr_minor >= 3)) &&
X11_InitModes_XRandR(_this) == 0) {
return 0;
}
}
#endif /* SDL_VIDEO_DRIVER_X11_XRANDR */

View file

@ -1180,33 +1180,6 @@ void X11_ShowWindow(_THIS, SDL_Window *window)
if (data->border_left == 0 && data->border_right == 0 && data->border_top == 0 && data->border_bottom == 0) {
X11_GetBorderValues(data);
}
/* Check if the window manager moved us somewhere unexpected, just in case. */
{
int (*prev_handler)(Display *, XErrorEvent *) = NULL;
Window childReturn, root, parent;
Window *children;
unsigned int childCount;
XWindowAttributes attrs;
int x, y;
X11_XSync(display, False);
prev_handler = X11_XSetErrorHandler(X11_CatchAnyError);
caught_x11_error = SDL_FALSE;
X11_XQueryTree(display, data->xwindow, &root, &parent, &children, &childCount);
X11_XGetWindowAttributes(display, data->xwindow, &attrs);
X11_XTranslateCoordinates(display, parent, DefaultRootWindow(display),
attrs.x, attrs.y, &x, &y, &childReturn);
if (!caught_x11_error) {
/* if these values haven't changed from our current beliefs, these don't actually generate events. */
SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MOVED, x, y);
SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, attrs.width, attrs.height);
}
X11_XSetErrorHandler(prev_handler);
caught_x11_error = SDL_FALSE;
}
}
void X11_HideWindow(_THIS, SDL_Window *window)
@ -1328,7 +1301,7 @@ static void SetWindowMaximized(_THIS, SDL_Window *window, SDL_bool maximized)
X11_XSync(display, False);
prev_handler = X11_XSetErrorHandler(X11_CatchAnyError);
timeout = SDL_GetTicks64() + 1000;
timeout = SDL_GetTicks64() + 100;
while (SDL_TRUE) {
caught_x11_error = SDL_FALSE;
X11_XSync(display, False);