437 lines
13 KiB
C++
437 lines
13 KiB
C++
//
|
|
// 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 <cstdint>
|
|
|
|
class Fl_Widget;
|
|
|
|
namespace Fl {
|
|
|
|
namespace Pen {
|
|
|
|
/**
|
|
\defgroup fl_pen_events Pen and tablet event handling
|
|
\ingroup fl_events
|
|
\brief The Fl::Pen namespace API, declared in <FL/core/pen_events.H>
|
|
|
|
The FL::Pen namespace 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.
|
|
By returning 1 to pen events, the user can ask for more detailed events.
|
|
|
|
Returning 0 form the event handler indicates that the event was not handled.
|
|
FLTK may convert the tablet event into a mouse event and resend it to
|
|
the relevant widget.
|
|
|
|
@{
|
|
*/
|
|
|
|
/**
|
|
\brief Bitfield of traits.
|
|
This is used in Fl::Pen::driver_traits() and Fl::Pen::pen_traits().
|
|
*/
|
|
enum class Trait : uint32_t {
|
|
/// Set if FLTK supports tablets and pens on this platform
|
|
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.
|
|
DETECTED = 0x0002,
|
|
/// If set, this is a digitizer for a display; if clear, this is a standalone tablet
|
|
DISPLAY = 0x0004,
|
|
/// Driver provides different device IDs for different pens
|
|
DEVICE_ID = 0x0008,
|
|
/// Pen may have an eraser tip
|
|
ERASER = 0x0010,
|
|
/// Pen returns a pressure value
|
|
PRESSURE = 0x0020,
|
|
/// Pen returns a barrel pressure value (tangential pressure)
|
|
BARREL_PRESSURE = 0x0040,
|
|
/// Pen returns tilt in X direction
|
|
TILT_X = 0x0080,
|
|
/// Pen returns tilt in Y direction
|
|
TILT_Y = 0x0100,
|
|
/// Pen returns a twist value
|
|
TWIST = 0x0200,
|
|
/// Pen returns a proximity value
|
|
PROXIMITY = 0x0400,
|
|
};
|
|
|
|
/**
|
|
\brief Bitwise OR operator for Trait enum.
|
|
\param lhs Left-hand side trait flags
|
|
\param rhs Right-hand side trait flags
|
|
\return Combined trait flags
|
|
*/
|
|
inline constexpr Trait operator|(Trait lhs, Trait rhs) {
|
|
return static_cast<Trait>(static_cast<uint32_t>(lhs) | static_cast<uint32_t>(rhs));
|
|
}
|
|
|
|
/**
|
|
\brief Bitwise AND operator for Trait enum.
|
|
\param lhs Left-hand side trait flags
|
|
\param rhs Right-hand side trait flags
|
|
\return Intersection of trait flags
|
|
*/
|
|
inline constexpr Trait operator&(Trait lhs, Trait rhs) {
|
|
return static_cast<Trait>(static_cast<uint32_t>(lhs) & static_cast<uint32_t>(rhs));
|
|
}
|
|
|
|
/**
|
|
\brief Bitwise OR assignment operator for Trait enum.
|
|
\param lhs Left-hand side trait flags (modified in place)
|
|
\param rhs Right-hand side trait flags
|
|
\return Reference to modified lhs
|
|
*/
|
|
inline Trait& operator|=(Trait& lhs, Trait rhs) {
|
|
lhs = lhs | rhs;
|
|
return lhs;
|
|
}
|
|
|
|
|
|
/**
|
|
\brief Bitfield of pen state flags.
|
|
\see event_state(), event_trigger()
|
|
*/
|
|
enum class State : uint32_t {
|
|
/// No button pressed
|
|
NONE = 0x0000,
|
|
/// The tip hovers over the surface but does not touch it
|
|
TIP_HOVERS = 0x0001,
|
|
/// The tip touches the surface
|
|
TIP_DOWN = 0x0002,
|
|
/// The eraser hovers over the surface but does not touch it
|
|
ERASER_HOVERS = 0x0004,
|
|
/// The eraser touches the surface
|
|
ERASER_DOWN = 0x0008,
|
|
/// Barrel button 0, usually the lower button on a pen, is pressed
|
|
BUTTON0 = 0x0100,
|
|
/// Barrel button 1, usually the upper button on a pen, is pressed
|
|
BUTTON1 = 0x0200,
|
|
/// Barrel button 2 is pressed
|
|
BUTTON2 = 0x0400,
|
|
/// Barrel button 3 is pressed
|
|
BUTTON3 = 0x0800,
|
|
/// Mask for all buttons, tip, and eraser down
|
|
ANY_DOWN = BUTTON0 | BUTTON1 | BUTTON2 | BUTTON3 | TIP_DOWN | ERASER_DOWN,
|
|
};
|
|
|
|
/*
|
|
\brief Bitwise OR operator for State enum.
|
|
\param lhs Left-hand side state flags
|
|
\param rhs Right-hand side state flags
|
|
\return Combined state flags
|
|
*/
|
|
inline constexpr State operator|(State lhs, State rhs) {
|
|
return static_cast<State>(static_cast<uint32_t>(lhs) | static_cast<uint32_t>(rhs));
|
|
}
|
|
|
|
/*
|
|
\brief Bitwise AND operator for State enum.
|
|
\param lhs Left-hand side state flags
|
|
\param rhs Right-hand side state flags
|
|
\return Intersection of state flags
|
|
*/
|
|
inline constexpr State operator&(State lhs, State rhs) {
|
|
return static_cast<State>(static_cast<uint32_t>(lhs) & static_cast<uint32_t>(rhs));
|
|
}
|
|
|
|
/*
|
|
\brief Bitwise OR assignment operator for State enum.
|
|
\param lhs Left-hand side state flags (modified in place)
|
|
\param rhs Right-hand side state flags
|
|
\return Reference to modified lhs
|
|
*/
|
|
inline State& operator|=(State& lhs, State rhs) {
|
|
lhs = lhs | rhs;
|
|
return lhs;
|
|
}
|
|
|
|
|
|
/**
|
|
\brief List of pen events.
|
|
These events extend the standard Fl_Event enumeration.
|
|
\see enum Fl_Event
|
|
*/
|
|
enum Event {
|
|
/**
|
|
A pen was detected for the first time for this subscriber.
|
|
*/
|
|
DETECTED = 0x1000,
|
|
|
|
/**
|
|
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.
|
|
|
|
Return 1 to receive ENTER and LEAVE events.
|
|
*/
|
|
CHANGED,
|
|
|
|
/**
|
|
Pen entered the widget area, either by moving in x/y, or by
|
|
a proximity change (pen gets closer to the surface).
|
|
event_trigger() returns 0, TIP_HOVERS, or ERASER_HOVERS.
|
|
Return 1 to receive MOVE events.
|
|
*/
|
|
ENTER,
|
|
|
|
/**
|
|
\brief Pen left the widget area.
|
|
No event values are set.
|
|
*/
|
|
LEAVE,
|
|
|
|
/**
|
|
Pen went from hovering to touching the surface.
|
|
event_trigger() returns TIP_DOWN or ERASER_DOWN.
|
|
Return 1 to receive DRAW events.
|
|
*/
|
|
TOUCH,
|
|
|
|
/**
|
|
Pen went from touching to hovering over the surface.
|
|
event_trigger() returns TIP_HOVERS or ERASER_HOVERS.
|
|
*/
|
|
LIFT,
|
|
|
|
/** Pen moved without touching the surface. */
|
|
HOVER,
|
|
|
|
/** Pen moved while touching the surface. */
|
|
DRAW,
|
|
|
|
/**
|
|
A pen button was pushed.
|
|
event_trigger() returns BUTTON0, BUTTON1, BUTTON2, or BUTTON3.
|
|
*/
|
|
BUTTON_PUSH,
|
|
|
|
/**
|
|
A pen button was released.
|
|
event_trigger() returns BUTTON0, BUTTON1, BUTTON2, or BUTTON3.
|
|
*/
|
|
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. Fl::Pen will return a
|
|
known default for those event values.
|
|
|
|
The bitfield returned is static.
|
|
|
|
\return a bitfield of supported traits
|
|
\see pen_traits()
|
|
*/
|
|
FL_EXPORT extern Trait driver_traits();
|
|
|
|
/**
|
|
\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] window must be a mapped (shown, visible) window
|
|
\return a bitfield of supported traits
|
|
*/
|
|
FL_EXPORT extern Trait pen_traits(Fl_Window *window);
|
|
|
|
/**
|
|
\brief Receive pen events when the pen is inside this widget, or all events.
|
|
Multiple widgets can subscribe to pen events, but every widget must only
|
|
subscribe once.
|
|
\param widget Widget to subscribe to pen events
|
|
*/
|
|
FL_EXPORT extern void subscribe(Fl_Widget* widget);
|
|
|
|
/**
|
|
\brief Stop receiving pen events for this widget.
|
|
Deleting a widget will automatically unsubscribe it.
|
|
\param widget Widget to unsubscribe from pen events
|
|
*/
|
|
FL_EXPORT extern void unsubscribe(Fl_Widget* widget);
|
|
|
|
/**
|
|
\brief Grab all pen events, including those outside the widget, until released.
|
|
Send all pen events exclusively to this widget to allow consistent drawing,
|
|
even when the pen leaves the widget area.
|
|
\param widget Widget that will receive all pen events
|
|
*/
|
|
FL_EXPORT extern void grab(Fl_Widget* widget);
|
|
|
|
/**
|
|
* \brief Release pen event handling after grab().
|
|
*/
|
|
FL_EXPORT extern void release();
|
|
|
|
/// \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 extern double event_x();
|
|
/** \brief Returns pen Y coordinate in widget space, see event_x(). */
|
|
FL_EXPORT extern double event_y();
|
|
|
|
/**
|
|
\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 extern double event_x_root();
|
|
/** \brief Returns pen Y coordinate in screen space, see event_x_root(). */
|
|
FL_EXPORT extern double event_y_root();
|
|
|
|
/**
|
|
\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 Trait::DEVICE_ID
|
|
*/
|
|
FL_EXPORT extern int event_id();
|
|
|
|
/**
|
|
\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 Trait::PRESSURE
|
|
*/
|
|
FL_EXPORT extern double event_pressure();
|
|
|
|
/**
|
|
\brief Returns barrel pressure or tangential pressure.
|
|
\return Pressure value from -1.0 to 1.0 , defaults to 0.0 .
|
|
\see Trait::BARREL_PRESSURE
|
|
*/
|
|
FL_EXPORT extern double event_barrel_pressure();
|
|
|
|
/**
|
|
\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 Trait::TILT_X, Trait::TILT_Y
|
|
*/
|
|
FL_EXPORT extern double event_tilt_x();
|
|
/** \brief Returns pen Y-axis tilt, see event_tilt_x() */
|
|
FL_EXPORT extern double event_tilt_y();
|
|
|
|
/**
|
|
* \brief Returns the pens axial rotation in degrees.
|
|
* \return Twist angle in degrees, defaults to 0.0 .
|
|
* \see Trait::TWIST
|
|
*/
|
|
FL_EXPORT extern double event_twist();
|
|
|
|
/**
|
|
* \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 Trait::PROXIMITY
|
|
*/
|
|
FL_EXPORT extern double event_proximity();
|
|
|
|
/**
|
|
* \brief Returns the state of the various buttons and tips.
|
|
* \return Current state flags (combination of State values)
|
|
*/
|
|
FL_EXPORT extern State event_state();
|
|
|
|
/**
|
|
* \brief Return true if the corresponding bit is set in the event state.
|
|
* \return true if any bit is set
|
|
*/
|
|
inline bool event_state(State bits) {
|
|
return ((event_state() & bits) != 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 extern State event_trigger();
|
|
|
|
/** @} */ // group fl_pen_events
|
|
|
|
|
|
} // namespace Pen
|
|
|
|
} // namespace Fl
|
|
|
|
|
|
/*
|
|
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
|