Welcome to mirror list, hosted at ThFree Co, Russian Federation.

GHOST_Wintab.h « intern « ghost « intern - git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 565aeb6ca026d9b33aba8f8a5e6358b8053f7739 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
/* SPDX-License-Identifier: GPL-2.0-or-later */

/** \file
 * \ingroup GHOST
 * Declaration of GHOST_WintabWin32 class.
 */

/* Wacom's Wintab documentation is periodically offline, moved, and increasingly hidden away. You
 * can find a (painstakingly) archived copy of the documentation at
 * https://web.archive.org/web/20201122230125/https://developer-docs-legacy.wacom.com/display/DevDocs/Windows+Wintab+Documentation
 */

#pragma once

#include <memory>
#include <stdio.h>
#include <vector>
#include <wtypes.h>

#include "GHOST_Types.h"

#include <wintab.h>
/* PACKETDATA and PACKETMODE modify structs in pktdef.h, so make sure they come first. */
#define PACKETDATA \
  (PK_BUTTONS | PK_NORMAL_PRESSURE | PK_ORIENTATION | PK_CURSOR | PK_X | PK_Y | PK_TIME)
#define PACKETMODE 0
#include <pktdef.h>

#define WINTAB_PRINTF(x, ...) \
  { \
    if (GHOST_Wintab::getDebug()) { \
      printf(x, __VA_ARGS__); \
    } \
  } \
  (void)0

/* Typedefs for Wintab functions to allow dynamic loading. */
typedef UINT(API *GHOST_WIN32_WTInfo)(UINT, UINT, LPVOID);
typedef BOOL(API *GHOST_WIN32_WTGet)(HCTX, LPLOGCONTEXTA);
typedef BOOL(API *GHOST_WIN32_WTSet)(HCTX, LPLOGCONTEXTA);
typedef HCTX(API *GHOST_WIN32_WTOpen)(HWND, LPLOGCONTEXTA, BOOL);
typedef BOOL(API *GHOST_WIN32_WTClose)(HCTX);
typedef int(API *GHOST_WIN32_WTPacketsGet)(HCTX, int, LPVOID);
typedef int(API *GHOST_WIN32_WTQueueSizeGet)(HCTX);
typedef BOOL(API *GHOST_WIN32_WTQueueSizeSet)(HCTX, int);
typedef BOOL(API *GHOST_WIN32_WTEnable)(HCTX, BOOL);
typedef BOOL(API *GHOST_WIN32_WTOverlap)(HCTX, BOOL);

/* Typedefs for Wintab and Windows resource management. */
typedef std::unique_ptr<std::remove_pointer_t<HMODULE>, decltype(&::FreeLibrary)> unique_hmodule;
typedef std::unique_ptr<std::remove_pointer_t<HCTX>, GHOST_WIN32_WTClose> unique_hctx;

struct GHOST_WintabInfoWin32 {
  int32_t x = 0;
  int32_t y = 0;
  GHOST_TEventType type = GHOST_kEventCursorMove;
  GHOST_TButton button = GHOST_kButtonMaskNone;
  uint64_t time = 0;
  GHOST_TabletData tabletData = GHOST_TABLET_DATA_NONE;
};

class GHOST_Wintab {
 public:
  /**
   * Loads Wintab if available.
   * \param hwnd: Window to attach Wintab context to.
   * \return Pointer to the initialized GHOST_Wintab object, or null if initialization failed.
   */
  static GHOST_Wintab *loadWintab(HWND hwnd);

  ~GHOST_Wintab();

  /**
   * Enables Wintab context.
   */
  void enable();

  /**
   * Disables the Wintab context and unwinds Wintab state.
   */
  void disable();

  /**
   * Brings Wintab context to the top of the overlap order.
   */
  void gainFocus();

  /**
   * Puts Wintab context at bottom of overlap order and unwinds Wintab state.
   */
  void loseFocus();

  /**
   * Clean up when Wintab leaves tracking range.
   */
  void leaveRange();

  /**
   * Handle Wintab coordinate changes when DisplayChange events occur.
   */
  void remapCoordinates();

  /**
   * Maps Wintab to Win32 display coordinates.
   * \param x_in: The tablet x coordinate.
   * \param y_in: The tablet y coordinate.
   * \param x_out: Output for the Win32 mapped x coordinate.
   * \param y_out: Output for the Win32 mapped y coordinate.
   */
  void mapWintabToSysCoordinates(int x_in, int y_in, int &x_out, int &y_out);

  /**
   * Updates cached Wintab properties for current cursor.
   */
  void updateCursorInfo();

  /**
   * Handle Wintab info changes such as change in number of connected tablets.
   * \param lParam: LPARAM of the event.
   */
  void processInfoChange(LPARAM lParam);

  /**
   * Whether Wintab devices are present.
   * \return True if Wintab devices are present.
   */
  bool devicesPresent();

