#import #include #include /* A strict event double catches querying tablet-only properties on ordinary * mouse events, and proximity-only properties on tablet point events. */ @interface TabletSample : NSObject @property NSEventType type; @property NSEventSubtype subtype; @property NSEventModifierFlags modifierFlags; @property NSPoint locationInWindow; @property NSInteger buttonNumber; @property NSUInteger buttonMask; @property(getter=isEnteringProximity) BOOL enteringProximity; @property NSPointingDeviceType tool; @property float samplePressure; @property NSPoint sampleTilt; @end @implementation TabletSample - (float)pressure { assert(self.type == NSEventTypeTabletPoint || self.subtype == NSEventSubtypeTabletPoint); return self.samplePressure; } - (NSPoint)tilt { assert(self.type == NSEventTypeTabletPoint || self.subtype == NSEventSubtypeTabletPoint); return self.sampleTilt; } - (NSPointingDeviceType)pointingDeviceType { assert(self.type == NSEventTypeTabletProximity || self.subtype == NSEventSubtypeTabletProximity); return self.tool; } @end static struct yasl_mouse_event next(struct yasl_surface *surface) { struct yasl_input_event event; while (yasl_surface_input_poll(surface, &event)) if (event.kind == YASL_INPUT_MOUSE) return event.mouse; assert(!"Expected a pointer event"); return (struct yasl_mouse_event){0}; } int main(void) { @autoreleasepool { struct yasl_display *display = yasl_display_open(NULL, NULL); assert(display && (yasl_display_caps(display) & YASL_CAP_TABLET)); struct yasl_window_spec spec = {.title = "Tablet test", .size = {320, 240}}; struct yasl_surface *surface = yasl_surface_create_toplevel(display, &spec); assert(surface); NSWindow *window = (NSWindow *)yasl_surface_get_native_handle(surface); NSView *view = window.contentView; struct yasl_input_event event; while (yasl_surface_input_poll(surface, &event)) {} TabletSample *sample = [TabletSample new]; NSEvent *native = (NSEvent *)sample; sample.type = NSEventTypeTabletProximity; sample.enteringProximity = YES; sample.tool = NSPointingDeviceTypePen; [view tabletProximity:native]; sample.type = NSEventTypeMouseMoved; sample.subtype = NSEventSubtypeTabletPoint; sample.locationInWindow = NSMakePoint(100, 120); sample.sampleTilt = NSMakePoint(-0.5, 0.5); [view mouseMoved:native]; struct yasl_mouse_event ev = next(surface); assert(ev.device == YASL_PTR_DEV_PEN && ev.kind == YASL_PTR_MOTION && !ev.pen.pressure); assert(ev.pen.tilt_x == -45 && ev.pen.tilt_y == -45); sample.type = NSEventTypeLeftMouseDown; sample.samplePressure = 0.5; [view mouseDown:native]; ev = next(surface); assert(ev.device == YASL_PTR_DEV_PEN && ev.kind == YASL_PTR_PRESS && ev.button == 0); assert(ev.pen.pressure == 32767); struct yasl_vector2i position = ev.pos; /* Native tablet events cover stationary pressure changes. */ sample.type = NSEventTypeTabletPoint; sample.subtype = NSEventSubtypeMouseEvent; sample.buttonMask = NSEventButtonMaskPenTip; sample.samplePressure = 1.5; [view tabletPoint:native]; ev = next(surface); assert(ev.kind == YASL_PTR_MOTION && ev.pen.pressure == 65535); assert(ev.pos.x == position.x && ev.pos.y == position.y); sample.samplePressure = 0; /* Zero does not release a held tip button. */ [view tabletPoint:native]; assert(next(surface).kind == YASL_PTR_MOTION); sample.buttonMask = 0; [view tabletPoint:native]; ev = next(surface); assert(ev.kind == YASL_PTR_RELEASE && !ev.pen.pressure && ev.device == YASL_PTR_DEV_PEN); sample.type = NSEventTypeTabletProximity; sample.enteringProximity = NO; [view tabletProximity:native]; assert(next(surface).kind == YASL_PTR_LEAVE); sample.enteringProximity = YES; sample.tool = NSPointingDeviceTypeEraser; [view tabletProximity:native]; sample.type = NSEventTypeTabletPoint; sample.samplePressure = 0.75; sample.buttonMask = NSEventButtonMaskPenTip; [view tabletPoint:native]; ev = next(surface); assert(ev.device == YASL_PTR_DEV_ERASER && ev.kind == YASL_PTR_PRESS && ev.pen.pressure > 0); sample.type = NSEventTypeTabletProximity; sample.enteringProximity = NO; [view tabletProximity:native]; ev = next(surface); assert(ev.device == YASL_PTR_DEV_ERASER && ev.kind == YASL_PTR_LEAVE && !ev.pen.pressure); sample.type = NSEventTypeMouseMoved; [view mouseMoved:native]; ev = next(surface); assert(ev.device == YASL_PTR_DEV_MOUSE && !ev.pen.pressure); [sample release]; yasl_surface_destroy(surface); yasl_display_close(display); } return 0; }