diff --git a/driver/Sources/NibCore/EventEmitter.swift b/driver/Sources/NibCore/EventEmitter.swift index d2a80f9..5d5ad05 100644 --- a/driver/Sources/NibCore/EventEmitter.swift +++ b/driver/Sources/NibCore/EventEmitter.swift @@ -136,12 +136,14 @@ public final class EventEmitter { private func postPointer(_ s: PenSample) { let pt = mapping.point(x: s.x, y: s.y) + // Contact: the eraser end reports touch via the Eraser bit, not Tip Switch. + let contact = s.tipDown || s.eraser let type: CGEventType - if s.tipDown && !wasTipDown { type = .leftMouseDown } - else if !s.tipDown && wasTipDown { type = .leftMouseUp } - else if s.tipDown { type = .leftMouseDragged } + if contact && !wasTipDown { type = .leftMouseDown } + else if !contact && wasTipDown { type = .leftMouseUp } + else if contact { type = .leftMouseDragged } else { type = .mouseMoved } - wasTipDown = s.tipDown + wasTipDown = contact if type == .leftMouseDown { tipClickState = tipClicks.down(at: pt, time: now()) } guard let e = CGEvent(mouseEventSource: nil, mouseType: type, @@ -167,7 +169,7 @@ public final class EventEmitter { e.setIntegerValueField(.tabletEventDeviceID, value: Int64(deviceID)) // Button mask: bit0 tip, bit1 barrel, bit2 secondary barrel. var buttons: Int64 = 0 - if s.tipDown { buttons |= 0x1 } + if contact { buttons |= 0x1 } if s.barrelButton { buttons |= 0x2 } if s.secondaryBarrel { buttons |= 0x4 } e.setIntegerValueField(.tabletEventPointButtons, value: buttons) diff --git a/driver/Tests/NibCoreTests/EventEmitterTests.swift b/driver/Tests/NibCoreTests/EventEmitterTests.swift index c3b6e25..7f04b38 100644 --- a/driver/Tests/NibCoreTests/EventEmitterTests.swift +++ b/driver/Tests/NibCoreTests/EventEmitterTests.swift @@ -14,6 +14,22 @@ final class EventEmitterTests: XCTestCase { sink: sink) } + func testEraserContactIsAClick() { + let sink = RecordingSink(), em = makeEmitter(sink) + var s = sample(); s.inverted = true + em.handle(s) // eraser hovering + var down = s; down.eraser = true; down.pressure = 3000 + em.handle(down); em.handle(down) // eraser pressed (Tip bit stays 0) + em.handle(s) // lifted + XCTAssertEqual(sink.clicks.map { $0.type }, [.leftMouseDown, .leftMouseUp]) + XCTAssertTrue(sink.types.contains(.leftMouseDragged)) + let prox = sink.events.first { $0.type == .tabletProximity }! + XCTAssertEqual(prox.getIntegerValueField(.tabletProximityEventPointerType), 3) + let press = sink.events.first { $0.type == .leftMouseDown }! + XCTAssertGreaterThan(press.getDoubleValueField(.tabletEventPointPressure), 0) + XCTAssertEqual(press.getIntegerValueField(.tabletEventPointButtons) & 0x1, 1) + } + func testLeavingProximityWithTipDownReleasesTip() { let sink = RecordingSink(), em = makeEmitter(sink) em.handle(sample(tip: true))