mirror of https://github.com/encounter/SDL.git
WinRT: workaround a possible Windows bug, whereby hiding cursors, disables mouse-moved events
This workaround, unfortunately, requires that apps directly link to a set of Win32-style cursor resource files (that contain a transparent cursor image). Copies of suitable resource files are in src/core/winrt/, and should be included directly in an app's MSVC project. A rough explanation of this workaround/hack, and why it's needed (and seemingly can't be done through programmatic means), is in this change's code.
This commit is contained in:
parent
e964d00f64
commit
441359bd5a
|
@ -159,7 +159,9 @@ following, at a high-level:
|
||||||
the linker, and will copy SDL's .dll files to your app's final output.
|
the linker, and will copy SDL's .dll files to your app's final output.
|
||||||
4. adjust your app's build settings, at minimum, telling it where to find SDL's
|
4. adjust your app's build settings, at minimum, telling it where to find SDL's
|
||||||
header files.
|
header files.
|
||||||
5. add a file that contains a WinRT-appropriate main function.
|
5. add files that contains a WinRT-appropriate main function, along with some
|
||||||
|
data to make sure mouse-cursor-hiding (via SDL_ShowCursor(SDL_DISABLE) calls)
|
||||||
|
work properly.
|
||||||
6. add SDL-specific app code.
|
6. add SDL-specific app code.
|
||||||
7. build and run your app.
|
7. build and run your app.
|
||||||
|
|
||||||
|
@ -267,33 +269,27 @@ To change these settings:
|
||||||
10. close the dialog, saving settings, by clicking the "OK" button
|
10. close the dialog, saving settings, by clicking the "OK" button
|
||||||
|
|
||||||
|
|
||||||
### 5. Add a WinRT-appropriate main function to the app. ###
|
### 5. Add a WinRT-appropriate main function, and a blank-cursor image, to the app. ###
|
||||||
|
|
||||||
C/C++-based WinRT apps do contain a `main` function that the OS will invoke when
|
A few files should be included directly in your app's MSVC project, specifically:
|
||||||
the app starts launching. The parameters of WinRT main functions are different
|
1. a WinRT-appropriate main function (which is different than main() functions on
|
||||||
than those found on other platforms, Win32 included. SDL/WinRT provides a
|
other platforms)
|
||||||
platform-appropriate main function that will perform these actions, setup key
|
2. a Win32-style cursor resource, used by SDL_ShowCursor() to hide the mouse cursor
|
||||||
portions of the app, then invoke a classic, C/C++-style main function (that take
|
(if and when the app needs to do so). *If this cursor resource is not
|
||||||
in "argc" and "argv" parameters). The code for this file is contained inside
|
included, mouse-position reporting may fail if and when the cursor is
|
||||||
SDL's source distribution, under `src/main/winrt/SDL_winrt_main_NonXAML.cpp`.
|
hidden, due to possible bugs/design-oddities in Windows itself.*
|
||||||
You'll need to add this file, or a copy of it, to your app's project, and make
|
|
||||||
sure it gets compiled using a Microsoft-specific set of C++ extensions called
|
|
||||||
C++/CX.
|
|
||||||
|
|
||||||
**NOTE: C++/CX compilation is currently required in at least one file of your
|
To include these files:
|
||||||
app's project. This is to make sure that Visual C++'s linker builds a 'Windows
|
|
||||||
Metadata' file (.winmd) for your app. Not doing so can lead to build errors.**
|
|
||||||
|
|
||||||
To include `SDL_winrt_main_NonXAML.cpp`:
|
|
||||||
|
|
||||||
1. right-click on your project (again, in Visual C++'s Solution Explorer),
|
1. right-click on your project (again, in Visual C++'s Solution Explorer),
|
||||||
navigate to "Add", then choose "Existing Item...".
|
navigate to "Add", then choose "Existing Item...".
|
||||||
2. open `SDL_winrt_main_NonXAML.cpp`, which is found inside SDL's source
|
2. navigate to the directory containing SDL's source code, then into its
|
||||||
distribution, under `src/main/winrt/`. Make sure that the open-file dialog
|
subdirectory, 'src/main/winrt/'. Select, then add, the following files:
|
||||||
closes, either by double-clicking on the file, or single-clicking on it and
|
- `SDL_winrt_main_NonXAML.cpp`
|
||||||
then clicking Add.
|
- `SDL2-WinRTResources.rc`
|
||||||
3. right-click on the file (as listed in your project), then click on
|
- `SDL2-WinRTResource_BlankCursor.cur`
|
||||||
"Properties...".
|
3. right-click on the file `SDL_winrt_main_NonXAML.cpp` (as listed in your
|
||||||
|
project), then click on "Properties...".
|
||||||
4. in the drop-down box next to "Configuration", choose, "All Configurations"
|
4. in the drop-down box next to "Configuration", choose, "All Configurations"
|
||||||
5. in the drop-down box next to "Platform", choose, "All Platforms"
|
5. in the drop-down box next to "Platform", choose, "All Platforms"
|
||||||
6. in the left-hand list, click on "C/C++"
|
6. in the left-hand list, click on "C/C++"
|
||||||
|
@ -301,6 +297,11 @@ To include `SDL_winrt_main_NonXAML.cpp`:
|
||||||
8. click the OK button. This will close the dialog.
|
8. click the OK button. This will close the dialog.
|
||||||
|
|
||||||
|
|
||||||
|
**NOTE: C++/CX compilation is currently required in at least one file of your
|
||||||
|
app's project. This is to make sure that Visual C++'s linker builds a 'Windows
|
||||||
|
Metadata' file (.winmd) for your app. Not doing so can lead to build errors.**
|
||||||
|
|
||||||
|
|
||||||
### 6. Add app code and assets ###
|
### 6. Add app code and assets ###
|
||||||
|
|
||||||
At this point, you can add in SDL-specific source code. Be sure to include a
|
At this point, you can add in SDL-specific source code. Be sure to include a
|
||||||
|
@ -465,3 +466,13 @@ section.
|
||||||
|
|
||||||
/nodefaultlib:vccorlibd /nodefaultlib:msvcrtd vccorlibd.lib msvcrtd.lib
|
/nodefaultlib:vccorlibd /nodefaultlib:msvcrtd vccorlibd.lib msvcrtd.lib
|
||||||
|
|
||||||
|
|
||||||
|
#### Mouse-motion events fail to get sent, or SDL_GetMouseState() fails to return updated values
|
||||||
|
|
||||||
|
This may be caused by a bug in Windows itself, whereby hiding the mouse
|
||||||
|
cursor can cause mouse-position reporting to fail.
|
||||||
|
|
||||||
|
SDL provides a workaround for this, but it requires that an app links to a
|
||||||
|
set of Win32-style cursor image-resource files. A copy of suitable resource
|
||||||
|
files can be found in `src/main/winrt/`. Adding them to an app's Visual C++
|
||||||
|
project file should be sufficient to get the app to use them.
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 326 B |
|
@ -0,0 +1,3 @@
|
||||||
|
#include "winres.h"
|
||||||
|
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||||
|
5000 CURSOR "SDL2-WinRTResource_BlankCursor.cur"
|
|
@ -26,6 +26,7 @@
|
||||||
* Windows includes:
|
* Windows includes:
|
||||||
*/
|
*/
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
|
#include <windows.ui.core.h>
|
||||||
using namespace Windows::UI::Core;
|
using namespace Windows::UI::Core;
|
||||||
using Windows::UI::Core::CoreCursor;
|
using Windows::UI::Core::CoreCursor;
|
||||||
|
|
||||||
|
@ -116,11 +117,69 @@ WINRT_ShowCursor(SDL_Cursor * cursor)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CoreWindow ^ coreWindow = CoreWindow::GetForCurrentThread();
|
||||||
if (cursor) {
|
if (cursor) {
|
||||||
CoreCursor ^* theCursor = (CoreCursor ^*) cursor->driverdata;
|
CoreCursor ^* theCursor = (CoreCursor ^*) cursor->driverdata;
|
||||||
CoreWindow::GetForCurrentThread()->PointerCursor = *theCursor;
|
coreWindow->PointerCursor = *theCursor;
|
||||||
} else {
|
} else {
|
||||||
CoreWindow::GetForCurrentThread()->PointerCursor = nullptr;
|
// HACK ALERT: TL;DR - Hiding the cursor in WinRT/UWP apps is weird, and
|
||||||
|
// a Win32-style cursor resource file must be directly included in apps,
|
||||||
|
// otherwise hiding the cursor will cause mouse-motion data to never be
|
||||||
|
// received.
|
||||||
|
//
|
||||||
|
// Here's the lengthy explanation:
|
||||||
|
//
|
||||||
|
// There are two ways to hide a cursor in WinRT/UWP apps.
|
||||||
|
// Both involve setting the WinRT CoreWindow's (which is somewhat analogous
|
||||||
|
// to a Win32 HWND) 'PointerCursor' property.
|
||||||
|
//
|
||||||
|
// The first way to hide a cursor sets PointerCursor to nullptr. This
|
||||||
|
// is, arguably, the easiest to implement for an app. It does have an
|
||||||
|
// unfortunate side-effect: it'll prevent mouse-motion events from being
|
||||||
|
// sent to the app (via CoreWindow).
|
||||||
|
//
|
||||||
|
// The second way to hide a cursor sets PointerCursor to a transparent
|
||||||
|
// cursor. This allows mouse-motion events to be sent to the app, but is
|
||||||
|
// more difficult to set up, as:
|
||||||
|
// 1. WinRT/UWP, while providing a few stock cursors, does not provide
|
||||||
|
// a completely transparent cursor.
|
||||||
|
// 2. WinRT/UWP allows apps to provide custom-built cursors, but *ONLY*
|
||||||
|
// if they are linked directly inside the app, via Win32-style
|
||||||
|
// cursor resource files. APIs to create cursors at runtime are
|
||||||
|
// not provided to apps, and attempting to link-to or use Win32
|
||||||
|
// cursor-creation APIs could cause an app to fail Windows Store
|
||||||
|
// certification.
|
||||||
|
//
|
||||||
|
// SDL can use either means of hiding the cursor. It provides a Win32-style
|
||||||
|
// set of cursor resource files in its source distribution, inside
|
||||||
|
// src/main/winrt/. If those files are linked to an SDL-for-WinRT/UWP app
|
||||||
|
// (by including them in a MSVC project, for example), SDL will attempt to
|
||||||
|
// use those, if and when the cursor is hidden via SDL APIs. If those
|
||||||
|
// files are not linked in, SDL will attempt to hide the cursor via the
|
||||||
|
// 'set PointerCursor to nullptr' means (which, if you recall, causes
|
||||||
|
// mouse-motion data to NOT be sent to the app!).
|
||||||
|
//
|
||||||
|
// Tech notes:
|
||||||
|
// - SDL's blank cursor resource uses a resource ID of 5000.
|
||||||
|
// - SDL's cursor resources consist of the following two files:
|
||||||
|
// - src/main/winrt/SDL2-WinRTResource_BlankCursor.cur -- cursor pixel data
|
||||||
|
// - src/main/winrt/SDL2-WinRTResources.rc -- declares the cursor resource, and its ID (of 5000)
|
||||||
|
//
|
||||||
|
|
||||||
|
const unsigned int win32CursorResourceID = 5000;
|
||||||
|
CoreCursor ^ blankCursor = ref new CoreCursor(CoreCursorType::Custom, win32CursorResourceID);
|
||||||
|
|
||||||
|
// Set 'PointerCursor' to 'blankCursor' in a way that shouldn't throw
|
||||||
|
// an exception if the app hasn't loaded that resource.
|
||||||
|
ABI::Windows::UI::Core::ICoreCursor * iblankCursor = reinterpret_cast<ABI::Windows::UI::Core::ICoreCursor *>(blankCursor);
|
||||||
|
ABI::Windows::UI::Core::ICoreWindow * icoreWindow = reinterpret_cast<ABI::Windows::UI::Core::ICoreWindow *>(coreWindow);
|
||||||
|
HRESULT hr = icoreWindow->put_PointerCursor(iblankCursor);
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
// The app doesn't contain the cursor resource, or some other error
|
||||||
|
// occurred. Just use the other, but mouse-motion-preventing, means of
|
||||||
|
// hiding the cursor.
|
||||||
|
coreWindow->PointerCursor = nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue