298 lines
9.8 KiB
C++
298 lines
9.8 KiB
C++
|
|
||
|
// enable touch functions - set version to windows 7
|
||
|
// mingw otherwise doesn't load touch stuff
|
||
|
#define _WIN32_WINNT 0x0601
|
||
|
|
||
|
#include <thread>
|
||
|
#include <mutex>
|
||
|
#include <windowsx.h>
|
||
|
|
||
|
#include "win7.h"
|
||
|
|
||
|
#include "util/libutils.h"
|
||
|
#include "util/logging.h"
|
||
|
#include "rawinput/touch.h"
|
||
|
|
||
|
// mingw issue #2205 workaround
|
||
|
// https://sourceforge.net/p/mingw/bugs/2205/
|
||
|
#undef TOUCHEVENTF_MOVE
|
||
|
#define TOUCHEVENTF_MOVE 0x0001
|
||
|
#undef TOUCHEVENTF_DOWN
|
||
|
#define TOUCHEVENTF_DOWN 0x0002
|
||
|
|
||
|
// mingw doesn't seem to have these
|
||
|
#ifndef WM_TABLET_DEFBASE
|
||
|
#define WM_TABLET_DEFBASE 0x02C0
|
||
|
#define WM_TABLET_QUERYSYSTEMGESTURESTATUS (WM_TABLET_DEFBASE + 12)
|
||
|
#define TABLET_DISABLE_PRESSANDHOLD 0x00000001
|
||
|
#define TABLET_DISABLE_PENTAPFEEDBACK 0x00000008
|
||
|
#define TABLET_DISABLE_PENBARRELFEEDBACK 0x00000010
|
||
|
#define TABLET_DISABLE_TOUCHUIFORCEON 0x00000100
|
||
|
#define TABLET_DISABLE_TOUCHUIFORCEOFF 0x00000200
|
||
|
#define TABLET_DISABLE_TOUCHSWITCH 0x00008000
|
||
|
#define TABLET_DISABLE_FLICKS 0x00010000
|
||
|
#define TABLET_DISABLE_SMOOTHSCROLLING 0x00080000
|
||
|
#define TABLET_DISABLE_FLICKFALLBACKKEYS 0x00100000
|
||
|
#define TABLET_ENABLE_MULTITOUCHDATA 0x01000000
|
||
|
#endif
|
||
|
|
||
|
// general states
|
||
|
static HMODULE USER32_INSTANCE = nullptr;
|
||
|
static const char *LOG_MODULE_NAME = "touch::win7";
|
||
|
|
||
|
/* dynamic touch functions
|
||
|
* to maintain compatibility with windows XP
|
||
|
*/
|
||
|
static BOOL (WINAPI *pSetGestureConfig)(HWND, DWORD, UINT, PGESTURECONFIG, UINT);
|
||
|
static BOOL (WINAPI *pRegisterTouchWindow)(HWND, ULONG);
|
||
|
static BOOL (WINAPI *pGetTouchInputInfo)(HANDLE, UINT, PTOUCHINPUT, int);
|
||
|
static BOOL (WINAPI *pCloseTouchInputHandle)(HANDLE);
|
||
|
static BOOL (WINAPI *pUnregisterTouchWindow)(HWND hWnd);
|
||
|
|
||
|
// other
|
||
|
static const char ATOM_NAME[] = "MicrosoftTabletPenServiceProperty";
|
||
|
|
||
|
Win7Handler::Win7Handler() : TouchHandler("win7") {
|
||
|
|
||
|
// check if already loaded
|
||
|
static bool functions_loaded = false;
|
||
|
if (functions_loaded) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// load user32
|
||
|
if (USER32_INSTANCE == nullptr) {
|
||
|
USER32_INSTANCE = libutils::load_library("user32.dll");
|
||
|
}
|
||
|
|
||
|
// load touch functions
|
||
|
pSetGestureConfig = libutils::try_proc<decltype(pSetGestureConfig)>(
|
||
|
USER32_INSTANCE, "SetGestureConfig");
|
||
|
pRegisterTouchWindow = libutils::try_proc<decltype(pRegisterTouchWindow)>(
|
||
|
USER32_INSTANCE, "RegisterTouchWindow");
|
||
|
pGetTouchInputInfo = libutils::try_proc<decltype(pGetTouchInputInfo)>(
|
||
|
USER32_INSTANCE, "GetTouchInputInfo");
|
||
|
pCloseTouchInputHandle = libutils::try_proc<decltype(pCloseTouchInputHandle)>(
|
||
|
USER32_INSTANCE, "CloseTouchInputHandle");
|
||
|
pUnregisterTouchWindow = libutils::try_proc<decltype(pUnregisterTouchWindow)>(
|
||
|
USER32_INSTANCE, "UnregisterTouchWindow");
|
||
|
|
||
|
functions_loaded = true;
|
||
|
}
|
||
|
|
||
|
bool Win7Handler::is_available() {
|
||
|
bool win_touch_available = (GetSystemMetrics(94) & 0x80) == 0x80;
|
||
|
|
||
|
if (win_touch_available) {
|
||
|
log_info(LOG_MODULE_NAME, "WinTouch available");
|
||
|
} else {
|
||
|
log_info(LOG_MODULE_NAME, "WinTouch unavailable");
|
||
|
}
|
||
|
|
||
|
return win_touch_available;
|
||
|
}
|
||
|
|
||
|
bool Win7Handler::window_register(HWND hWnd) {
|
||
|
|
||
|
bool result = true;
|
||
|
|
||
|
// atom settings
|
||
|
DWORD dwHwndTabletProperty = TABLET_DISABLE_PRESSANDHOLD |
|
||
|
TABLET_DISABLE_PENTAPFEEDBACK |
|
||
|
TABLET_DISABLE_PENBARRELFEEDBACK |
|
||
|
TABLET_DISABLE_FLICKS;
|
||
|
|
||
|
// get atom ID
|
||
|
ATOM atom_id = GlobalAddAtom(ATOM_NAME);
|
||
|
|
||
|
// disable gestures
|
||
|
if (atom_id > 0) {
|
||
|
SetProp(hWnd, ATOM_NAME, (HANDLE) ((unsigned long long) dwHwndTabletProperty));
|
||
|
}
|
||
|
|
||
|
// register touch window
|
||
|
if ((pRegisterTouchWindow == nullptr) || (pRegisterTouchWindow(hWnd, TWF_WANTPALM) == 0)) {
|
||
|
log_warning(LOG_MODULE_NAME, "could not register touch window");
|
||
|
|
||
|
result = false;
|
||
|
}
|
||
|
|
||
|
// set gesture config
|
||
|
if (pSetGestureConfig != nullptr) {
|
||
|
GESTURECONFIG gc {};
|
||
|
gc.dwID = 0;
|
||
|
gc.dwWant = 0;
|
||
|
gc.dwBlock = 1;
|
||
|
pSetGestureConfig(hWnd, 0, 1, &gc, sizeof(GESTURECONFIG));
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
bool Win7Handler::window_unregister(HWND hWnd) {
|
||
|
|
||
|
// dispose window
|
||
|
if (pUnregisterTouchWindow != nullptr) {
|
||
|
pUnregisterTouchWindow(hWnd);
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
void Win7Handler::handle_message(msg_handler_result &result, HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
|
||
|
|
||
|
// parse touch messages
|
||
|
switch (msg) {
|
||
|
case WM_TOUCH: {
|
||
|
|
||
|
// touch input fields
|
||
|
UINT cInputs = LOWORD(wParam);
|
||
|
auto pInputs = std::make_unique<TOUCHINPUT[]>(cInputs);
|
||
|
|
||
|
// get touch input
|
||
|
if ((pGetTouchInputInfo != nullptr) &&
|
||
|
(pGetTouchInputInfo((HANDLE) lParam, cInputs, pInputs.get(), sizeof(TOUCHINPUT)) != 0)) {
|
||
|
|
||
|
// lock touch points
|
||
|
std::lock_guard<std::mutex> lock_points(TOUCH_POINTS_M);
|
||
|
std::lock_guard<std::mutex> lock_events(TOUCH_EVENTS_M);
|
||
|
|
||
|
// iterate all inputs
|
||
|
static long prev_x, prev_y;
|
||
|
for (UINT i = 0; i < cInputs; i++) {
|
||
|
auto &ti = pInputs[i];
|
||
|
|
||
|
// touch down
|
||
|
if (ti.dwFlags & TOUCHEVENTF_DOWN) {
|
||
|
|
||
|
// convert to window position
|
||
|
POINT point {};
|
||
|
point.x = ti.x / 100;
|
||
|
point.y = ti.y / 100;
|
||
|
ScreenToClient(hWnd, &point);
|
||
|
|
||
|
// create new touch point
|
||
|
TouchPoint tp {
|
||
|
.id = ti.dwID,
|
||
|
.x = point.x,
|
||
|
.y = point.y,
|
||
|
.mouse = false,
|
||
|
};
|
||
|
TOUCH_POINTS.push_back(tp);
|
||
|
|
||
|
// add touch down event
|
||
|
TouchEvent te {
|
||
|
.id = tp.id,
|
||
|
.x = tp.x,
|
||
|
.y = tp.y,
|
||
|
.type = TOUCH_DOWN,
|
||
|
.mouse = tp.mouse,
|
||
|
};
|
||
|
add_touch_event(&te);
|
||
|
|
||
|
// set prev coordinates
|
||
|
prev_x = point.x;
|
||
|
prev_y = point.y;
|
||
|
|
||
|
// card button
|
||
|
update_card_button();
|
||
|
}
|
||
|
|
||
|
// touch move
|
||
|
if ((ti.dwFlags & TOUCHEVENTF_MOVE) != 0u) {
|
||
|
|
||
|
// convert to window position
|
||
|
POINT point {};
|
||
|
point.x = ti.x / 100;
|
||
|
point.y = ti.y / 100;
|
||
|
ScreenToClient(hWnd, &point);
|
||
|
|
||
|
// check prev coordinates
|
||
|
if (point.x != prev_x || point.y != prev_y) {
|
||
|
|
||
|
// update point
|
||
|
for (auto &tp : TOUCH_POINTS) {
|
||
|
if (tp.id == ti.dwID) {
|
||
|
|
||
|
// update values
|
||
|
tp.x = point.x;
|
||
|
tp.y = point.y;
|
||
|
|
||
|
// add touch move event
|
||
|
TouchEvent te {
|
||
|
.id = tp.id,
|
||
|
.x = tp.x,
|
||
|
.y = tp.y,
|
||
|
.type = TOUCH_MOVE,
|
||
|
.mouse = tp.mouse,
|
||
|
};
|
||
|
add_touch_event(&te);
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// set prev coordinates
|
||
|
prev_x = point.x;
|
||
|
prev_y = point.y;
|
||
|
}
|
||
|
|
||
|
// touch up
|
||
|
if ((ti.dwFlags & TOUCHEVENTF_UP) != 0u) {
|
||
|
|
||
|
// remove point
|
||
|
for (size_t x = 0; x < TOUCH_POINTS.size(); x++) {
|
||
|
auto &tp = TOUCH_POINTS[x];
|
||
|
|
||
|
if (tp.id == ti.dwID) {
|
||
|
|
||
|
// add touch up event
|
||
|
TouchEvent te {
|
||
|
.id = tp.id,
|
||
|
.x = tp.x,
|
||
|
.y = tp.y,
|
||
|
.type = TOUCH_UP,
|
||
|
.mouse = tp.mouse,
|
||
|
};
|
||
|
add_touch_event(&te);
|
||
|
|
||
|
// remove from active touch points
|
||
|
TOUCH_POINTS.erase(TOUCH_POINTS.begin() + x);
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// clean up
|
||
|
if (pCloseTouchInputHandle != nullptr) {
|
||
|
pCloseTouchInputHandle((HANDLE) lParam);
|
||
|
}
|
||
|
|
||
|
result.action = ACTION_RETURN_DEFAULT;
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
case WM_TABLET_QUERYSYSTEMGESTURESTATUS: {
|
||
|
result.action = ACTION_RETURN_STORED;
|
||
|
result.return_value = TABLET_DISABLE_PRESSANDHOLD
|
||
|
| TABLET_DISABLE_PENTAPFEEDBACK
|
||
|
| TABLET_DISABLE_PENBARRELFEEDBACK
|
||
|
| TABLET_DISABLE_TOUCHUIFORCEON
|
||
|
| TABLET_DISABLE_TOUCHUIFORCEOFF
|
||
|
| TABLET_DISABLE_TOUCHSWITCH
|
||
|
| TABLET_DISABLE_FLICKS
|
||
|
| TABLET_DISABLE_SMOOTHSCROLLING
|
||
|
| TABLET_DISABLE_FLICKFALLBACKKEYS
|
||
|
| TABLET_ENABLE_MULTITOUCHDATA;
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|