summaryrefslogtreecommitdiff
path: root/tests/cocoa/test_keyboard.m
diff options
context:
space:
mode:
authorBerke Güzel <wenekar1@gmail.com>2026-10-12 22:12:02 +0300
committerBerke Güzel <wenekar1@gmail.com>2026-10-12 22:12:02 +0300
commit94c5e361fbb229b0cd6853e2102a7d95f1f358b3 (patch)
tree3c0f11af9dcb84dac8067a31a6979acd6dd56fbf /tests/cocoa/test_keyboard.m
parent08dc9047098d6d96791024ac7d8f5837633673ef (diff)
better public interface and doxygen
Diffstat (limited to 'tests/cocoa/test_keyboard.m')
-rw-r--r--tests/cocoa/test_keyboard.m134
1 files changed, 134 insertions, 0 deletions
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 <AppKit/AppKit.h>
+#include <yasl/native.h>
+#include <assert.h>
+#include <math.h>
+#include <string.h>
+
+/* 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<NSTextInputClient> *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;
+}