summaryrefslogtreecommitdiff
path: root/FL/core/pen_events.H
blob: 39310e4cb93e8fe5d8d81cc530a59af6a83e3689 (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
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
//
// Pen event header file for the Fast Light Tool Kit (FLTK).
//
// Copyright 2025 by Bill Spitzak and others.
//
// This library is free software. Distribution and use rights are outlined in
// the file "COPYING" which should have been included with this file.  If this
// file is missing or damaged, see the license at:
//
//     https://www.fltk.org/COPYING.php
//
// Please see the following page on how to report bugs and issues:
//
//     https://www.fltk.org/bugs.php
//

/**
 \file FL/core/pen_events.H
 \brief Pen event handling variables and functions.
*/

#ifndef Fl_core_pen_events_H
#define Fl_core_pen_events_H

#include <FL/fl_config.h>             // build configuration
#include <FL/Fl_Export.H>             // for FL_EXPORT
#include <FL/core/function_types.H>   // widget callbacks and services

#include <stdint.h>

class Fl_Widget;

/**
 \defgroup fl_pen_events Pen and tablet event handling
 \ingroup fl_events
 \brief This chapter documents the Fl_Pen API, declared in <FL/core/pen_events.H>

 The Fl_Pen prefix contains everything needed to work with a pen type input
 device, either in connection with an external tablet, or as a stylus for
 drawing directly onto a screen.

 To receive pen input, call Fl_Pen_subscribe() for one or more widgets. The
 widget will receive a FL_PEN_ENTER event when the stylus enters the widget
 area. By returning 1 to FL_PEN_ENTER, all further pen events are sent to
 this widget, and no mouse events are generated until FL_PEN_LEAVE.

 Returning 0 to FL_PEN_ENTER tells FLTK to suppress further pen events until
 FL_PEN_LEAVE, and convert them into mouse events instead.

 Pen events also set Fl::event_x(), Fl::event_y(), Fl::event_x_root(),
 Fl::event_y_root(), Fl::event_is_click(), and Fl::event_clicks().

 @{
 */

/**
 \brief Bitfield of traits.
 This is used in Fl_Pen_driver_traits() and Fl_Pen_pen_traits().
 */
typedef uint32_t Fl_Pen_Trait;
enum {
  /// No bits set
  FL_PEN_TRAIT_NONE              = 0x0000,
  /// Set if FLTK supports tablets and pens on this platform
  FL_PEN_TRAIT_DRIVER_AVAILABLE  = 0x0001,
  /// Set after the system detected a pen, stylus, or tablet. This bit may not be
  /// set until a pen is brought into proximity of the tablet.
  FL_PEN_TRAIT_DETECTED          = 0x0002,
  /// If set, this is a digitizer for a display; if clear, this is a standalone tablet
  FL_PEN_TRAIT_DISPLAY           = 0x0004,
  /// Driver provides different device IDs for different pens
  FL_PEN_TRAIT_PEN_ID            = 0x0008,
  /// Pen may have an eraser tip
  FL_PEN_TRAIT_ERASER            = 0x0010,
  /// Pen returns a pressure value
  FL_PEN_TRAIT_PRESSURE          = 0x0020,
  /// Pen returns a barrel pressure value (tangential pressure)
  FL_PEN_TRAIT_BARREL_PRESSURE   = 0x0040,
  /// Pen returns tilt in X direction
  FL_PEN_TRAIT_TILT_X            = 0x0080,
  /// Pen returns tilt in Y direction
  FL_PEN_TRAIT_TILT_Y            = 0x0100,
  /// Pen returns a twist value
  FL_PEN_TRAIT_TWIST             = 0x0200,
  /// Pen returns a proximity value
  FL_PEN_TRAIT_PROXIMITY         = 0x0400
};


/**
 \brief Bitfield of pen state flags.
 \see Fl_Pen_event_state(), Fl_Pen_event_trigger()
 */
typedef uint32_t Fl_Pen_State;
enum {
  /// No button pressed
  FL_PEN_STATE_NONE              = 0x0000,
  /// The tip hovers over the surface but does not touch it
  FL_PEN_STATE_TIP_HOVERS        = 0x0001,
  /// The tip touches the surface
  FL_PEN_STATE_TIP_DOWN          = 0x0002,
  /// The eraser hovers over the surface but does not touch it
  FL_PEN_STATE_ERASER_HOVERS     = 0x0004,
  /// The eraser touches the surface
  FL_PEN_STATE_ERASER_DOWN       = 0x0008,
  /// Barrel button 0, usually the lower button on a pen, is pressed
  FL_PEN_STATE_BUTTON0           = 0x0100,
  /// Barrel button 1, usually the upper button on a pen, is pressed
  FL_PEN_STATE_BUTTON1           = 0x0200,
  /// Barrel button 2 is pressed
  FL_PEN_STATE_BUTTON2           = 0x0400,
  /// Barrel button 3 is pressed
  FL_PEN_STATE_BUTTON3           = 0x0800,
  /// Mask for all buttons, tip, and eraser down
  FL_PEN_STATE_ANY_DOWN          = 0x0100 | 0x0200 | 0x0400 | 0x0800 | 0x0002 | 0x0008
};


/**
 \brief List of pen events.
 These events extend the standard Fl_Event enumeration.
 \see enum Fl_Event
 */
enum {
  /**
   Pen entered the proximity of the tablet with a new pen.
   */
  FL_PEN_DETECTED = 0x1000,

  /**
   Pen entered the proximity of the tablet with a known, but changed pen.
   User changed to a different pen (event_id() > 0) or the pen or tablet
   was disconnected (event_id() == -1). Pen IDs, if supported, are assigned by
   the tablet manufacturer.
   */
  FL_PEN_CHANGED,

  /**
   Pen entered the proximity of the tablet with a known pen.
   */
  FL_PEN_IN_RANGE,

  /**
   Pen left the proximity of the tablet.
   */
  FL_PEN_OUT_OF_RANGE,

  /**
   Pen entered the widget area, either by moving in x/y, or by
   a proximity change (pen gets closer to the surface).
   Fl_Pen_event_trigger() returns 0, FL_PEN_STATE_TIP_HOVERS, or FL_PEN_STATE_ERASER_HOVERS.
   */
  FL_PEN_ENTER,

  /**
   If no button is pressed, indicates that the pen left the widget area.
   While any pen button is held down, or the pen touches the surface,
   Fl::pushed() is set, and the pushed widgets receives DRAG events, even
   if the pen leaves the widget area. If all buttons are released outside the
   widget area, a LEAVE event is sent as well as FL_PEN_LIFT or FL_PEN_BUTTON_RELEASE.
   */
  FL_PEN_LEAVE,

  /**
   Pen went from hovering to touching the surface.
   Fl_Pen_event_trigger() returns FL_PEN_STATE_TIP_DOWN or FL_PEN_STATE_ERASER_DOWN.
   */
  FL_PEN_TOUCH,

  /**
   Pen went from touching to hovering over the surface.
   Fl_Pen_event_trigger() returns FL_PEN_STATE_TIP_HOVERS or FL_PEN_STATE_ERASER_HOVERS.
  */
  FL_PEN_LIFT,

  /** Pen moved without touching the surface and no button is pressed. */
  FL_PEN_HOVER,

  /** Pen moved while touching the surface, or any button is pressed. */
  FL_PEN_DRAW,

  /**
   A pen button was pushed.
   Fl_Pen_event_trigger() returns FL_PEN_STATE_BUTTON0, FL_PEN_STATE_BUTTON1, FL_PEN_STATE_BUTTON2, or FL_PEN_STATE_BUTTON3.
   */
  FL_PEN_BUTTON_PUSH,

  /**
   A pen button was released.
   Fl_Pen_event_trigger() returns FL_PEN_STATE_BUTTON0, FL_PEN_STATE_BUTTON1, FL_PEN_STATE_BUTTON2, or FL_PEN_STATE_BUTTON3.
   */
  FL_PEN_BUTTON_RELEASE

};

/**
 \brief Query the traits supported by the pen/tablet driver.

 This function returns a bitfield of traits that are supported by the FLTK driver
 for this platform. If a trait is not supported, the corresponding event value
 will not return a useful value. Note that even if the FLTK driver support a
 trait, the underlying pen device or driver may not. The Fl_Pen API will return
 a known default for those event values.

 The bitfield returned is static.

 \return a bitfield of supported traits
 \see Fl_Pen_pen_traits()
 */
FL_EXPORT Fl_Pen_Trait Fl_Pen_driver_traits(void);

/**
 \brief Return non-zero if the corresponding bit is set in the driver traits.
 \param[in] bits check for one or more trait bits
 \return non-zero if any bit is set
 */
inline int Fl_Pen_driver_traits_check(Fl_Pen_Trait bits) {
  return ((Fl_Pen_driver_traits() & bits) != FL_PEN_TRAIT_NONE);
}

/**
 \brief Query traits of the current pen or stylus.
 The value returned by this function may change when pens change or when more
 information becomes known about the currently used pen.
 \param[in] pen_id a know pen ID as returned from Fl_Pen_event_pen_id(),
    or 0 for the current pen
 \return a bitfield of supported traits
 */
FL_EXPORT Fl_Pen_Trait Fl_Pen_pen_traits(int pen_id);

/**
 \brief Return non-zero if the corresponding bit is set in the pen traits.
 \param[in] bits check for one or more trait bits
 \param[in] pen_id a know pen ID as returned from Fl_Pen_event_pen_id(),
  or 0 for the current pen
 \return non-zero if any bit is set
 */
inline int Fl_Pen_pen_traits_check(Fl_Pen_Trait bits, int pen_id) {
  return ((Fl_Pen_pen_traits(pen_id) & bits) != FL_PEN_TRAIT_NONE);
}

/**
 \brief Receives a FL_PEN_ENTER event when the pen enters this widget.
 Multiple widgets may subscribe to pen events. Additional subscription
 requests for the same widget are ignored.
 \param widget The widget subscribing to pen events.
 */
FL_EXPORT void Fl_Pen_subscribe(Fl_Widget* widget);

/**
 \brief Stop receiving FL_PEN_ENTER for this widget.
 Deleting a widget will automatically unsubscribe it.
 \param widget Widget to unsubscribe from pen events
 */
FL_EXPORT void Fl_Pen_unsubscribe(Fl_Widget* widget);

/**
 Clear the "pushed" state and forward pen events as mouse events.
 Call this if another window is popped up during pen event handling, so
 mouse event handling can resume normal.
 */
FL_EXPORT void Fl_Pen_release(void);

/// \name Query values during event handling
/// @{

/**
 \brief Returns the pen x and y position inside the handling widget as doubles.
 These functions provide high-precision pen coordinates relative to the widget
 that received the pen event. For integer coordinates, use Fl::event_x() and
 Fl::event_y() instead.
 \return Pen position as floating-point coordinate, defaults to 0.0
 \see Fl::event_x(), Fl::event_y()
 */
FL_EXPORT double Fl_Pen_event_x(void);
/** \brief Returns pen Y coordinate in widget space, see Fl_Pen_event_x(). */
FL_EXPORT double Fl_Pen_event_y(void);

/**
 \brief Returns the pen x and y position in global coordinates as doubles.
 For integer coordinates, use Fl::event_x_root() and Fl::event_y_root().
 \return Pen position as floating-point coordinate in screen space, defaults to 0.0
 \see Fl::event_x_root(), Fl::event_y_root()
 */
FL_EXPORT double Fl_Pen_event_x_root(void);
/** \brief Returns pen Y coordinate in screen space, see Fl_Pen_event_x_root(). */
FL_EXPORT double Fl_Pen_event_y_root(void);

/**
 \brief Returns the ID of the pen used in the last event.
 \return Unique pen identifier, or -1 if pen was removed, defaults to 0
 \see FL_PEN_TRAIT_PEN_ID
 */
FL_EXPORT int Fl_Pen_event_pen_id(void);

/**
 \brief Returns the pressure between the tip or eraser and the surface.
 \return pressure value from 0.0 (no pressure) to 1.0 (maximum pressure),
      defaults to 1.0.
 \see FL_PEN_TRAIT_PRESSURE
 */
FL_EXPORT double Fl_Pen_event_pressure(void);

/**
 \brief Returns barrel pressure or tangential pressure.
 \return Pressure value from -1.0 to 1.0 , defaults to 0.0 .
 \see FL_PEN_TRAIT_BARREL_PRESSURE
 */
FL_EXPORT double Fl_Pen_event_barrel_pressure(void);

/**
 \brief Returns the tilt of the pen in the x and y directions between -1 and 1.

 X-axis tilt returns -1.0 when the pen tilts all the way to the left, 0.0 when
 it is perfectly vertical, and 1.0 all the way to the right. Most pens seem to
 return a maximum range of -0.7 to 0.7.

 Y-axis tilt returns -1.0 when the pen tilts away from the user, and 1.0 when
 it tilts toward the user.

 \return Tilt value from -1.0 to 1.0, defaults to 0.0
 \see FL_PEN_TRAIT_TILT_X, FL_PEN_TRAIT_TILT_Y
 */
FL_EXPORT double Fl_Pen_event_tilt_x(void);
/** \brief Returns pen Y-axis tilt, see Fl_Pen_event_tilt_x() */
FL_EXPORT double Fl_Pen_event_tilt_y(void);

/**
 \brief Returns the pen's axial rotation in degrees.
 The twist angle is reported in degrees, with:
  - 0 deg : pen's "top" (the button side) facing upward
  - +180 deg : twisted halfway clockwise, looking at the end of the pen toward the tip
  - -180 deg : twisted half way counter clockwise
 So the full range is usually -180 to +180.
 \return Twist angle in degrees, defaults to 0.0.
 \see FL_PEN_TRAIT_TWIST
 */
FL_EXPORT double Fl_Pen_event_twist(void);

/**
 \brief Returns the proximity of the pen to the surface between 0 and 1.
 A proximity of 0 is closest to the surface, 1 is farthest away.
 \return Proximity value from 0.0 (touching) to 1.0 (far away), defaults to 0.0 .
 \see FL_PEN_TRAIT_PROXIMITY
 */
FL_EXPORT double Fl_Pen_event_proximity(void);

/**
 \brief Returns the state of the various buttons and tips.
 \return Current state flags (combination of Fl_Pen_State values)
 */
FL_EXPORT Fl_Pen_State Fl_Pen_event_state(void);

/**
 \brief Return non-zero if any of the bits are set in the event state.
 \param[in] bits check for one or more event state bits
 \return non-zero if any bit is set
 */
inline int Fl_Pen_event_state_check(Fl_Pen_State bits) {
  return ((Fl_Pen_event_state() & bits) != FL_PEN_STATE_NONE);
}

/**
 \brief Returns the state change that triggered the event.
 \return a state with one bit set for the action that triggered this event
 */
FL_EXPORT Fl_Pen_State Fl_Pen_event_trigger(void);

/** @} */ // group fl_pen_events


/*
 Resources:

 Windows:
 1. Legacy WinTab API (Win2k), Wintab32.dll, wintab.h
    https://developer.wacom.com/en-us/developer-dashboard/downloads
 2. Windows Ink API (Modern, Win10), Windows.UI.Input.Inking (WinRT API), InkCanvas(), etc.
    https://learn.microsoft.com/windows/uwp/design/input/windows-ink
 3. Pointer Input / WM_POINTER API (Win8), WM_POINTERUPDATE, GetPointerPenInfo
    https://learn.microsoft.com/windows/win32/inputmsg/wm-pointerupdate
      return WTInfo(0, 0, NULL) > 0; // Wintab check

 Linux:
 1. Low-level: evdev, /dev/input/event*, libevdev,
    https://www.kernel.org/doc/html/latest/input/event-codes.html
 2. Mid-level: XInput2 (for X11), XI_Motion, XI_ButtonPress
    https://www.x.org/releases/current/doc/inputproto/XI2proto.txt
    https://www.freedesktop.org/wiki/Software/libevdev/
 3. Mid-level: Wayland tablet protocol, tablet-v2 protocol,
    zwp_tablet_tool_v2_listener, zwp_tablet_v2, zwp_tablet_seat_v2
    https://wayland.app/protocols/tablet-v2

 SDL3:
    https://github.com/libsdl-org/SDL/blob/main/include/SDL3/SDL_pen.h
    https://wiki.libsdl.org/SDL3/CategoryPen
 */


#endif // !Fl_core_pen_events_H