7 #define _USE_MATH_DEFINES
14 auto handle =
unique_hmodule(::LoadLibrary(
"Wintab32.dll"), &::FreeLibrary);
74 if (!info(WTI_DEFSYSCTX, 0, &lc)) {
79 extractCoordinates(lc, tablet, system);
90 const int maxQueue = 500;
91 int queueSize = queueSizeGet(hctx.get());
93 while (queueSize < maxQueue) {
94 int testSize =
min(queueSize + 16, maxQueue);
95 if (queueSizeSet(hctx.get(), testSize)) {
109 if (!queueSizeSet(hctx.get(), queueSize)) {
118 int sanityQueueSize = queueSizeGet(hctx.get());
119 WINTAB_PRINTF(
"HCTX %p %s queueSize: %d, queueSizeGet: %d\n",
140 void GHOST_Wintab::modifyContext(LOGCONTEXT &lc)
145 lc.lcOptions |= CXO_CSRMESSAGES | CXO_MESSAGES;
149 lc.lcOutOrgX = lc.lcInOrgX;
150 lc.lcOutOrgY = lc.lcInOrgY;
151 lc.lcOutExtX = lc.lcInExtX;
152 lc.lcOutExtY = lc.lcInExtY;
155 void GHOST_Wintab::extractCoordinates(LOGCONTEXT &lc, Coord &tablet, Coord &system)
157 tablet.x.org = lc.lcInOrgX;
158 tablet.x.ext = lc.lcInExtX;
159 tablet.y.org = lc.lcInOrgY;
160 tablet.y.ext = lc.lcInExtY;
162 system.x.org = lc.lcSysOrgX;
163 system.x.ext = lc.lcSysExtX;
164 system.y.org = lc.lcSysOrgY;
167 system.y.ext = -lc.lcSysExtY;
181 : m_handle{
std::move(handle)},
185 m_fpPacketsGet{packetsGet},
187 m_fpOverlap{overlap},
188 m_context{
std::move(hctx)},
189 m_tabletCoord{tablet},
190 m_systemCoord{system},
193 m_fpInfo(WTI_INTERFACE, IFC_NDEVICES, &m_numDevices);
199 printContextDebugInfo();
204 WINTAB_PRINTF(
"Closing Wintab context %p\n", m_context.get());
209 m_fpEnable(m_context.get(),
true);
218 m_fpEnable(m_context.get(),
false);
224 m_fpOverlap(m_context.get(),
true);
236 m_coordTrusted =
false;
238 m_fpOverlap(m_context.get(),
false);
249 m_fpPacketsGet(m_context.get(), m_pkts.size(), m_pkts.data());
256 if (m_fpInfo(WTI_DEFSYSCTX, 0, &lc)) {
257 extractCoordinates(lc, m_tabletCoord, m_systemCoord);
260 m_fpSet(m_context.get(), &lc);
266 AXIS Pressure, Orientation[3];
268 BOOL pressureSupport = m_fpInfo(WTI_DEVICES, DVC_NPRESSURE, &Pressure);
269 m_maxPressure = pressureSupport ? Pressure.axMax : 0;
270 WINTAB_PRINTF(
"HCTX %p %s maxPressure: %d\n", m_context.get(), __func__, m_maxPressure);
272 BOOL tiltSupport = m_fpInfo(WTI_DEVICES, DVC_ORIENTATION, &Orientation);
274 if (tiltSupport && Orientation[0].axResolution && Orientation[1].axResolution) {
275 m_maxAzimuth = Orientation[0].axMax;
276 m_maxAltitude = Orientation[1].axMax;
279 m_maxAzimuth = m_maxAltitude = 0;
281 WINTAB_PRINTF(
"HCTX %p %s maxAzimuth: %d, maxAltitude: %d\n",
291 if (LOWORD(lParam) == WTI_INTERFACE && HIWORD(lParam) == IFC_NDEVICES) {
292 m_fpInfo(WTI_INTERFACE, IFC_NDEVICES, &m_numDevices);
293 WINTAB_PRINTF(
"HCTX %p %s numDevices: %d\n", m_context.get(), __func__, m_numDevices);
299 return m_numDevices > 0;
304 return m_lastTabletData;
309 const int numPackets = m_fpPacketsGet(m_context.get(), m_pkts.size(), m_pkts.data());
310 outWintabInfo.reserve(numPackets);
312 for (
int i = 0; i < numPackets; i++) {
313 const PACKET pkt = m_pkts[i];
317 switch (pkt.pkCursor % 3) {
333 if (m_maxPressure > 0) {
334 out.tabletData.Pressure = (
float)pkt.pkNormalPressure / (
float)m_maxPressure;
337 if ((m_maxAzimuth > 0) && (m_maxAltitude > 0)) {
351 ORIENTATION ort = pkt.pkOrientation;
354 float altRad = (
float)((
fabs((
float)ort.orAltitude) / (
float)m_maxAltitude) *
M_PI_2);
355 float azmRad = (
float)(((
float)ort.orAzimuth / (
float)m_maxAzimuth) *
M_PI * 2.0);
358 float vecLen =
cos(altRad);
361 out.tabletData.Xtilt =
sin(azmRad) * vecLen;
365 out.time = pkt.pkTime;
369 DWORD buttonsChanged = m_buttons ^ pkt.pkButtons;
371 m_buttons = pkt.pkButtons;
374 for (WORD buttonIndex = 0; buttonsChanged; buttonIndex++, buttonsChanged >>= 1) {
375 if (buttonsChanged & 1) {
376 GHOST_TButton button = mapWintabToGhostButton(pkt.pkCursor, buttonIndex);
381 outWintabInfo.push_back(
out);
386 DWORD buttonFlag = 1 << buttonIndex;
392 outWintabInfo.push_back(
out);
395 if (!outWintabInfo.empty()) {
396 m_lastTabletData = outWintabInfo.back().tabletData;
400 GHOST_TButton GHOST_Wintab::mapWintabToGhostButton(
UINT cursor, WORD physicalButton)
402 const WORD numButtons = 32;
403 BYTE logicalButtons[numButtons] = {0};
404 BYTE systemButtons[numButtons] = {0};
406 if (!m_fpInfo(WTI_CURSORS + cursor, CSR_BUTTONMAP, &logicalButtons) ||
407 !m_fpInfo(WTI_CURSORS + cursor, CSR_SYSBTNMAP, &systemButtons)) {
411 if (physicalButton >= numButtons) {
415 BYTE lb = logicalButtons[physicalButton];
417 if (lb >= numButtons) {
421 switch (systemButtons[lb]) {
437 auto remap = [](
int inPoint, Range in, Range
out) ->
int {
438 int absInExt =
abs(in.ext);
439 int absOutExt =
abs(
out.ext);
442 int inMagnitude = inPoint - in.org;
445 if ((in.ext < 0) != (
out.ext < 0)) {
446 inMagnitude = absInExt - inMagnitude;
450 int outMagnitude = inMagnitude * absOutExt / absInExt;
453 int outPoint = outMagnitude +
out.org;
458 x_out = remap(x_in, m_tabletCoord.x, m_systemCoord.x);
459 y_out = remap(y_in, m_tabletCoord.y, m_systemCoord.y);
464 return m_coordTrusted;
472 if (
abs(sysX - wtX) <= 1 &&
abs(sysY - wtY) <= 1) {
473 m_coordTrusted =
true;
477 m_coordTrusted =
false;
482 bool GHOST_Wintab::m_debug =
false;
494 void GHOST_Wintab::printContextDebugInfo()
501 BYTE logicalButtons[32] = {0};
502 BYTE systemButtons[32] = {0};
503 for (
int i = 0; i < 3; i++) {
504 printf(
"initializeWintab cursor %d buttons\n", i);
505 UINT lbut = m_fpInfo(WTI_CURSORS + i, CSR_BUTTONMAP, &logicalButtons);
507 printf(
"%d", logicalButtons[0]);
508 for (
int j = 1; j < lbut; j++) {
509 printf(
", %d", logicalButtons[j]);
514 printf(
"logical button error\n");
516 UINT sbut = m_fpInfo(WTI_CURSORS + i, CSR_SYSBTNMAP, &systemButtons);
518 printf(
"%d", systemButtons[0]);
519 for (
int j = 1; j < sbut; j++) {
520 printf(
", %d", systemButtons[j]);
525 printf(
"system button error\n");
532 UINT maxcontexts, opencontexts;
533 m_fpInfo(WTI_INTERFACE, IFC_NCONTEXTS, &maxcontexts);
534 m_fpInfo(WTI_STATUS, STA_CONTEXTS, &opencontexts);
535 printf(
"%u max contexts, %u open contexts\n", maxcontexts, opencontexts);
538 printf(
"left: %d, top: %d, width: %d, height: %d\n",
539 ::GetSystemMetrics(SM_XVIRTUALSCREEN),
540 ::GetSystemMetrics(SM_YVIRTUALSCREEN),
541 ::GetSystemMetrics(SM_CXVIRTUALSCREEN),
542 ::GetSystemMetrics(SM_CYVIRTUALSCREEN));
544 auto printContextRanges = [](LOGCONTEXT &lc) {
545 printf(
"lcInOrgX: %d, lcInOrgY: %d, lcInExtX: %d, lcInExtY: %d\n",
550 printf(
"lcOutOrgX: %d, lcOutOrgY: %d, lcOutExtX: %d, lcOutExtY: %d\n",
555 printf(
"lcSysOrgX: %d, lcSysOrgY: %d, lcSysExtX: %d, lcSysExtY: %d\n",
565 m_fpInfo(WTI_DEFSYSCTX, 0, &lc);
566 printf(
"WTI_DEFSYSCTX\n");
567 printContextRanges(lc);
570 m_fpInfo(WTI_DEFSYSCTX, CTX_INORGX, &lc.lcInOrgX);
571 m_fpInfo(WTI_DEFSYSCTX, CTX_INORGY, &lc.lcInOrgY);
572 m_fpInfo(WTI_DEFSYSCTX, CTX_INEXTX, &lc.lcInExtX);
573 m_fpInfo(WTI_DEFSYSCTX, CTX_INEXTY, &lc.lcInExtY);
574 m_fpInfo(WTI_DEFSYSCTX, CTX_OUTORGX, &lc.lcOutOrgX);
575 m_fpInfo(WTI_DEFSYSCTX, CTX_OUTORGY, &lc.lcOutOrgY);
576 m_fpInfo(WTI_DEFSYSCTX, CTX_OUTEXTX, &lc.lcOutExtX);
577 m_fpInfo(WTI_DEFSYSCTX, CTX_OUTEXTY, &lc.lcOutExtY);
578 m_fpInfo(WTI_DEFSYSCTX, CTX_SYSORGX, &lc.lcSysOrgX);
579 m_fpInfo(WTI_DEFSYSCTX, CTX_SYSORGY, &lc.lcSysOrgY);
580 m_fpInfo(WTI_DEFSYSCTX, CTX_SYSEXTX, &lc.lcSysExtX);
581 m_fpInfo(WTI_DEFSYSCTX, CTX_SYSEXTY, &lc.lcSysExtY);
582 printf(
"WTI_DEFSYSCTX CTX_*\n");
583 printContextRanges(lc);
585 for (
unsigned int i = 0; i < m_numDevices; i++) {
587 m_fpInfo(WTI_DSCTXS + i, 0, &lc);
588 printf(
"WTI_DSCTXS %u\n", i);
589 printContextRanges(lc);
592 m_fpInfo(WTI_DSCTXS + i, CTX_INORGX, &lc.lcInOrgX);
593 m_fpInfo(WTI_DSCTXS + i, CTX_INORGY, &lc.lcInOrgY);
594 m_fpInfo(WTI_DSCTXS + i, CTX_INEXTX, &lc.lcInExtX);
595 m_fpInfo(WTI_DSCTXS + i, CTX_INEXTY, &lc.lcInExtY);
596 m_fpInfo(WTI_DSCTXS + i, CTX_OUTORGX, &lc.lcOutOrgX);
597 m_fpInfo(WTI_DSCTXS + i, CTX_OUTORGY, &lc.lcOutOrgY);
598 m_fpInfo(WTI_DSCTXS + i, CTX_OUTEXTX, &lc.lcOutExtX);
599 m_fpInfo(WTI_DSCTXS + i, CTX_OUTEXTY, &lc.lcOutExtY);
600 m_fpInfo(WTI_DSCTXS + i, CTX_SYSORGX, &lc.lcSysOrgX);
601 m_fpInfo(WTI_DSCTXS + i, CTX_SYSORGY, &lc.lcSysOrgY);
602 m_fpInfo(WTI_DSCTXS + i, CTX_SYSEXTX, &lc.lcSysExtX);
603 m_fpInfo(WTI_DSCTXS + i, CTX_SYSEXTY, &lc.lcSysExtY);
604 printf(
"WTI_DSCTX %u CTX_*\n", i);
605 printContextRanges(lc);
609 m_fpInfo(WTI_DEVICES + i, DVC_X, &axis_x);
610 m_fpInfo(WTI_DEVICES + i, DVC_Y, &axis_y);
611 printf(
"WTI_DEVICES %u axis_x org: %d, axis_y org: %d axis_x ext: %d, axis_y ext: %d\n",
615 axis_x.axMax - axis_x.axMin + 1,
616 axis_y.axMax - axis_y.axMin + 1);
620 printf(
"sysmode %d\n", lc.lcSysMode);
typedef float(TangentPoint)[2]
static const GHOST_TabletData GHOST_TABLET_DATA_NONE
@ GHOST_kTabletModeEraser
@ GHOST_kTabletModeStylus
@ GHOST_kButtonMaskMiddle
typedef UINT(API *GHOST_WIN32_GetDpiForWindow)(HWND)
BOOL(API * GHOST_WIN32_WTOverlap)(HCTX, BOOL)
BOOL(API * GHOST_WIN32_WTEnable)(HCTX, BOOL)
std::unique_ptr< std::remove_pointer_t< HCTX >, GHOST_WIN32_WTClose > unique_hctx
HCTX(API * GHOST_WIN32_WTOpen)(HWND, LPLOGCONTEXTA, BOOL)
BOOL(API * GHOST_WIN32_WTClose)(HCTX)
BOOL(API * GHOST_WIN32_WTGet)(HCTX, LPLOGCONTEXTA)
#define WINTAB_PRINTF(x,...)
std::unique_ptr< std::remove_pointer_t< HMODULE >, decltype(&::FreeLibrary)> unique_hmodule
BOOL(API * GHOST_WIN32_WTQueueSizeSet)(HCTX, int)
BOOL(API * GHOST_WIN32_WTSet)(HCTX, LPLOGCONTEXTA)
UINT(API * GHOST_WIN32_WTInfo)(UINT, UINT, LPVOID)
int(API * GHOST_WIN32_WTPacketsGet)(HCTX, int, LPVOID)
int(API * GHOST_WIN32_WTQueueSizeGet)(HCTX)
void mapWintabToSysCoordinates(int x_in, int y_in, int &x_out, int &y_out)
GHOST_TabletData getLastTabletData()
void getInput(std::vector< GHOST_WintabInfoWin32 > &outWintabInfo)
void processInfoChange(LPARAM lParam)
static GHOST_Wintab * loadWintab(HWND hwnd)
bool testCoordinates(int sysX, int sysY, int wtX, int wtY)
static void setDebug(bool debug)
ccl_device_inline float2 fabs(const float2 &a)
INLINE Rall1d< T, V, S > cos(const Rall1d< T, V, S > &arg)
INLINE Rall1d< T, V, S > sin(const Rall1d< T, V, S > &arg)
static const pxr::TfToken out("out", pxr::TfToken::Immortal)