  /**
   * Translate Wintab packets into GHOST_WintabInfoWin32 structs.
   * \param outWintabInfo: Storage to return resulting GHOST_WintabInfoWin32 data.
   */
  void getInput(std::vector<GHOST_WintabInfoWin32> &outWintabInfo);

  /**
   * Whether Wintab coordinates should be trusted.
   * \return True if Wintab coordinates should be trusted.
   */
  bool trustCoordinates();

  /**
   * Tests whether Wintab coordinates can be trusted by comparing Win32 and Wintab reported cursor
   * position.
   * \param sysX: System cursor x position.
   * \param sysY: System cursor y position.
   * \param wtX: Wintab cursor x position.
   * \param wtY: Wintab cursor y position.
   * \return True if Win32 and Wintab cursor positions match within tolerance.
   *
   * NOTE: Only test coordinates on button press, not release. This prevents issues when async
   * mismatch causes mouse movement to replay and snap back, which is only an issue while drawing.
   */
  bool testCoordinates(int sysX, int sysY, int wtX, int wtY);

  /**
   * Retrieve the most recent tablet data, or none if pen is not in range.
   * \return Most recent tablet data, or none if pen is not in range.
   */
  GHOST_TabletData getLastTabletData();

  /* Sets Wintab debugging.
   * \param debug: True to enable Wintab debugging.
   */
  static void setDebug(bool debug);

  /* Returns whether Wintab logging should occur.
   * \return True if Wintab logging should occur.
   */
  static bool getDebug();

 private:
  /** Wintab DLL handle. */
  unique_hmodule m_handle;
  /** Wintab API functions. */
  GHOST_WIN32_WTInfo m_fpInfo = nullptr;
  GHOST_WIN32_WTGet m_fpGet = nullptr;
  GHOST_WIN32_WTSet m_fpSet = nullptr;
  GHOST_WIN32_WTPacketsGet m_fpPacketsGet = nullptr;
  GHOST_WIN32_WTEnable m_fpEnable = nullptr;
  GHOST_WIN32_WTOverlap m_fpOverlap = nullptr;

  /** Stores the Wintab tablet context. */
  unique_hctx m_context;
  /** Whether the context is enabled. */
  bool m_enabled = false;
  /** Whether the context has focus and is at the top of overlap order. */
  bool m_focused = false;

  /** Pressed button map. */
  DWORD m_buttons = 0;

  /** Range of a coordinate space. */
  struct Range {
    /** Origin of range. */
    int org = 0;
    /** Extent of range. */
    int ext = 1;
  };

  /** 2D Coordinate space. */
  struct Coord {
    /** Range of x. */
    Range x = {};
    /** Range of y. */
    Range y = {};
  };
  /** Whether Wintab coordinates are trusted. */
  bool m_coordTrusted = false;
  /** Tablet input range. */
  Coord m_tabletCoord = {};
  /** System output range. */
  Coord m_systemCoord = {};

  int m_maxPressure = 0;
  int m_maxAzimuth = 0;
  int m_maxAltitude = 0;

  /** Number of connected Wintab devices. */
  UINT m_numDevices = 0;
  /** Reusable buffer to read in Wintab packets. */
  std::vector<PACKET> m_pkts;
  /** Most recently received tablet data, or none if pen is not in range. */
  GHOST_TabletData m_lastTabletData = GHOST_TABLET_DATA_NONE;

  /** Whether Wintab logging is enabled. */
  static bool m_debug;

  GHOST_Wintab(unique_hmodule handle,
               GHOST_WIN32_WTInfo info,
               GHOST_WIN32_WTGet get,
               GHOST_WIN32_WTSet set,
               GHOST_WIN32_WTPacketsGet packetsGet,
               GHOST_WIN32_WTEnable enable,
               GHOST_WIN32_WTOverlap overlap,
               unique_hctx hctx,
               Coord tablet,
               Coord system,
               int queueSize);

  /**
   * Convert Wintab system mapped (mouse) buttons into Ghost button mask.
   * \param cursor: The Wintab cursor associated to the button.
   * \param physicalButton: The physical button ID to inspect.
   * \return The system mapped button.
   */
  GHOST_TButton mapWintabToGhostButton(UINT cursor, WORD physicalButton);

  /**
   * Applies common modifications to Wintab context.
   * \param lc: Wintab context to modify.
   */
  static void modifyContext(LOGCONTEXT &lc);

  /**
   * Extracts tablet and system coordinates from Wintab context.
   * \param lc: Wintab context to extract coordinates from.
   * \param tablet: Tablet coordinates.
   * \param system: System coordinates.
   */
  static void extractCoordinates(LOGCONTEXT &lc, Coord &tablet, Coord &system);

  /* Prints Wintab Context information. */
  void printContextDebugInfo();
};