From 537b2d768b31deb0f95c5122e0d562e4406ae9a0 Mon Sep 17 00:00:00 2001 From: Berke Güzel Date: Tue, 13 Oct 2026 15:41:39 +0300 Subject: Unify core and runner events into struct yasl_event The core input queue and the yasl_run() runner each had their own event type, and the runner translated one into the other. Both now share struct yasl_event in : yasl_surface_poll_event() returns the same events the app event callback receives, so the runner forwards them unchanged. Pointer input becomes POINTER_DOWN/UP/MOTION/SCROLL/LEAVE with a named yasl_pointer_button and a motion delta computed in the input queue. TEXT, PASTE and DROP share one text payload, scale changes fold into WINDOW_RESIZE, and every event carries a monotonic time_ns. yasl_surface_set_mouse_mode() is replaced by yasl_surface_set_pointer_mode(); no backend implements relative mode yet. The export check now only counts YASL_API declarations, so function pointer fields returning enum yasl_app_result are not mistaken for exports. Co-Authored-By: Claude Opus 5.5 --- include/yasl/app.h | 125 ++----------------------------- include/yasl/keycodes.h | 2 +- include/yasl/yasl.h | 193 ++++++++++++++++++++++++++++-------------------- 3 files changed, 117 insertions(+), 203 deletions(-) (limited to 'include') diff --git a/include/yasl/app.h b/include/yasl/app.h index 112140d..f067d5b 100644 --- a/include/yasl/app.h +++ b/include/yasl/app.h @@ -41,114 +41,6 @@ typedef enum yasl_pacing_mode { YASL_PACING_CONTINUOUS, } yasl_pacing_mode; -/** Mouse capture and virtualization modes. */ -typedef enum yasl_mouse_mode { - YASL_MOUSE_NORMAL = 0, /**< Standard visible pointer. */ - YASL_MOUSE_HIDDEN, /**< Hidden cursor, normal bounded window coordinates. */ - YASL_MOUSE_RELATIVE, /**< Relative pointer lock: cursor hidden, unbounded deltas. */ -} yasl_mouse_mode; - -/** Unified event types delivered to the application event callback. */ -typedef enum yasl_event_type { - YASL_EVENT_NONE = 0, - - /* Input events */ - YASL_EVENT_KEY, - YASL_EVENT_TEXT, - YASL_EVENT_MOUSE_BUTTON, - YASL_EVENT_MOUSE_MOTION, - YASL_EVENT_MOUSE_SCROLL, - YASL_EVENT_MOUSE_LEAVE, - - /* Window lifecycle events */ - YASL_EVENT_WINDOW_RESIZE, - YASL_EVENT_WINDOW_SCALE_CHANGED, - YASL_EVENT_WINDOW_CLOSE_REQUEST, - YASL_EVENT_WINDOW_FOCUS, - - /* System & external events */ - YASL_EVENT_PASTE, - YASL_EVENT_DROP_FILES, - YASL_EVENT_USER, - YASL_EVENT_INPUT_RESET, /**< Input interrupted; clear held keys/buttons and composition. */ -} yasl_event_type; - -/** Unified event payload delivered to yasl_app_desc.event(). */ -struct yasl_event { - struct yasl_surface *surface; /**< Associated surface, or NULL for display-wide events. */ - yasl_event_type type; - - union { - struct { - enum yasl_key key; - enum yasl_key_action action; - uint32_t mods; - uint32_t codepoint; - uint32_t shifted; - uint32_t native_code; - bool repeat; /**< true if this press is generated by OS autorepeat. */ - } key; - - struct { - const char *text; /**< UTF-8 text string; borrowed for callback duration. */ - size_t len; /**< Length in bytes excluding terminating NUL. */ - } text; - - struct { - struct yasl_vector2i pos; /**< Device-pixel position relative to surface. */ - enum yasl_pointer_device device; /**< Mouse, touch, pen, or eraser. */ - int16_t button; /**< 0 primary, 1 middle, 2 secondary. */ - bool pressed; /**< true for press, false for release. */ - uint32_t mods; - struct yasl_pointer_pen pen; - } mouse_button; - - struct { - struct yasl_vector2i pos; /**< Device-pixel position relative to surface. */ - struct yasl_vector2i delta; /**< Relative motion delta (dx, dy). */ - enum yasl_pointer_device device; /**< Mouse, touch, pen, or eraser. */ - uint32_t mods; - struct yasl_pointer_pen pen; - } mouse_motion; - - struct { - struct yasl_vector2i pos; - struct yasl_vector2d scroll; /**< Fractional line units; positive right/down. */ - uint32_t mods; - } mouse_scroll; - - struct { - struct yasl_vector2i size; /**< Configured content extent in device pixels. */ - uint32_t scale_120; - } resize; - - struct { - uint32_t scale_120; - struct yasl_vector2i size; - } scale; - - struct { - bool focused; - } focus; - - struct { - const char *text; /**< UTF-8 text from clipboard. */ - size_t len; - } paste; - - struct { - const char *files; /**< NUL-terminated text/uri-list. */ - size_t len; - } drop_files; - - struct { - uint32_t type; /**< Application-defined message type. */ - void *payload; /**< User-defined payload pointer. */ - size_t size; /**< Optional payload size. */ - } user; - }; -}; - /** Frame context provided to yasl_app_desc.frame() during presentation. */ struct yasl_frame_context { struct yasl_surface *surface; @@ -198,25 +90,18 @@ YASL_API void yasl_surface_set_pacing(struct yasl_surface *s, yasl_pacing_mode m */ YASL_API void yasl_surface_request_frame(struct yasl_surface *s); -/** - * Configure mouse pointer capture / virtualization mode. - * @param s Surface. - * @param mode Normal, hidden, or relative pointer lock. - */ -YASL_API void yasl_surface_set_mouse_mode(struct yasl_surface *s, yasl_mouse_mode mode); - /** * Safely post a custom user event to the main event loop from ANY thread. * Wakes the display loop and delivers YASL_EVENT_USER to the event callback. * @param d Display. * @param s Optional target surface, or NULL. - * @param user_type Application-defined message type. + * @param code Application-defined message code (yasl_user_event.code). * @param payload Arbitrary pointer passed through to the event. * @param size Optional payload size. * @return true if queued successfully, false if queue is full or memory failed. */ YASL_API bool yasl_post_event(struct yasl_display *d, struct yasl_surface *s, - uint32_t user_type, void *payload, size_t size); + uint32_t code, void *payload, size_t size); /** * Watch an open file descriptor or socket for poll-style readiness in the main loop. @@ -269,15 +154,15 @@ struct yasl_app_desc { * Use this to create windows and initialize application resources. * Return YASL_APP_CONTINUE or YASL_APP_QUIT. */ - int (*init)(void *ud, struct yasl_display *d); + enum yasl_app_result (*init)(void *ud, struct yasl_display *d); /** - * Unified event handler called for input, resize, close, scale, and custom events. + * Unified event handler for input, window and user events, in arrival order. * Event payloads and borrowed strings are valid for the duration of the callback. * INPUT_RESET has no payload and requires clearing held application input. * Return YASL_APP_CONTINUE or YASL_APP_QUIT. */ - int (*event)(void *ud, const struct yasl_event *ev); + enum yasl_app_result (*event)(void *ud, const struct yasl_event *ev); /** * Invoked when a surface needs to present a frame. diff --git a/include/yasl/keycodes.h b/include/yasl/keycodes.h index 7586945..d34aeae 100644 --- a/include/yasl/keycodes.h +++ b/include/yasl/keycodes.h @@ -2,7 +2,7 @@ * @file * Portable physical keyboard identities, included by yasl/yasl.h. * Letter/punctuation names describe positions on a US keyboard, regardless of - * active layout or modifiers. Use YASL_INPUT_TEXT for text and codepoint/shifted + * active layout or modifiers. Use YASL_EVENT_TEXT for text and codepoint/shifted * in yasl_key_event for layout labels. These values are neither Unicode nor * native scancodes; do not derive a character from a key enumerator. */ diff --git a/include/yasl/yasl.h b/include/yasl/yasl.h index 3b3b712..22ed308 100644 --- a/include/yasl/yasl.h +++ b/include/yasl/yasl.h @@ -282,15 +282,6 @@ enum yasl_mod : uint32_t { YASL_MOD_CAPS = 1 << 4, /**< Caps Lock modifier. */ }; -/** Pointer transition or motion type; fields are meaningful according to this tag. */ -enum yasl_pointer_kind { - YASL_PTR_PRESS, /**< Button/tip pressed. */ - YASL_PTR_RELEASE, /**< Button/tip released. */ - YASL_PTR_MOTION, /**< Position or tablet axes changed. */ - YASL_PTR_LEAVE, /**< Pointer/tool left the surface. */ - YASL_PTR_SCROLL, /**< Scroll sample. */ -}; - /** Pointer source class; capability support does not imply an attached device. */ enum yasl_pointer_device { YASL_PTR_DEV_MOUSE, /**< Mouse or trackpad pointer. */ @@ -299,6 +290,24 @@ enum yasl_pointer_device { YASL_PTR_DEV_ERASER, /**< Tablet eraser tool. */ }; +/** Pointer button; meaningful only for POINTER_DOWN and POINTER_UP. */ +enum yasl_pointer_button { + YASL_BUTTON_PRIMARY = 0, /**< Left button, pen tip, or touch contact. */ + YASL_BUTTON_MIDDLE = 1, /**< Middle button / wheel click. */ + YASL_BUTTON_SECONDARY = 2, /**< Right button or pen barrel button. */ + YASL_BUTTON_BACK = 3, /**< Side "back" button. */ + YASL_BUTTON_FORWARD = 4, /**< Side "forward" button. */ +}; + +/** Pointer capture mode for a surface. */ +enum yasl_pointer_mode { + YASL_POINTER_NORMAL = 0, /**< Absolute positions; cursor per yasl_surface_set_cursor(). */ + /** Cursor hidden and locked in place while the surface has focus. POINTER_MOTION + * reports unbounded relative motion in delta; pos stays at the lock position. + * The lock is released on focus loss and re-acquired on focus gain. */ + YASL_POINTER_RELATIVE, +}; + /** Normalized tablet axes; zero for unavailable axes and non-tablet devices. */ struct yasl_pointer_pen { /** 0..65535 normalized to device range. Zero alone does not end contact. */ @@ -309,13 +318,36 @@ struct yasl_pointer_pen { int8_t tilt_y; }; +/** Event tag. Each tag lists the union member it selects. */ +enum yasl_event_type { + YASL_EVENT_NONE = 0, + + /* Input: produced by backends, returned by yasl_surface_poll_event(). */ + YASL_EVENT_KEY, /**< .key */ + YASL_EVENT_TEXT, /**< .text — committed UTF-8; insert this, not key codepoints. */ + YASL_EVENT_POINTER_DOWN, /**< .pointer — button/tip pressed; button valid. */ + YASL_EVENT_POINTER_UP, /**< .pointer — button/tip released; button valid. */ + YASL_EVENT_POINTER_MOTION, /**< .pointer — position, relative motion, or pen axes changed. */ + YASL_EVENT_POINTER_SCROLL, /**< .pointer — scroll valid. */ + YASL_EVENT_POINTER_LEAVE, /**< .pointer — last known pos/device; cancel hover state. */ + YASL_EVENT_FOCUS, /**< .focus — keyboard focus changed; cancel held state on loss. */ + YASL_EVENT_PASTE, /**< .text — UTF-8 from yasl_display_paste(). */ + YASL_EVENT_DROP, /**< .text — dropped text/uri-list: CRLF-separated file URLs, not paths. */ + YASL_EVENT_INPUT_RESET, /**< No payload. Input stream interrupted; clear held keys, buttons, strokes, IME. */ + + /* Window and application: delivered only through yasl_app_desc.event(). + * Low-level users receive the same information via yasl_window_cbs. */ + YASL_EVENT_WINDOW_RESIZE, /**< .resize — size and/or scale changed; reallocate and redraw. */ + YASL_EVENT_WINDOW_CLOSE, /**< No payload. User asked to close the window. */ + YASL_EVENT_USER, /**< .user — posted with yasl_post_event(). */ +}; + /** Physical keyboard transition with optional layout labels. * key is independent of modifiers/layout and stable between press and release. * codepoint and shifted are optional single Unicode scalars for the current * layout at levels zero/one, not text input. Zero means unavailable, a control - * key, or a layout mapping that produces multiple characters. Native scancodes - * are backend-specific. Insert committed YASL_INPUT_TEXT into documents. - */ + * key, or a layout mapping that produces multiple characters. Insert committed + * YASL_EVENT_TEXT into documents instead. */ struct yasl_key_event { /** Portable physical key; YASL_KEY_UNKNOWN when unmapped. */ enum yasl_key key; @@ -331,89 +363,75 @@ struct yasl_key_event { uint32_t native_code; }; -/** Pointer sample. Pen and eraser events share this structure with mouse input. -Track contact with primary press/release, not pressure alone. Leave, focus loss, -and YASL_INPUT_RESET must cancel held application input state. This is not a -multi-contact touch API. Scroll offsets use fractional line units: positive x -means right and positive y means down, after system scroll preferences. */ -struct yasl_mouse_event { - /** Surface-relative device-pixel position. */ +/** Pointer sample shared by all POINTER_* events. Pen and eraser share it with + * mouse input. Track contact with DOWN/UP of the primary button, not pressure. + * This is not a multi-contact touch API. */ +struct yasl_pointer_event { + /** Surface-relative device-pixel position. Frozen while YASL_POINTER_RELATIVE is locked. */ struct yasl_vector2i pos; - /** Press/release: 0 primary/tip, 1 middle, 2 secondary. Unused for scroll. */ - int16_t button; - /** Sample type. */ - enum yasl_pointer_kind kind; + /** MOTION: device-pixel movement since the previous sample on this surface. + * Unbounded under YASL_POINTER_RELATIVE; zero after enter, leave, or reset. */ + struct yasl_vector2d delta; + /** SCROLL: fractional line offsets after system preferences; positive right/down. */ + struct yasl_vector2d scroll; + /** DOWN/UP: which button changed. */ + enum yasl_pointer_button button; /** Mouse, touch, pen, or eraser. */ enum yasl_pointer_device device; /** yasl_mod bitmask at this event. */ uint32_t mods; - /** Fractional line offsets, valid for SCROLL only; positive right/down. */ - struct yasl_vector2d scroll; - /** Current tablet axes, including on pressure-only motion; missing axes are zero. */ struct yasl_pointer_pen pen; }; -/** Input union tag. RESET has no payload and requires clearing held state. */ -enum yasl_input_kind { - YASL_INPUT_KEY, /**< key member. */ - YASL_INPUT_MOUSE, /**< mouse member. */ - YASL_INPUT_FOCUS, /**< focus member. */ - YASL_INPUT_PASTE, /**< paste member. */ - YASL_INPUT_DROP_FILES, /**< drop_files member. */ - YASL_INPUT_TEXT, /**< text member, containing committed UTF-8. */ - /* The input stream was interrupted (e.g. allocation failure or device - * removal). Clear held keys/buttons and composition state. */ - YASL_INPUT_RESET, /**< No payload. Clear held keys/buttons and composition after an interruption. */ +/** Borrowed NUL-terminated UTF-8, shared by TEXT, PASTE and DROP. */ +struct yasl_text_event { + /** Borrowed NUL-terminated bytes; see yasl_surface_poll_event() for lifetime. */ + const char *data; + /** Length in bytes excluding the terminating NUL. */ + size_t len; }; -/** Keyboard focus transition; cancel held state when focus is lost. */ +/** Keyboard focus transition. */ struct yasl_focus_event { /** true on focus gain, false on loss. */ bool focused; }; -/** Committed UTF-8 text; insert this instead of deriving characters from key events. */ -struct yasl_text_event { - /** Borrowed NUL-terminated UTF-8. */ - const char *text; - /** Length in bytes excluding the terminating NUL. */ - size_t len; +/** New configured geometry for a surface. */ +struct yasl_resize_event { + /** Content size in device pixels and display scale. */ + struct yasl_geometry geometry; + /** true when scale_120 differs from the previous resize of this surface. */ + bool scale_changed; }; -/** UTF-8 text received from an explicit selection request. */ -struct yasl_paste_event { - /** Borrowed NUL-terminated UTF-8. */ - const char *text; - /** Length in bytes excluding the terminating NUL. */ - size_t len; +/** Application message posted with yasl_post_event(). */ +struct yasl_user_event { + /** Application-defined message code. */ + uint32_t code; + /** Pointer passed through unchanged; ownership stays with the application. */ + void *payload; + /** Optional payload size, passed through unchanged. */ + size_t size; }; -/** File URLs in text/uri-list form, separated by CRLF; not filesystem paths. */ -struct yasl_drop_files_event { - /** Borrowed NUL-terminated text/uri-list; parse URLs and percent escapes. */ - const char *files; - /** Length in bytes excluding the terminating NUL. */ - size_t len; -}; - -/** One tagged input event; read only the union member selected by kind. -Payload strings follow yasl_surface_input_poll() lifetime rules. RESET carries -no union payload; clear keys, buttons, strokes, and composition state. */ -struct yasl_input_event { - /** Recipient; can differ from the polled surface for routed popup input. */ - struct yasl_surface *surface; +/** One tagged event; read only the union member selected by type. */ +struct yasl_event { /** Selects the valid union member. */ - enum yasl_input_kind kind; - /** Reserved for YASL; applications must not interpret it. */ - uint32_t reserved; + enum yasl_event_type type; + /** Recipient surface, or NULL for display-wide events. Can differ from the + * polled surface for routed popup input. */ + struct yasl_surface *surface; + /** Monotonic timestamp in nanoseconds, same clock as yasl_loop_now_ns(). */ + uint64_t time_ns; union { - struct yasl_key_event key; /**< Keyboard payload. */ - struct yasl_mouse_event mouse; /**< Pointer payload. */ - struct yasl_focus_event focus; /**< Focus payload. */ - struct yasl_text_event text; /**< Committed text payload. */ - struct yasl_paste_event paste; /**< Selection text payload. */ - struct yasl_drop_files_event drop_files; /**< File URL list payload. */ + struct yasl_key_event key; /**< KEY */ + struct yasl_pointer_event pointer; /**< POINTER_* */ + struct yasl_text_event text; /**< TEXT, PASTE, DROP */ + struct yasl_focus_event focus; /**< FOCUS */ + struct yasl_resize_event resize; /**< WINDOW_RESIZE */ + struct yasl_user_event user; /**< USER */ }; }; @@ -556,7 +574,7 @@ YASL_API void yasl_display_copy(struct yasl_display *d, enum yasl_selection sel, * @param d Display that owns target. * @param sel YASL_CLIPBOARD or YASL_PRIMARY. * @param target Destination surface; NULL or a surface on another display does nothing. - * Results arrive as YASL_INPUT_PASTE, possibly during a later dispatch. No result + * Results arrive as YASL_EVENT_PASTE, possibly during a later dispatch. No result * is promised for unavailable data or a failed transfer. Destroying target cancels * delivery. Unsupported selections do nothing. */ @@ -722,18 +740,29 @@ YASL_API bool yasl_surface_present(struct yasl_surface *s, const struct yasl_fra * the next SUCCESSFUL poll on this surface or surface destruction. Dispatch, * flush and unsuccessful polls do not invalidate them. Copy to keep longer. */ /** - * Remove one event from a surface's input queue without waiting. + * Remove one input event from a surface's queue without waiting. * @param s Surface whose queue to drain. * @param ev Required output event; unchanged when no event is available. * @return true for an event, false for an empty queue or NULL arguments. - * Dispatch receives native input; polling only drains the queue. Read the union - * member selected by kind. Payload strings are borrowed, NUL-terminated, and - * valid until the next successful poll on this queue or its destruction; dispatch, - * flush, and unsuccessful polls do not invalidate them. On Wayland, popup pointer - * and keyboard input can be routed through the root parent's queue; inspect + * Dispatch receives native input; polling only drains the queue. Only input + * types (KEY through INPUT_RESET) are returned. Read the union member selected + * by type. Payload strings are borrowed, NUL-terminated, and valid until the + * next successful poll on this queue or its destruction; dispatch, flush, and + * unsuccessful polls do not invalidate them. On Wayland, popup pointer and + * keyboard input can be routed through the root parent's queue; inspect * ev->surface to identify the receiving surface. */ -YASL_API bool yasl_surface_input_poll(struct yasl_surface *s, struct yasl_input_event *ev); +YASL_API bool yasl_surface_poll_event(struct yasl_surface *s, struct yasl_event *ev); +/** + * Select absolute or relative (locked) pointer input for a surface. + * @param s Surface. + * @param mode YASL_POINTER_NORMAL or YASL_POINTER_RELATIVE. + * @return true if the mode is supported by the backend; false leaves NORMAL. + * RELATIVE hides the cursor and locks it while the surface is focused; + * POINTER_MOTION then carries unbounded delta. Returning to NORMAL restores + * the cursor selected with yasl_surface_set_cursor(). + */ +YASL_API bool yasl_surface_set_pointer_mode(struct yasl_surface *s, enum yasl_pointer_mode mode); /* Current device-pixel size and scale, matching the configure callback. */ /** @@ -794,7 +823,7 @@ YASL_API void yasl_surface_set_background_color(struct yasl_surface *s, uint32_t * @param s Surface, or NULL. * @return Borrowed NUL-terminated text, or NULL if absent/unsupported. * Copy to retain across the next dispatch or surface destruction. Composition - * changes can schedule a redraw. Insert committed YASL_INPUT_TEXT into documents, + * changes can schedule a redraw. Insert committed YASL_EVENT_TEXT into documents, * not preedit text. */ YASL_API const char *yasl_surface_ime_preedit(const struct yasl_surface *s); -- cgit v1.2.3