Use WM_POINTER on Windows 8 platform

First version. Still touch support is not working as expected. The pen,
mouse, and trackpad are working correctly. (Even the eraser tip of the
pen is recognized.)
This commit is contained in:
David Capello 2017-11-01 22:42:30 -03:00
parent 7c4f811fc7
commit 8c9b8910c1
8 changed files with 437 additions and 47 deletions

View File

@ -405,8 +405,9 @@ if(WIN32)
kernel32 user32 gdi32 comdlg32 ole32 winmm kernel32 user32 gdi32 comdlg32 ole32 winmm
shlwapi psapi wininet comctl32 dbghelp) shlwapi psapi wininet comctl32 dbghelp)
# Windows XP is the minimum supported platform. # Windows Vista is the minimum supported platform but we're defining
add_definitions(-D_WIN32_WINNT=0x0501 -DWINVER=0x0501) # Windows 10 to get the all constant/structure definitions.
add_definitions(-D_WIN32_WINNT=0x0A00 -DWINVER=0x0A00)
# We need Unicode support # We need Unicode support
add_definitions(-DUNICODE -D_UNICODE) add_definitions(-DUNICODE -D_UNICODE)

View File

@ -122,6 +122,7 @@ if(USE_SKIA_BACKEND)
skia/skia_window_win.cpp skia/skia_window_win.cpp
win/pen.cpp win/pen.cpp
win/vk.cpp win/vk.cpp
win/winapi.cpp
win/window.cpp win/window.cpp
win/window_dde.cpp) win/window_dde.cpp)
elseif(APPLE) elseif(APPLE)

View File

