mirror of
https://github.com/SFML/SFML.git
synced 2024-11-25 04:41:05 +08:00
Simplified the Windows touch implementation
This commit is contained in:
parent
3e1031e3d4
commit
d8dd4b9bf9
@ -226,7 +226,7 @@ void InputImpl::setMousePosition(const Vector2i& position)
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
void InputImpl::setMousePosition(const Vector2i& position, const WindowBase& relativeTo)
|
void InputImpl::setMousePosition(const Vector2i& position, const WindowBase& relativeTo)
|
||||||
{
|
{
|
||||||
WindowHandle handle = relativeTo.getSystemHandle();
|
const WindowHandle handle = relativeTo.getSystemHandle();
|
||||||
if (handle)
|
if (handle)
|
||||||
{
|
{
|
||||||
POINT point = {position.x, position.y};
|
POINT point = {position.x, position.y};
|
||||||
@ -253,7 +253,7 @@ Vector2i InputImpl::getTouchPosition(unsigned int finger)
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
Vector2i InputImpl::getTouchPosition(unsigned int finger, const WindowBase& relativeTo)
|
Vector2i InputImpl::getTouchPosition(unsigned int finger, const WindowBase& relativeTo)
|
||||||
{
|
{
|
||||||
WindowHandle handle = relativeTo.getSystemHandle();
|
const WindowHandle handle = relativeTo.getSystemHandle();
|
||||||
Vector2i pos;
|
Vector2i pos;
|
||||||
|
|
||||||
if (handle && WindowImplWin32::isTouchDown(finger))
|
if (handle && WindowImplWin32::isTouchDown(finger))
|
||||||
|
@ -56,68 +56,28 @@
|
|||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
constexpr int maxTouchPoints = 10; // Current Windows API limitation
|
||||||
|
|
||||||
|
// Define constants for tablet API to avoid pulling in an extra Tablet PC header
|
||||||
|
const char* tabletServiceProperty = "MicrosoftTabletPenServiceProperty";
|
||||||
|
const unsigned long long tabletDisablePressAndHold = 0x00000001ULL;
|
||||||
|
|
||||||
unsigned int windowCount = 0; // Windows owned by SFML
|
unsigned int windowCount = 0; // Windows owned by SFML
|
||||||
unsigned int handleCount = 0; // All window handles
|
unsigned int handleCount = 0; // All window handles
|
||||||
const wchar_t* className = L"SFML_Window";
|
const wchar_t* className = L"SFML_Window";
|
||||||
sf::priv::WindowImplWin32* fullscreenWindow = nullptr;
|
sf::priv::WindowImplWin32* fullscreenWindow = nullptr;
|
||||||
HINSTANCE user32Dll = nullptr;
|
DWORD touchIDs[maxTouchPoints];
|
||||||
DWORD touchIDs[10];
|
POINT touches[maxTouchPoints];
|
||||||
POINT touches[10];
|
|
||||||
|
|
||||||
#if WINVER < 0x0601
|
|
||||||
// Define touch API that's available for more recent versions of Windows
|
|
||||||
#define WM_TOUCH 0x0240
|
|
||||||
|
|
||||||
DECLARE_HANDLE(HTOUCHINPUT);
|
|
||||||
|
|
||||||
typedef struct tagTOUCHINPUT
|
|
||||||
{
|
|
||||||
LONG x;
|
|
||||||
LONG y;
|
|
||||||
HANDLE hSource;
|
|
||||||
DWORD dwID;
|
|
||||||
DWORD dwFlags;
|
|
||||||
DWORD dwMask;
|
|
||||||
DWORD dwTime;
|
|
||||||
ULONG_PTR dwExtraInfo;
|
|
||||||
DWORD cxContact;
|
|
||||||
DWORD cyContact;
|
|
||||||
} TOUCHINPUT, *PTOUCHINPUT;
|
|
||||||
|
|
||||||
typedef TOUCHINPUT const * PCTOUCHINPUT;
|
|
||||||
|
|
||||||
#define TOUCH_COORD_TO_PIXEL(l) ((l) / 100)
|
|
||||||
|
|
||||||
#define TOUCHEVENTF_MOVE 0x0001
|
|
||||||
#define TOUCHEVENTF_DOWN 0x0002
|
|
||||||
#define TOUCHEVENTF_UP 0x0004
|
|
||||||
#define TOUCHEVENTF_INRANGE 0x0008
|
|
||||||
#define TOUCHEVENTF_PRIMARY 0x0010
|
|
||||||
#define TOUCHEVENTF_NOCOALESCE 0x0020
|
|
||||||
#define TOUCHEVENTF_PEN 0x0040
|
|
||||||
#define TOUCHEVENTF_PALM 0x0080
|
|
||||||
|
|
||||||
typedef BOOL(WINAPI* RegisterTouchWindowFuncType)(HWND, ULONG);
|
|
||||||
typedef BOOL(WINAPI* CloseTouchInputHandleFuncType)(HTOUCHINPUT);
|
|
||||||
typedef BOOL(WINAPI* GetTouchInputInfoFuncType)(HTOUCHINPUT, UINT, PTOUCHINPUT, int);
|
|
||||||
|
|
||||||
RegisterTouchWindowFuncType RegisterTouchWindow = nullptr;
|
|
||||||
CloseTouchInputHandleFuncType CloseTouchInputHandle = nullptr;
|
|
||||||
GetTouchInputInfoFuncType GetTouchInputInfo = nullptr;
|
|
||||||
bool touchEnabled = false;
|
|
||||||
#else
|
|
||||||
static const bool touchEnabled = true;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Convert a hardware dependent ID to a 0 based index we can use
|
// Convert a hardware dependent ID to a 0 based index we can use
|
||||||
int getTouchID(DWORD id)
|
int getTouchID(DWORD id)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < 10; ++i)
|
for (int i = 0; i < maxTouchPoints; ++i)
|
||||||
{
|
{
|
||||||
if (touchIDs[i] == id)
|
if (touchIDs[i] == id)
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
for (int i = 0; i < 10; ++i)
|
for (int i = 0; i < maxTouchPoints; ++i)
|
||||||
{
|
{
|
||||||
if (touchIDs[i] == -1)
|
if (touchIDs[i] == -1)
|
||||||
{
|
{
|
||||||
@ -142,7 +102,7 @@ std::string getErrorString(DWORD error)
|
|||||||
nullptr) == 0)
|
nullptr) == 0)
|
||||||
return "Unknown error.";
|
return "Unknown error.";
|
||||||
|
|
||||||
sf::String message = buffer;
|
const sf::String message = buffer;
|
||||||
LocalFree(buffer);
|
LocalFree(buffer);
|
||||||
return message.toAnsiString();
|
return message.toAnsiString();
|
||||||
}
|
}
|
||||||
@ -151,54 +111,19 @@ const GUID GUID_DEVINTERFACE_HID = {0x4d1e55b2, 0xf16f, 0x11cf, {0x88, 0xcb, 0x0
|
|||||||
|
|
||||||
void setProcessDpiAware()
|
void setProcessDpiAware()
|
||||||
{
|
{
|
||||||
// Try SetProcessDpiAwareness first
|
#if 0
|
||||||
HINSTANCE shCoreDll = LoadLibrary(L"Shcore.dll");
|
// Windows 8.1+
|
||||||
|
if (SetProcessDpiAwareness(PROCESS_SYSTEM_DPI_AWARE) == E_INVALIDARG)
|
||||||
if (shCoreDll)
|
|
||||||
{
|
|
||||||
enum ProcessDpiAwareness
|
|
||||||
{
|
|
||||||
ProcessDpiUnaware = 0,
|
|
||||||
ProcessSystemDpiAware = 1,
|
|
||||||
ProcessPerMonitorDpiAware = 2
|
|
||||||
};
|
|
||||||
|
|
||||||
using SetProcessDpiAwarenessFuncType = HRESULT(WINAPI*)(ProcessDpiAwareness);
|
|
||||||
auto SetProcessDpiAwarenessFunc = reinterpret_cast<SetProcessDpiAwarenessFuncType>(
|
|
||||||
reinterpret_cast<void*>(GetProcAddress(shCoreDll, "SetProcessDpiAwareness")));
|
|
||||||
|
|
||||||
if (SetProcessDpiAwarenessFunc)
|
|
||||||
{
|
|
||||||
// We only check for E_INVALIDARG because we would get
|
|
||||||
// E_ACCESSDENIED if the DPI was already set previously
|
|
||||||
// and S_OK means the call was successful
|
|
||||||
if (SetProcessDpiAwarenessFunc(ProcessSystemDpiAware) == E_INVALIDARG)
|
|
||||||
{
|
{
|
||||||
sf::err() << "Failed to set process DPI awareness" << std::endl;
|
sf::err() << "Failed to set process DPI awareness" << std::endl;
|
||||||
}
|
}
|
||||||
else
|
#endif
|
||||||
{
|
|
||||||
FreeLibrary(shCoreDll);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FreeLibrary(shCoreDll);
|
if (!SetProcessDPIAware())
|
||||||
}
|
|
||||||
|
|
||||||
if (user32Dll)
|
|
||||||
{
|
{
|
||||||
using SetProcessDPIAwareFuncType = BOOL(WINAPI*)();
|
|
||||||
auto SetProcessDPIAwareFunc = reinterpret_cast<SetProcessDPIAwareFuncType>(
|
|
||||||
reinterpret_cast<void*>(GetProcAddress(user32Dll, "SetProcessDPIAware")));
|
|
||||||
|
|
||||||
if (SetProcessDPIAwareFunc)
|
|
||||||
{
|
|
||||||
if (!SetProcessDPIAwareFunc())
|
|
||||||
sf::err() << "Failed to set process DPI awareness" << std::endl;
|
sf::err() << "Failed to set process DPI awareness" << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace sf
|
namespace sf
|
||||||
@ -221,21 +146,16 @@ m_fullscreen(false),
|
|||||||
m_cursorGrabbed(false)
|
m_cursorGrabbed(false)
|
||||||
{
|
{
|
||||||
// If we're the first window handle
|
// If we're the first window handle
|
||||||
if (handleCount == 0)
|
|
||||||
{
|
|
||||||
// Ensure User32.dll is loaded
|
|
||||||
if (!user32Dll)
|
|
||||||
user32Dll = LoadLibraryA("User32.dll");
|
|
||||||
|
|
||||||
// Set that this process is DPI aware and can handle DPI scaling
|
|
||||||
setProcessDpiAware();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_handle)
|
if (m_handle)
|
||||||
{
|
{
|
||||||
// If we're the first window handle, we only need to poll for joysticks when WM_DEVICECHANGE message is received
|
// If we're the first window handle, set DPI Awareness
|
||||||
|
// plus we only need to poll for joysticks when WM_DEVICECHANGE message is received
|
||||||
if (handleCount == 0)
|
if (handleCount == 0)
|
||||||
|
{
|
||||||
|
setProcessDpiAware();
|
||||||
JoystickImpl::setLazyUpdates(true);
|
JoystickImpl::setLazyUpdates(true);
|
||||||
|
}
|
||||||
|
|
||||||
++handleCount;
|
++handleCount;
|
||||||
|
|
||||||
@ -265,24 +185,18 @@ m_fullscreen((style & Style::Fullscreen) != 0),
|
|||||||
m_cursorGrabbed(m_fullscreen)
|
m_cursorGrabbed(m_fullscreen)
|
||||||
{
|
{
|
||||||
// If we're the first window handle
|
// If we're the first window handle
|
||||||
if (handleCount == 0)
|
|
||||||
{
|
|
||||||
// Ensure User32.dll is loaded
|
|
||||||
if (!user32Dll)
|
|
||||||
user32Dll = LoadLibraryA("User32.dll");
|
|
||||||
|
|
||||||
// Set that this process is DPI aware and can handle DPI scaling
|
// Set that this process is DPI aware and can handle DPI scaling
|
||||||
|
if (handleCount == 0)
|
||||||
setProcessDpiAware();
|
setProcessDpiAware();
|
||||||
}
|
|
||||||
|
|
||||||
// Register the window class at first call
|
// Register the window class at first call
|
||||||
if (windowCount == 0)
|
if (windowCount == 0)
|
||||||
registerWindowClass();
|
registerWindowClass();
|
||||||
|
|
||||||
// Compute position and size
|
// Compute position and size
|
||||||
HDC screenDC = GetDC(nullptr);
|
const HDC screenDC = GetDC(nullptr);
|
||||||
int left = (GetDeviceCaps(screenDC, HORZRES) - static_cast<int>(mode.size.x)) / 2;
|
const int left = (GetDeviceCaps(screenDC, HORZRES) - static_cast<int>(mode.size.x)) / 2;
|
||||||
int top = (GetDeviceCaps(screenDC, VERTRES) - static_cast<int>(mode.size.y)) / 2;
|
const int top = (GetDeviceCaps(screenDC, VERTRES) - static_cast<int>(mode.size.y)) / 2;
|
||||||
int width = static_cast<int>(mode.size.x);
|
int width = static_cast<int>(mode.size.x);
|
||||||
int height = static_cast<int>(mode.size.y);
|
int height = static_cast<int>(mode.size.y);
|
||||||
ReleaseDC(nullptr, screenDC);
|
ReleaseDC(nullptr, screenDC);
|
||||||
@ -337,7 +251,6 @@ m_cursorGrabbed(m_fullscreen)
|
|||||||
JoystickImpl::setLazyUpdates(true);
|
JoystickImpl::setLazyUpdates(true);
|
||||||
|
|
||||||
++handleCount;
|
++handleCount;
|
||||||
}
|
|
||||||
|
|
||||||
// By default, the OS limits the size of the window the the desktop size,
|
// By default, the OS limits the size of the window the the desktop size,
|
||||||
// we have to resize it after creation to apply the real size
|
// we have to resize it after creation to apply the real size
|
||||||
@ -353,6 +266,7 @@ m_cursorGrabbed(m_fullscreen)
|
|||||||
// Increment window count
|
// Increment window count
|
||||||
++windowCount;
|
++windowCount;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
@ -370,18 +284,10 @@ WindowImplWin32::~WindowImplWin32()
|
|||||||
--handleCount;
|
--handleCount;
|
||||||
|
|
||||||
// This was the last handle
|
// This was the last handle
|
||||||
if (handleCount == 0)
|
|
||||||
{
|
|
||||||
// Free User32.dll
|
|
||||||
if (user32Dll)
|
|
||||||
{
|
|
||||||
FreeLibrary(user32Dll);
|
|
||||||
user32Dll = nullptr;
|
|
||||||
}
|
|
||||||
// Reenable automatic joystick polling
|
// Reenable automatic joystick polling
|
||||||
|
if (handleCount == 0)
|
||||||
JoystickImpl::setLazyUpdates(false);
|
JoystickImpl::setLazyUpdates(false);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (!m_callback)
|
if (!m_callback)
|
||||||
{
|
{
|
||||||
@ -895,7 +801,7 @@ void WindowImplWin32::processEvent(UINT message, WPARAM wParam, LPARAM lParam)
|
|||||||
position.y = static_cast<std::int16_t>(HIWORD(lParam));
|
position.y = static_cast<std::int16_t>(HIWORD(lParam));
|
||||||
ScreenToClient(m_handle, &position);
|
ScreenToClient(m_handle, &position);
|
||||||
|
|
||||||
auto delta = static_cast<std::int16_t>(HIWORD(wParam));
|
const auto delta = static_cast<std::int16_t>(HIWORD(wParam));
|
||||||
|
|
||||||
Event event;
|
Event event;
|
||||||
|
|
||||||
@ -1045,8 +951,8 @@ void WindowImplWin32::processEvent(UINT message, WPARAM wParam, LPARAM lParam)
|
|||||||
case WM_MOUSEMOVE:
|
case WM_MOUSEMOVE:
|
||||||
{
|
{
|
||||||
// Extract the mouse local coordinates
|
// Extract the mouse local coordinates
|
||||||
int x = static_cast<std::int16_t>(LOWORD(lParam));
|
const int x = static_cast<std::int16_t>(LOWORD(lParam));
|
||||||
int y = static_cast<std::int16_t>(HIWORD(lParam));
|
const int y = static_cast<std::int16_t>(HIWORD(lParam));
|
||||||
|
|
||||||
// Get the client area of the window
|
// Get the client area of the window
|
||||||
RECT area;
|
RECT area;
|
||||||
@ -1115,7 +1021,7 @@ void WindowImplWin32::processEvent(UINT message, WPARAM wParam, LPARAM lParam)
|
|||||||
if ((wParam == DBT_DEVICEARRIVAL) || (wParam == DBT_DEVICEREMOVECOMPLETE))
|
if ((wParam == DBT_DEVICEARRIVAL) || (wParam == DBT_DEVICEREMOVECOMPLETE))
|
||||||
{
|
{
|
||||||
// Some sort of device change has happened, update joystick connections if it is a device interface
|
// Some sort of device change has happened, update joystick connections if it is a device interface
|
||||||
auto* deviceBroadcastHeader = reinterpret_cast<DEV_BROADCAST_HDR*>(lParam);
|
const auto* deviceBroadcastHeader = reinterpret_cast<DEV_BROADCAST_HDR*>(lParam);
|
||||||
|
|
||||||
if (deviceBroadcastHeader && (deviceBroadcastHeader->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE))
|
if (deviceBroadcastHeader && (deviceBroadcastHeader->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE))
|
||||||
JoystickImpl::updateConnections();
|
JoystickImpl::updateConnections();
|
||||||
@ -1126,22 +1032,20 @@ void WindowImplWin32::processEvent(UINT message, WPARAM wParam, LPARAM lParam)
|
|||||||
case WM_TOUCH:
|
case WM_TOUCH:
|
||||||
{
|
{
|
||||||
// Get the number of events
|
// Get the number of events
|
||||||
std::int16_t num = LOWORD(wParam);
|
const unsigned int count = LOWORD(wParam);
|
||||||
|
|
||||||
// Reserve memory
|
// Reserve memory
|
||||||
PTOUCHINPUT events = new TOUCHINPUT[num];
|
std::vector<TOUCHINPUT> events(count);
|
||||||
|
|
||||||
if (events)
|
if (GetTouchInputInfo(reinterpret_cast<HTOUCHINPUT>(lParam), count, events.data(), sizeof(TOUCHINPUT)))
|
||||||
{
|
|
||||||
if (GetTouchInputInfo(reinterpret_cast<HTOUCHINPUT>(lParam), num, events, sizeof(TOUCHINPUT)))
|
|
||||||
{
|
{
|
||||||
POINT point;
|
POINT point;
|
||||||
for (int i = 0; i < num; ++i)
|
for (unsigned int i = 0; i < count; ++i)
|
||||||
{
|
{
|
||||||
Event event;
|
Event event;
|
||||||
int index = getTouchID(events[i].dwID);
|
int index = getTouchID(events[i].dwID);
|
||||||
|
|
||||||
// Out of Ids? Should never happen
|
// Out of IDs? Should never happen
|
||||||
if (index == -1)
|
if (index == -1)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -1170,7 +1074,8 @@ void WindowImplWin32::processEvent(UINT message, WPARAM wParam, LPARAM lParam)
|
|||||||
// Remove the stored ID
|
// Remove the stored ID
|
||||||
touchIDs[index] = static_cast<DWORD>(-1);
|
touchIDs[index] = static_cast<DWORD>(-1);
|
||||||
}
|
}
|
||||||
if (events[i].dwFlags & TOUCHEVENTF_MOVE) {
|
if (events[i].dwFlags & TOUCHEVENTF_MOVE)
|
||||||
|
{
|
||||||
// Only handle real movement
|
// Only handle real movement
|
||||||
if (touches[index].x != point.x || touches[index].y != point.y)
|
if (touches[index].x != point.x || touches[index].y != point.y)
|
||||||
{
|
{
|
||||||
@ -1186,8 +1091,6 @@ void WindowImplWin32::processEvent(UINT message, WPARAM wParam, LPARAM lParam)
|
|||||||
{
|
{
|
||||||
err() << "Failed to get touch input info: " << getErrorString(GetLastError()) << std::endl;
|
err() << "Failed to get touch input info: " << getErrorString(GetLastError()) << std::endl;
|
||||||
}
|
}
|
||||||
delete[] events;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1361,26 +1264,20 @@ void WindowImplWin32::prepareTouch()
|
|||||||
{
|
{
|
||||||
prepared = true;
|
prepared = true;
|
||||||
|
|
||||||
#if WINVER < 0x0601
|
|
||||||
RegisterTouchWindow = reinterpret_cast<RegisterTouchWindowFuncType>(GetProcAddress(user32Dll, "RegisterTouchWindow"));
|
|
||||||
|
|
||||||
touchEnabled = RegisterTouchWindow != nullptr;
|
|
||||||
|
|
||||||
// If we've got touch support, load the other procs
|
|
||||||
if (touchEnabled)
|
|
||||||
{
|
|
||||||
CloseTouchInputHandle = reinterpret_cast<CloseTouchInputHandleFuncType>(GetProcAddress(user32Dll, "CloseTouchInputHandle"));
|
|
||||||
GetTouchInputInfo = reinterpret_cast<GetTouchInputInfoFuncType>(GetProcAddress(user32Dll, "GetTouchInputInfo"));
|
|
||||||
|
|
||||||
// Reset touch IDs
|
// Reset touch IDs
|
||||||
for (int i = 0; i < 10; ++i)
|
std::fill_n(touchIDs, maxTouchPoints, static_cast<DWORD>(-1));
|
||||||
touchIDs[i] = static_cast<DWORD>(-1);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (touchEnabled && m_handle)
|
// Tell Windows this window is touch aware
|
||||||
RegisterTouchWindow(m_handle, 0);
|
RegisterTouchWindow(m_handle, 0);
|
||||||
|
|
||||||
|
// Disable right mouse button emulation by long touching
|
||||||
|
const ATOM atom = GlobalAddAtomA(tabletServiceProperty);
|
||||||
|
if (atom)
|
||||||
|
{
|
||||||
|
SetPropA(m_handle, tabletServiceProperty, reinterpret_cast<HANDLE>(tabletDisablePressAndHold));
|
||||||
|
GlobalDeleteAtom(atom);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
|
Loading…
Reference in New Issue
Block a user