From 94c5e361fbb229b0cd6853e2102a7d95f1f358b3 Mon Sep 17 00:00:00 2001 From: Berke Güzel Date: Mon, 12 Oct 2026 22:12:02 +0300 Subject: better public interface and doxygen --- tests/cocoa/test_keyboard.m | 134 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 tests/cocoa/test_keyboard.m (limited to 'tests/cocoa/test_keyboard.m') diff --git a/tests/cocoa/test_keyboard.m b/tests/cocoa/test_keyboard.m new file mode 100644 index 0000000..4854065 --- /dev/null +++ b/tests/cocoa/test_keyboard.m @@ -0,0 +1,134 @@ +#import +#include +#include +#include +#include + +/* Reject character queries on modifier-only events, as AppKit does. */ +@interface InputSample : NSObject +@property NSEventType type; +@property unsigned short keyCode; +@property NSEventModifierFlags modifierFlags; +@property(copy) NSString *label; +@property(copy) NSString *shiftedLabel; +@property NSPoint locationInWindow; +@property CGFloat scrollingDeltaX; +@property CGFloat scrollingDeltaY; +@property BOOL hasPreciseScrollingDeltas; +@end + +@implementation InputSample +- (NSString *)charactersByApplyingModifiers:(NSEventModifierFlags)modifiers +{ + assert(self.type == NSEventTypeKeyDown || self.type == NSEventTypeKeyUp); + return modifiers & NSEventModifierFlagShift ? self.shiftedLabel : self.label; +} +- (void)dealloc +{ + [_label release]; + [_shiftedLabel release]; + [super dealloc]; +} +@end + +static struct yasl_input_event next(struct yasl_surface *surface, enum yasl_input_kind kind) +{ + struct yasl_input_event event; + assert(yasl_surface_input_poll(surface, &event)); + assert(event.kind == kind && event.surface == surface); + return event; +} + +static void empty(struct yasl_surface *surface) +{ + struct yasl_input_event event; + assert(!yasl_surface_input_poll(surface, &event)); +} + +int main(void) +{ + @autoreleasepool { + struct yasl_display *display = yasl_display_open(NULL, NULL); + assert(display); + struct yasl_surface_spec spec = {.title = "Keyboard 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 = (id)window.contentView; + struct yasl_input_event event; + while (yasl_surface_input_poll(surface, &event)) {} + + InputSample *sample = [InputSample new]; + NSEvent *native = (NSEvent *)sample; + sample.type = NSEventTypeKeyUp; + sample.keyCode = 0; /* US A, even with a different active layout. */ + sample.label = @"q"; + sample.shiftedLabel = @"Q"; + [view keyUp:native]; + event = next(surface, YASL_INPUT_KEY); + assert(event.key.key == YASL_KEY_A && event.key.native_code == 0); + assert(event.key.action == YASL_KEY_RELEASE); + assert(event.key.codepoint == 'q' && event.key.shifted == 'Q'); + empty(surface); + sample.label = @"😀"; /* One scalar, two UTF-16 units. */ + sample.shiftedLabel = @"ab"; + [view keyUp:native]; + event = next(surface, YASL_INPUT_KEY); + assert(event.key.codepoint == 0x1f600 && event.key.shifted == 0); + sample.type = NSEventTypeFlagsChanged; + sample.keyCode = 56; /* Left Shift. */ + sample.modifierFlags = NSEventModifierFlagShift | 0x0002; + [view flagsChanged:native]; + event = next(surface, YASL_INPUT_KEY); + assert(event.key.key == YASL_KEY_LEFT_SHIFT && event.key.action == YASL_KEY_PRESS); + assert(event.key.mods == YASL_MOD_SHIFT && !event.key.codepoint && !event.key.shifted); + sample.modifierFlags = 0; + [view flagsChanged:native]; + assert(next(surface, YASL_INPUT_KEY).key.action == YASL_KEY_RELEASE); + + /* Native text services own preedit and commits. Marked text is not an + * insertion, and commits retain all UTF-8 bytes, including non-BMP. */ + [view setMarkedText:@"é" selectedRange:NSMakeRange(1, 0) + replacementRange:NSMakeRange(NSNotFound, 0)]; + assert(strcmp(yasl_surface_ime_preedit(surface), "é") == 0); + empty(surface); + [view insertText:@"😀é" replacementRange:NSMakeRange(NSNotFound, 0)]; + event = next(surface, YASL_INPUT_TEXT); + assert(event.text.len == strlen("😀é") && strcmp(event.text.text, "😀é") == 0); + assert(!yasl_surface_ime_preedit(surface)); + empty(surface); + + /* Exercise the keyDown -> interpretKeyEvents -> insertText route with + * an actual AppKit key event rather than the strict event double. */ + NSEvent *press = [NSEvent keyEventWithType:NSEventTypeKeyDown location:NSZeroPoint + modifierFlags:0 timestamp:0 windowNumber:window.windowNumber context:nil + characters:@"a" charactersIgnoringModifiers:@"a" isARepeat:NO keyCode:0]; + [view keyDown:press]; + assert(next(surface, YASL_INPUT_KEY).key.key == YASL_KEY_A); + event = next(surface, YASL_INPUT_TEXT); + assert(event.text.len == 1 && event.text.text[0] == 'a'); + empty(surface); + + sample.type = NSEventTypeScrollWheel; + sample.hasPreciseScrollingDeltas = YES; + sample.scrollingDeltaX = -2.5; + sample.scrollingDeltaY = 1.25; + [view scrollWheel:native]; + event = next(surface, YASL_INPUT_MOUSE); + assert(event.mouse.kind == YASL_PTR_SCROLL); + assert(event.mouse.scroll.x == 0.25 && event.mouse.scroll.y == -0.125); + sample.hasPreciseScrollingDeltas = NO; + sample.scrollingDeltaX = 1; + sample.scrollingDeltaY = -1; + [view scrollWheel:native]; + event = next(surface, YASL_INPUT_MOUSE); + assert(event.mouse.scroll.x == -1 && event.mouse.scroll.y == 1); + sample.scrollingDeltaX = NAN; + [view scrollWheel:native]; + empty(surface); + [sample release]; + yasl_surface_destroy(surface); + yasl_display_close(display); + } + return 0; +} -- cgit v1.2.3