Skip to content

Fix pen not activating apps and pen/eraser not switching after clicking in - #6

Merged
modfox merged 1 commit into
mainfrom
fix/pen-app-activation
Nov 4, 2026
Merged

modfox merged 1 commit into
mainfrom
fix/pen-app-activation

Conversation

@modfox

@modfox modfox commented Nov 4, 2026

Copy link
Copy Markdown
Owner

After clicking into Clip Studio Paint with the pen:

  • sometimes it wouldn't draw at all
  • sometimes it drew, but flipping to the eraser still drew

Cause

A pen tap raised Clip Studio's window but never made it the active app. A listen-only event tap showed the terminal staying frontmost through the whole pen session. Clip Studio only became active, for about 12ms, on the next trackpad click. macOS delivers tablet proximity events (which carry whether the pen tip or the eraser is in range) only to the frontmost app, so Clip Studio never received them. Qt apps look up the tool by the device ID from the last proximity event, so Clip Studio either didn't recognise the pen or kept a stale tool.

Comparing a trackpad click with a nib click field by field showed nib's events had no source state (synthetic), no event number, no hardware sender ID, and nib's PID as source. Giving them an HID-state source alone didn't let the click activate the app.

Fix

  • Activate on press (main.swift): on each tip or eraser press over a normal window (layer 0) of a non-frontmost app, nib activates that app by setting kAXFrontmostAttribute through Accessibility, with a 0.25s AX timeout. If that fails it falls back to NSRunningApplication.activate(). The menu bar, Dock, panels and overlays are left alone. This goes through EventEmitter.willPress.
  • Re-announce proximity (EventEmitter): when the frontmost app changes (NSWorkspace.didActivateApplicationNotification), nib re-sends proximity-enter with the current pointer type. It also does this when the pen end changes without a reported exit.
  • HID-state event source (EventEmitter, TouchGesture): events now carry sourceStateID = 1 like hardware input, with local event suppression disabled so the keyboard isn't muted after posting.

Testing

  • swift test: 47 tests pass. 4 new: proximity re-announce, re-announce on flip in range, willPress fires once per press, HID source state.
  • Checked on the Cintiq Pro 24 with a listen-only event tap: a pen tap from the terminal makes Clip Studio frontmost before the press arrives, then pen draws, eraser erases, and pen draws again.

🤖 Generated with Claude Code

Clicking into a background app with the pen raised its window but never
made it the active app. macOS only delivers tablet proximity events to
the frontmost app, so the app never learned the pointer type: it either
ignored pen input or kept a stale tool (the eraser end still drew).

- On each tip/eraser press over a normal window of a non-frontmost app,
  activate that app via Accessibility (kAXFrontmostAttribute), falling
  back to NSRunningApplication.activate(). Synthesized clicks raise the
  window but macOS does not let them activate the app.
- Re-send proximity-enter with the current pointer type when the
  frontmost app changes, and when the pen end changes without a reported
  exit.
- Create all events from an HID-system-state CGEventSource (with local
  event suppression disabled) so they are tagged like hardware input
  rather than as synthetic session events.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@modfox
modfox merged commit 5fc1ddc into main Nov 4, 2026
1 check passed
@modfox
modfox deleted the fix/pen-app-activation branch November 4, 2026 22:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant