wolfhece.tablet_wintab ====================== .. py:module:: wolfhece.tablet_wintab .. autoapi-nested-parse:: wolfhece/tablet_wintab.py ========================= Direct WinTab pressure reader via ``Wintab32.dll`` (ctypes). ``wx.glcanvas.GLCanvas`` is not registered as a WinTab context by wxPython, so ``wx.MouseEvent.GetPressure()`` always returns 0.0 on OpenGL canvases even with a working Wacom driver. This module bypasses wx and opens its own WinTab context, then polls the packet queue in EVT_MOTION handlers. Usage:: # In WolfMapViewer.__init__ (after super().__init__): try: from wolfhece.tablet_wintab import WinTabContext self._wintab = WinTabContext(self.GetHandle()) except Exception as exc: logging.warning("WinTab unavailable: %s", exc) self._wintab = None # In _get_event_pressure: if self._wintab is not None: return self._wintab.get_pressure() # On window close: if self._wintab is not None: self._wintab.close() Module Contents --------------- .. py:exception:: DllNotFoundError Bases: :py:obj:`RuntimeError` .. autoapi-inheritance-diagram:: wolfhece.tablet_wintab.DllNotFoundError :parts: 1 :private-bases: Raised when Wintab32.dll cannot be found on this machine. .. py:data:: log .. py:data:: _WTI_DEFCONTEXT :value: 3 .. py:data:: _WTI_DEVICES :value: 100 .. py:data:: _DVC_NPRESSURE :value: 15 .. py:data:: _CXO_MESSAGES :value: 4 .. py:data:: _PK_NORMAL_PRESSURE :value: 1024 .. py:class:: _LOGCONTEXTA Bases: :py:obj:`ctypes.Structure` .. autoapi-inheritance-diagram:: wolfhece.tablet_wintab._LOGCONTEXTA :parts: 1 :private-bases: LOGCONTEXTA — WinTab logical context (ASCII variant). .. py:attribute:: _fields_ .. py:class:: _AXIS Bases: :py:obj:`ctypes.Structure` .. autoapi-inheritance-diagram:: wolfhece.tablet_wintab._AXIS :parts: 1 :private-bases: AXIS — range and resolution of one tablet axis. .. py:attribute:: _fields_ .. py:class:: _PACKET Bases: :py:obj:`ctypes.Structure` .. autoapi-inheritance-diagram:: wolfhece.tablet_wintab._PACKET :parts: 1 :private-bases: Minimal WinTab packet containing only normal pressure. Must match the ``lcPktData`` mask set in the LOGCONTEXT (only ``_PK_NORMAL_PRESSURE`` is requested, so the packet is one UINT). .. py:attribute:: _fields_ .. py:class:: WinTabContext(hwnd: int) Reads stylus pressure via ``Wintab32.dll`` (polling mode). :param hwnd: Native window handle, typically ``wx.Window.GetHandle()``. :raises RuntimeError: If ``Wintab32.dll`` is not found or the tablet context cannot be opened (driver absent, no tablet connected, etc.). .. py:attribute:: _MAX_PACKETS :value: 32 .. py:attribute:: _hctx :type: Optional[int] :value: None .. py:attribute:: _enabled :type: bool :value: False .. py:attribute:: _pressure :type: float :value: 1.0 .. py:attribute:: _pressure_max :type: int :value: 1023 .. py:method:: _bind_functions() -> None Set argtypes/restype on the WinTab functions we use. .. py:method:: _open_context(hwnd: int) -> None .. py:method:: enable() -> None Enable the WinTab context so it starts delivering packets. Called via ``wx.CallAfter`` from ``_init_wintab_context`` so that activation happens after the wx event loop has started, avoiding the Wacom driver heap-corruption bug triggered during app initialisation. .. py:method:: get_pressure() -> float Drain the WinTab packet queue and return the latest pressure. Returns a float in ``[0.0, 1.0]``. Returns the last known value when no new packets are available, and ``1.0`` if the context is closed. .. py:method:: close() -> None Close the WinTab context and release the DLL handle.