@ -7,3 +7,4 @@ back-ends:
* Previous version were using Allegro 4 (it still uses Allegro 4 on Linux) * Previous version were using Allegro 4 (it still uses Allegro 4 on Linux)
* Now we use our own implementation on Windows and macOS to handle * Now we use our own implementation on Windows and macOS to handle
events, and [Skia](https://skia.org/) to render graphics. events, and [Skia](https://skia.org/) to render graphics.
* Minimum Windows platform: Windows Vista

View File

@ -1,5 +1,5 @@
// SHE library // SHE library
// Copyright (C) 2012-2016 David Capello // Copyright (C) 2012-2017 David Capello
// //
// This file is released under the terms of the MIT license. // This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information. // Read LICENSE.txt for more information.
@ -10,6 +10,7 @@
#include "she/common/system.h" #include "she/common/system.h"
#include "she/win/pen.h" #include "she/win/pen.h"
#include "she/win/winapi.h"
namespace she { namespace she {
@ -21,9 +22,8 @@ public:
WindowSystem() { } WindowSystem() { }
~WindowSystem() { } ~WindowSystem() { }
PenAPI& penApi() { WinAPI& winApi() { return m_winApi; }
return m_penApi; PenAPI& penApi() { return m_penApi; }
}
bool isKeyPressed(KeyScancode scancode) override { bool isKeyPressed(KeyScancode scancode) override {
return win_is_key_pressed(scancode); return win_is_key_pressed(scancode);
@ -34,6 +34,7 @@ public:
} }
private: private:
WinAPI m_winApi;
PenAPI m_penApi; PenAPI m_penApi;
}; };

42
src/she/win/winapi.cpp Normal file
View File

@ -0,0 +1,42 @@
// SHE library
// Copyright (C) 2017 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "she/win/winapi.h"
namespace she {
#define GET_PROC(dll, name) \
name = base::get_dll_proc<name##_Func>(dll, #name)
WinAPI::WinAPI()
: EnableMouseInPointer(nullptr)
, IsMouseInPointerEnabled(nullptr)
, GetPointerInfo(nullptr)
, GetPointerPenInfo(nullptr)
, m_user32(nullptr)
{
m_user32 = base::load_dll("user32.dll");
if (m_user32) {
GET_PROC(m_user32, EnableMouseInPointer);
GET_PROC(m_user32, IsMouseInPointerEnabled);
GET_PROC(m_user32, GetPointerInfo);
GET_PROC(m_user32, GetPointerPenInfo);
}
}
WinAPI::~WinAPI()
{
if (m_user32) {
base::unload_dll(m_user32);
m_user32 = nullptr;
}
}
} // namespace she

39
src/she/win/winapi.h Normal file
View File

@ -0,0 +1,39 @@
// SHE library
// Copyright (C) 2017 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef SHE_WIN_WINAPI_H_INCLUDED
#define SHE_WIN_WINAPI_H_INCLUDED
#pragma once
#include "base/dll.h"
#include <windows.h>
namespace she {
typedef BOOL (WINAPI* EnableMouseInPointer_Func)(BOOL fEnable);
typedef BOOL (WINAPI* IsMouseInPointerEnabled_Func)(void);
typedef BOOL (WINAPI* GetPointerInfo_Func)(UINT32 pointerId, POINTER_INFO* pointerInfo);
typedef BOOL (WINAPI* GetPointerPenInfo_Func)(UINT32 pointerId, POINTER_PEN_INFO* penInfo);
class WinAPI {
public:
WinAPI();
~WinAPI();
// These functions are availble only since Windows 8
EnableMouseInPointer_Func EnableMouseInPointer;
IsMouseInPointerEnabled_Func IsMouseInPointerEnabled;
GetPointerInfo_Func GetPointerInfo;
GetPointerPenInfo_Func GetPointerPenInfo;
private:
base::dll m_user32;
};
} // namespace she
#endif

View File

@ -25,29 +25,57 @@
#include "she/win/vk.h" #include "she/win/vk.h"
#include "she/win/window_dde.h" #include "she/win/window_dde.h"
#ifndef WM_MOUSEHWHEEL
#define WM_MOUSEHWHEEL 0x020E
#endif
#define SHE_WND_CLASS_NAME L"Aseprite.Window" #define SHE_WND_CLASS_NAME L"Aseprite.Window"
#define MOUSE_TRACE(...)
// Gets the window client are in absolute/screen coordinates
#define ABS_CLIENT_RC(rc) \
RECT rc; \
GetClientRect(m_hwnd, &rc); \
MapWindowPoints(m_hwnd, NULL, (POINT*)&rc, 2)
// Not yet ready because if we start receiving WM_POINTERDOWN messages
// instead of WM_LBUTTONDBLCLK we lost the automatic double-click
// messages.
#define USE_EnableMouseInPointer 0
namespace she { namespace she {
WinWindow::WinWindow(int width, int height, int scale) WinWindow::WinWindow(int width, int height, int scale)
: m_hwnd(nullptr) : m_hwnd(nullptr)
, m_hcursor(nullptr)
, m_clientSize(1, 1) , m_clientSize(1, 1)
, m_restoredSize(0, 0) , m_restoredSize(0, 0)
, m_scale(scale)
, m_isCreated(false) , m_isCreated(false)
, m_translateDeadKeys(false) , m_translateDeadKeys(false)
, m_hasMouse(false) , m_hasMouse(false)
, m_captureMouse(false) , m_captureMouse(false)
, m_customHcursor(false)
, m_usePointerApi(false)
, m_ignoreMouseMessages(false)
, m_lastPointerId(0)
, m_capturePointerId(0)
, m_hpenctx(nullptr) , m_hpenctx(nullptr)
, m_pointerType(PointerType::Unknown) , m_pointerType(PointerType::Unknown)
, m_pressure(0.0) , m_pressure(0.0)
{ {
m_hcursor = nullptr; auto& winApi = system()->winApi();
m_customHcursor = false; if (winApi.EnableMouseInPointer &&
m_scale = scale; winApi.IsMouseInPointerEnabled &&
winApi.GetPointerInfo &&
winApi.GetPointerPenInfo) {
#if USE_EnableMouseInPointer == 1
if (!winApi.IsMouseInPointerEnabled()) {
// Prefer pointer messages (WM_POINTER*) since Windows 8 instead
// of mouse messages (WM_MOUSE*)
winApi.EnableMouseInPointer(TRUE);
m_ignoreMouseMessages = (winApi.IsMouseInPointerEnabled() ? true: false);
}
#endif
m_usePointerApi = true;
}
registerClass(); registerClass();
@ -127,11 +155,23 @@ void WinWindow::setTitle(const std::string& title)
void WinWindow::captureMouse() void WinWindow::captureMouse()
{ {
m_captureMouse = true; m_captureMouse = true;
m_capturePointerId = m_lastPointerId;
if (GetCapture() != m_hwnd) {
MOUSE_TRACE("SetCapture\n");
SetCapture(m_hwnd);
}
} }
void WinWindow::releaseMouse() void WinWindow::releaseMouse()
{ {
m_captureMouse = false; m_captureMouse = false;
m_capturePointerId = 0;
if (GetCapture() == m_hwnd) {
MOUSE_TRACE("ReleaseCapture\n");
ReleaseCapture();
}
} }
void WinWindow::setMousePosition(const gfx::Point& position) void WinWindow::setMousePosition(const gfx::Point& position)
@ -436,22 +476,23 @@ LRESULT WinWindow::wndProc(UINT msg, WPARAM wparam, LPARAM lparam)
} }
break; break;
// Mouse and Trackpad Messages
case WM_MOUSEMOVE: { case WM_MOUSEMOVE: {
// Adjust capture // If the pointer API is enable, we use WM_POINTERUPDATE instead
if (m_captureMouse) { // of WM_MOUSEMOVE. This check is here because Windows keeps
if (GetCapture() != m_hwnd) // sending us WM_MOUSEMOVE messages even when we call
SetCapture(m_hwnd); // EnableMouseInPointer() (mainly when we use Alt+stylus we
} // receive WM_MOUSEMOVE with the position of the mouse/trackpad
else { // + WM_POINTERUPDATE with the position of the pen)
if (GetCapture() == m_hwnd) if (m_ignoreMouseMessages)
ReleaseCapture(); break;
}
Event ev; Event ev;
ev.setModifiers(get_modifiers_from_last_win32_message()); mouseEvent(lparam, ev);
ev.setPosition(gfx::Point(
GET_X_LPARAM(lparam) / m_scale, MOUSE_TRACE("MOUSEMOVE xy=%d,%d\n",
GET_Y_LPARAM(lparam) / m_scale)); ev.position().x, ev.position().y);
if (!m_hasMouse) { if (!m_hasMouse) {
m_hasMouse = true; m_hasMouse = true;
@ -459,6 +500,8 @@ LRESULT WinWindow::wndProc(UINT msg, WPARAM wparam, LPARAM lparam)
ev.setType(Event::MouseEnter); ev.setType(Event::MouseEnter);
queueEvent(ev); queueEvent(ev);
MOUSE_TRACE("-> Event::MouseEnter\n");
// Track mouse to receive WM_MOUSELEAVE message. // Track mouse to receive WM_MOUSELEAVE message.
TRACKMOUSEEVENT tme; TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(TRACKMOUSEEVENT); tme.cbSize = sizeof(TRACKMOUSEEVENT);
@ -486,6 +529,8 @@ LRESULT WinWindow::wndProc(UINT msg, WPARAM wparam, LPARAM lparam)
ev.setType(Event::MouseLeave); ev.setType(Event::MouseLeave);
ev.setModifiers(get_modifiers_from_last_win32_message()); ev.setModifiers(get_modifiers_from_last_win32_message());
queueEvent(ev); queueEvent(ev);
MOUSE_TRACE("-> Event::MouseLeave\n");
} }
break; break;
@ -494,11 +539,8 @@ LRESULT WinWindow::wndProc(UINT msg, WPARAM wparam, LPARAM lparam)
case WM_MBUTTONDOWN: case WM_MBUTTONDOWN:
case WM_XBUTTONDOWN: { case WM_XBUTTONDOWN: {
Event ev; Event ev;
mouseEvent(lparam, ev);
ev.setType(Event::MouseDown); ev.setType(Event::MouseDown);
ev.setModifiers(get_modifiers_from_last_win32_message());
ev.setPosition(gfx::Point(
GET_X_LPARAM(lparam) / m_scale,
GET_Y_LPARAM(lparam) / m_scale));
ev.setButton( ev.setButton(
msg == WM_LBUTTONDOWN ? Event::LeftButton: msg == WM_LBUTTONDOWN ? Event::LeftButton:
msg == WM_RBUTTONDOWN ? Event::RightButton: msg == WM_RBUTTONDOWN ? Event::RightButton:
@ -511,8 +553,11 @@ LRESULT WinWindow::wndProc(UINT msg, WPARAM wparam, LPARAM lparam)
ev.setPointerType(m_pointerType); ev.setPointerType(m_pointerType);
ev.setPressure(m_pressure); ev.setPressure(m_pressure);
} }
queueEvent(ev); queueEvent(ev);
MOUSE_TRACE("BUTTONDOWN xy=%d,%d button=%d\n",
ev.position().x, ev.position().y,
ev.button());
break; break;
} }
@ -521,11 +566,8 @@ LRESULT WinWindow::wndProc(UINT msg, WPARAM wparam, LPARAM lparam)
case WM_MBUTTONUP: case WM_MBUTTONUP:
case WM_XBUTTONUP: { case WM_XBUTTONUP: {
Event ev; Event ev;
mouseEvent(lparam, ev);
ev.setType(Event::MouseUp); ev.setType(Event::MouseUp);
ev.setModifiers(get_modifiers_from_last_win32_message());
ev.setPosition(gfx::Point(
GET_X_LPARAM(lparam) / m_scale,
GET_Y_LPARAM(lparam) / m_scale));
ev.setButton( ev.setButton(
msg == WM_LBUTTONUP ? Event::LeftButton: msg == WM_LBUTTONUP ? Event::LeftButton:
msg == WM_RBUTTONUP ? Event::RightButton: msg == WM_RBUTTONUP ? Event::RightButton:
@ -538,9 +580,12 @@ LRESULT WinWindow::wndProc(UINT msg, WPARAM wparam, LPARAM lparam)
ev.setPointerType(m_pointerType); ev.setPointerType(m_pointerType);
ev.setPressure(m_pressure); ev.setPressure(m_pressure);
} }
queueEvent(ev); queueEvent(ev);
MOUSE_TRACE("BUTTONUP xy=%d,%d button=%d\n",
ev.position().x, ev.position().y,
ev.button());
// Avoid popup menu for scrollbars // Avoid popup menu for scrollbars
if (msg == WM_RBUTTONUP) if (msg == WM_RBUTTONUP)
return 0; return 0;
@ -553,11 +598,8 @@ LRESULT WinWindow::wndProc(UINT msg, WPARAM wparam, LPARAM lparam)
case WM_RBUTTONDBLCLK: case WM_RBUTTONDBLCLK:
case WM_XBUTTONDBLCLK: { case WM_XBUTTONDBLCLK: {
Event ev; Event ev;
mouseEvent(lparam, ev);
ev.setType(Event::MouseDoubleClick); ev.setType(Event::MouseDoubleClick);
ev.setModifiers(get_modifiers_from_last_win32_message());
ev.setPosition(gfx::Point(
GET_X_LPARAM(lparam) / m_scale,
GET_Y_LPARAM(lparam) / m_scale));
ev.setButton( ev.setButton(
msg == WM_LBUTTONDBLCLK ? Event::LeftButton: msg == WM_LBUTTONDBLCLK ? Event::LeftButton:
msg == WM_RBUTTONDBLCLK ? Event::RightButton: msg == WM_RBUTTONDBLCLK ? Event::RightButton:
@ -570,8 +612,11 @@ LRESULT WinWindow::wndProc(UINT msg, WPARAM wparam, LPARAM lparam)
ev.setPointerType(m_pointerType); ev.setPointerType(m_pointerType);
ev.setPressure(m_pressure); ev.setPressure(m_pressure);
} }
queueEvent(ev); queueEvent(ev);
MOUSE_TRACE("BUTTONDBLCLK xy=%d,%d button=%d\n",
ev.position().x, ev.position().y,
ev.button());
break; break;
} }
@ -599,8 +644,11 @@ LRESULT WinWindow::wndProc(UINT msg, WPARAM wparam, LPARAM lparam)
(msg == WM_MOUSEHWHEEL ? z: 0), (msg == WM_MOUSEHWHEEL ? z: 0),
(msg == WM_MOUSEWHEEL ? -z: 0)); (msg == WM_MOUSEWHEEL ? -z: 0));
ev.setWheelDelta(delta); ev.setWheelDelta(delta);
queueEvent(ev); queueEvent(ev);
MOUSE_TRACE("MOUSEWHEEL xy=%d,%d delta=%d,%d\n",
ev.position().x, ev.position().y,
ev.wheelDelta().x, ev.wheelDelta().y);
break; break;
} }
@ -646,11 +694,208 @@ LRESULT WinWindow::wndProc(UINT msg, WPARAM wparam, LPARAM lparam)
ev.setWheelDelta(delta); ev.setWheelDelta(delta);
SetScrollPos(m_hwnd, bar, 50, FALSE); SetScrollPos(m_hwnd, bar, 50, FALSE);
queueEvent(ev); queueEvent(ev);
MOUSE_TRACE("HVSCROLL xy=%d,%d delta=%d,%d\n",
ev.position().x, ev.position().y,
ev.wheelDelta().x, ev.wheelDelta().y);
break; break;
} }
// Pointer API (since Windows 8.0)
case WM_POINTERCAPTURECHANGED: {
MOUSE_TRACE("POINTERCAPTURECHANGED\n");
m_capturePointerId = 0;
break;
}
case WM_POINTERENTER: {
POINTER_INFO pi;
Event ev;
if (!pointerEvent(wparam, lparam, ev, pi))
break;
// Ignore this message because we have captured other pointerId.
if (m_capturePointerId &&
m_capturePointerId != pi.pointerId) {
return 0;
}
MOUSE_TRACE("POINTERENTER id=%d xy=%d,%d\n",
pi.pointerId, ev.position().x, ev.position().y);
#if USE_EnableMouseInPointer == 0
// This is necessary to avoid receiving random WM_MOUSEMOVE from
// the mouse position when we use Alt+pen tip.
// TODO Remove this line when we enable EnableMouseInPointer(TRUE);
m_ignoreMouseMessages = true;
#endif
if (!m_hasMouse) {
m_hasMouse = true;
ev.setType(Event::MouseEnter);
queueEvent(ev);
MOUSE_TRACE("-> Event::MouseEnter\n");
}
return 0;
}
case WM_POINTERLEAVE: {
UINT32 pointerId = GET_POINTERID_WPARAM(wparam);
// Ignore this message because we have captured other pointerId.
if (m_capturePointerId &&
m_capturePointerId != pointerId) {
return 0;
}
MOUSE_TRACE("POINTERLEAVE id=%d\n", pointerId);
#if USE_EnableMouseInPointer == 0
m_ignoreMouseMessages = false;
#endif
if (m_hasMouse) {
m_hasMouse = false;
Event ev;
ev.setType(Event::MouseLeave);
ev.setModifiers(get_modifiers_from_last_win32_message());
queueEvent(ev);
MOUSE_TRACE("-> Event::MouseLeave\n");
return 0;
}
break;
}
case WM_POINTERDOWN: {
POINTER_INFO pi;
Event ev;
if (!pointerEvent(wparam, lparam, ev, pi))
break;
// Ignore this message because we have captured other pointerId.
if (m_capturePointerId &&
m_capturePointerId != pi.pointerId) {
return 0;
}
ev.setType(Event::MouseDown);
ev.setButton(
pi.ButtonChangeType == POINTER_CHANGE_FIRSTBUTTON_DOWN ? Event::LeftButton:
pi.ButtonChangeType == POINTER_CHANGE_SECONDBUTTON_DOWN ? Event::RightButton:
pi.ButtonChangeType == POINTER_CHANGE_THIRDBUTTON_DOWN ? Event::MiddleButton:
pi.ButtonChangeType == POINTER_CHANGE_FOURTHBUTTON_DOWN ? Event::X1Button:
pi.ButtonChangeType == POINTER_CHANGE_FIFTHBUTTON_DOWN ? Event::X2Button:
Event::NoneButton);
queueEvent(ev);
MOUSE_TRACE("POINTERDOWN id=%d xy=%d,%d button=%d\n",
pi.pointerId, ev.position().x, ev.position().y,
ev.button());
return 0;
}
case WM_POINTERUP: {
POINTER_INFO pi;
Event ev;
if (!pointerEvent(wparam, lparam, ev, pi))
break;
// Ignore this message because we have captured other pointerId.
if (m_capturePointerId &&
m_capturePointerId != pi.pointerId) {
return 0;
}
ev.setType(Event::MouseUp);
ev.setButton(
pi.ButtonChangeType == POINTER_CHANGE_FIRSTBUTTON_UP ? Event::LeftButton:
pi.ButtonChangeType == POINTER_CHANGE_SECONDBUTTON_UP ? Event::RightButton:
pi.ButtonChangeType == POINTER_CHANGE_THIRDBUTTON_UP ? Event::MiddleButton:
pi.ButtonChangeType == POINTER_CHANGE_FOURTHBUTTON_UP ? Event::X1Button:
pi.ButtonChangeType == POINTER_CHANGE_FIFTHBUTTON_UP ? Event::X2Button:
Event::NoneButton);
queueEvent(ev);
MOUSE_TRACE("POINTERUP id=%d xy=%d,%d button=%d\n",
pi.pointerId, ev.position().x, ev.position().y,
ev.button());
return 0;
}
case WM_POINTERUPDATE: {
POINTER_INFO pi;
Event ev;
if (!pointerEvent(wparam, lparam, ev, pi))
break;
// Ignore this message because we have captured other pointerId.
if (m_capturePointerId &&
m_capturePointerId != pi.pointerId) {
return 0;
}
if (!m_hasMouse) {
m_hasMouse = true;
ev.setType(Event::MouseEnter);
queueEvent(ev);
MOUSE_TRACE("-> Event::MouseEnter\n");
}
ev.setType(Event::MouseMove);
queueEvent(ev);
MOUSE_TRACE("POINTERUPDATE id=%d xy=%d,%d\n",
pi.pointerId, ev.position().x, ev.position().y);
return 0;
}
case WM_POINTERWHEEL:
case WM_POINTERHWHEEL: {
POINTER_INFO pi;
Event ev;
if (!pointerEvent(wparam, lparam, ev, pi))
break;
// Ignore this message because we have captured other pointerId.
if (m_capturePointerId &&
m_capturePointerId != pi.pointerId) {
return 0;
}
ev.setType(Event::MouseWheel);
int z = GET_WHEEL_DELTA_WPARAM(wparam);
if (ABS(z) >= WHEEL_DELTA)
z /= WHEEL_DELTA;
else {
// TODO use floating point numbers or something similar
// (so we could use: z /= double(WHEEL_DELTA))
z = SGN(z);
}
gfx::Point delta(
(msg == WM_POINTERHWHEEL ? z: 0),
(msg == WM_POINTERWHEEL ? -z: 0));
ev.setWheelDelta(delta);
queueEvent(ev);
MOUSE_TRACE("POINTERWHEEL xy=%d,%d delta=%d,%d\n",
ev.position().x, ev.position().y,
ev.wheelDelta().x, ev.wheelDelta().y);
return 0;
}
// Keyboard Messages
case WM_SYSKEYDOWN: case WM_SYSKEYDOWN:
case WM_KEYDOWN: { case WM_KEYDOWN: {
int vk = wparam; int vk = wparam;
@ -749,11 +994,10 @@ LRESULT WinWindow::wndProc(UINT msg, WPARAM wparam, LPARAM lparam)
case WM_NCHITTEST: { case WM_NCHITTEST: {
LRESULT result = CallWindowProc(DefWindowProc, m_hwnd, msg, wparam, lparam); LRESULT result = CallWindowProc(DefWindowProc, m_hwnd, msg, wparam, lparam);
gfx::Point pt(GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam)); gfx::Point pt(GET_X_LPARAM(lparam),
GET_Y_LPARAM(lparam));
RECT rc; ABS_CLIENT_RC(rc);
GetClientRect(m_hwnd, &rc);
MapWindowPoints(m_hwnd, NULL, (POINT*)&rc, 2);
gfx::Rect area(rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top); gfx::Rect area(rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top);
//LOG("NCHITTEST: %d %d - %d %d %d %d - %s\n", pt.x, pt.y, area.x, area.y, area.w, area.h, area.contains(pt) ? "true": "false"); //LOG("NCHITTEST: %d %d - %d %d %d %d - %s\n", pt.x, pt.y, area.x, area.y, area.w, area.h, area.contains(pt) ? "true": "false");
@ -772,6 +1016,8 @@ LRESULT WinWindow::wndProc(UINT msg, WPARAM wparam, LPARAM lparam)
return result; return result;
} }
// Wintab API Messages
case WT_PROXIMITY: { case WT_PROXIMITY: {
bool entering_ctx = (LOWORD(lparam) ? true: false); bool entering_ctx = (LOWORD(lparam) ? true: false);
if (!entering_ctx) if (!entering_ctx)
@ -836,6 +1082,56 @@ LRESULT WinWindow::wndProc(UINT msg, WPARAM wparam, LPARAM lparam)
return DefWindowProc(m_hwnd, msg, wparam, lparam); return DefWindowProc(m_hwnd, msg, wparam, lparam);
} }
void WinWindow::mouseEvent(LPARAM lparam, Event& ev)
{
ev.setModifiers(get_modifiers_from_last_win32_message());
ev.setPosition(gfx::Point(
GET_X_LPARAM(lparam) / m_scale,
GET_Y_LPARAM(lparam) / m_scale));
}
bool WinWindow::pointerEvent(WPARAM wparam, LPARAM lparam,
Event& ev, POINTER_INFO& pi)
{
if (!m_usePointerApi)
return false;
auto& winApi = system()->winApi();
if (!winApi.GetPointerInfo(GET_POINTERID_WPARAM(wparam), &pi))
return false;
ABS_CLIENT_RC(rc);
ev.setModifiers(get_modifiers_from_last_win32_message());
ev.setPosition(gfx::Point((pi.ptPixelLocation.x - rc.left) / m_scale,
(pi.ptPixelLocation.y - rc.top) / m_scale));
switch (pi.pointerType) {
case PT_MOUSE: {
ev.setPointerType(PointerType::Mouse);
break;
}
case PT_TOUCH:
case PT_TOUCHPAD: {
ev.setPointerType(PointerType::Multitouch);
break;
}
case PT_PEN: {
ev.setPointerType(PointerType::Pen);
POINTER_PEN_INFO ppi;
if (winApi.GetPointerPenInfo(pi.pointerId, &ppi)) {
if (ppi.penFlags & PEN_FLAG_ERASER)
ev.setPointerType(PointerType::Eraser);
}
break;
}
}
m_lastPointerId = pi.pointerId;
return true;
}
//static //static
void WinWindow::registerClass() void WinWindow::registerClass()
{ {

View File

@ -54,6 +54,9 @@ namespace she {
private: private:
bool setCursor(HCURSOR hcursor, bool custom); bool setCursor(HCURSOR hcursor, bool custom);
LRESULT wndProc(UINT msg, WPARAM wparam, LPARAM lparam); LRESULT wndProc(UINT msg, WPARAM wparam, LPARAM lparam);
void mouseEvent(LPARAM lparam, Event& ev);
bool pointerEvent(WPARAM wparam, LPARAM lparam,
Event& ev, POINTER_INFO& pi);
virtual void onQueueEvent(Event& ev) { } virtual void onQueueEvent(Event& ev) { }
virtual void onResize(const gfx::Size& sz) { } virtual void onResize(const gfx::Size& sz) { }
@ -76,6 +79,12 @@ namespace she {
bool m_captureMouse; bool m_captureMouse;
bool m_customHcursor; bool m_customHcursor;
// Windows 8 pointer API
bool m_usePointerApi;
bool m_ignoreMouseMessages;
UINT32 m_lastPointerId;
UINT32 m_capturePointerId;
// Wintab API data // Wintab API data
HCTX m_hpenctx; HCTX m_hpenctx;
PointerType m_pointerType; PointerType m_pointerType;