diff --git a/meson.build b/meson.build index 0e5270cb..503a3c05 100644 --- a/meson.build +++ b/meson.build @@ -286,7 +286,7 @@ sources = [] src += [ 'anim.c', 'config.c', 'datastream.c','font.c','HandmadeMath.c','jsffi.c','model.c', 'render.c','simplex.c','spline.c', 'transform.c','cell.c', 'wildmatch.c', - 'sprite.c', 'rtree.c', 'qjs_nota.c', 'qjs_soloud.c', 'qjs_sdl.c', 'qjs_sdl_video.c', 'qjs_sdl_surface.c', 'qjs_math.c', 'qjs_geometry.c', 'qjs_transform.c', 'qjs_sprite.c', 'qjs_io.c', 'qjs_fd.c', 'qjs_os.c', 'qjs_actor.c', + 'sprite.c', 'rtree.c', 'qjs_nota.c', 'qjs_soloud.c', 'qjs_sdl.c', 'qjs_sdl_input.c', 'qjs_sdl_video.c', 'qjs_sdl_surface.c', 'qjs_math.c', 'qjs_geometry.c', 'qjs_transform.c', 'qjs_sprite.c', 'qjs_io.c', 'qjs_fd.c', 'qjs_os.c', 'qjs_actor.c', 'qjs_qr.c', 'qjs_wota.c', 'monocypher.c', 'qjs_blob.c', 'qjs_crypto.c', 'qjs_time.c', 'qjs_http.c', 'qjs_rtree.c', 'qjs_spline.c', 'qjs_js.c', 'qjs_debug.c', 'picohttpparser.c', 'qjs_miniz.c' ] # quirc src diff --git a/source/cell.c b/source/cell.c index 407d51a2..92c387dc 100644 --- a/source/cell.c +++ b/source/cell.c @@ -53,12 +53,6 @@ static unsigned char *zip_buffer_global = NULL; static char *prosperon = NULL; cell_rt *root_cell = NULL; -/* Event watch subscribers */ -char **event_watchers = NULL; -SDL_Mutex *event_watchers_mutex = NULL; - -static Uint32 queue_event; - static SDL_AtomicInt engine_shutdown; static SDL_Thread **runners = NULL; @@ -73,6 +67,7 @@ static inline uint64_t now_ns() return SDL_GetTicksNS(); } +// Add a message into each actor's event queue for expired timers static void process_due_timers(void) { uint64_t tnow = now_ns(); @@ -203,7 +198,7 @@ void actor_free(cell_rt *actor) // Do not go forward with actor destruction until the actor is completely free SDL_LockMutex(actor->mutex); SDL_LockMutex(actor->msg_mutex); - SDL_LockMutex(actor->turn); + SDL_LockMutex(actor->mutex); JSContext *js = actor->context; @@ -256,8 +251,8 @@ void actor_free(cell_rt *actor) SDL_DestroyMutex(actor->mutex); SDL_UnlockMutex(actor->msg_mutex); SDL_DestroyMutex(actor->msg_mutex); - SDL_UnlockMutex(actor->turn); - SDL_DestroyMutex(actor->turn); + SDL_UnlockMutex(actor->mutex); + SDL_DestroyMutex(actor->mutex); free(actor); @@ -266,11 +261,13 @@ void actor_free(cell_rt *actor) // exit_handler(); } -static Uint32 actor_remove_cb(cell_rt *actor, Uint32 id, Uint32 interval) +JSValue js_actor_remove_cb(JSContext *js, JSValue this_val, int argc, JSValue *argv) { + cell_rt *actor = JS_GetContextOpaque(js); + if (actor->need_stop) { actor_free(actor); - return 0; + return JS_UNDEFINED; } if (JS_IsUndefined(actor->unneeded)) @@ -282,7 +279,7 @@ static Uint32 actor_remove_cb(cell_rt *actor, Uint32 id, Uint32 interval) SDL_UnlockMutex(actor->mutex); actor_free(actor); } - return 0; + return JS_UNDEFINED; } void js_dofree(JSRuntime *rt, void *opaque, void *ptr) @@ -446,7 +443,6 @@ cell_rt *create_actor(void *wota) actor->mutex = SDL_CreateMutex(); /* Protects JSContext + state */ actor->msg_mutex = SDL_CreateMutex(); /* Mailbox queue lock */ - actor->turn = SDL_CreateMutex(); /* Lock actor->mutex while initializing JS runtime. */ SDL_LockMutex(actor->mutex); @@ -511,13 +507,19 @@ const char *send_message(const char *id, void *msg) return NULL; } -/* set_actor_state should check if any letters are pending. */ +/* + set_actor_state should check if any letters are pending. + +*/ void set_actor_state(cell_rt *actor) { SDL_LockMutex(actor->msg_mutex); if (actor->need_stop) { - if (!actor->ar) - actor->ar = SDL_AddTimerNS(0, actor_remove_cb, actor); + if (!actor->ar) { + JSValue remove_cb = JS_NewCFunction(actor->context, js_actor_remove_cb, "actor_remove", 0); + actor->ar = scheduler_add_timer(actor, 0, remove_cb); + JS_FreeValue(actor->context, remove_cb); + } SDL_UnlockMutex(actor->msg_mutex); return; } @@ -535,9 +537,6 @@ void set_actor_state(cell_rt *actor) SDL_LockMutex(queue_mutex); if (actor->main_thread_only) { arrput(main_ready_queue, actor); - SDL_Event event; - event.type = queue_event; - SDL_PushEvent(&event); } else { SDL_SignalCondition(queue_cond); arrput(ready_queue, actor); @@ -556,15 +555,17 @@ void set_actor_state(cell_rt *actor) } END: - if (actor->state == ACTOR_IDLE && !actor->ar && !has_upcoming) - actor->ar = SDL_AddTimerNS(SDL_SECONDS_TO_NS(actor->ar_secs), actor_remove_cb, actor); + if (actor->state == ACTOR_IDLE && !actor->ar && !has_upcoming) { + JSValue remove_cb = JS_NewCFunction(actor->context, js_actor_remove_cb, "actor_remove", 0); + actor->ar = scheduler_add_timer(actor, actor->ar_secs, remove_cb); + JS_FreeValue(actor->context, remove_cb); + } SDL_UnlockMutex(actor->msg_mutex); } -void actor_turn(cell_rt *actor, int greedy) +void actor_turn(cell_rt *actor) { - SDL_LockMutex(actor->turn); #ifdef TRACY_ENABLE if (tracy_profiling_enabled) TracyCFiberEnter(actor->name); @@ -573,19 +574,8 @@ void actor_turn(cell_rt *actor, int greedy) SDL_LockMutex(actor->msg_mutex); actor->state = ACTOR_RUNNING; - int letters_count = 0; - int need_stop = 0; JSValue result; - letters_count = arrlen(actor->letters); - need_stop = actor->need_stop; - SDL_UnlockMutex(actor->msg_mutex); - - if (need_stop) goto KILL; - if (!letters_count) goto END; - - PROCESS_LETTER: - SDL_LockMutex(actor->msg_mutex); letter l = actor->letters[0]; arrdel(actor->letters, 0); SDL_UnlockMutex(actor->msg_mutex); @@ -606,41 +596,12 @@ void actor_turn(cell_rt *actor, int greedy) SDL_UnlockMutex(actor->mutex); - if (!greedy) goto END; - - SDL_LockMutex(actor->msg_mutex); - need_stop = actor->need_stop; - letters_count = arrlen(actor->letters); - SDL_UnlockMutex(actor->msg_mutex); - - if (need_stop) goto KILL; - if (!letters_count) goto END; - - SDL_LockMutex(queue_mutex); - int queuen = arrlen(ready_queue); - SDL_UnlockMutex(queue_mutex); - - if (queuen != 0) - goto END; - - goto PROCESS_LETTER; +#ifdef TRACY_ENABLE + if (tracy_profiling_enabled) + TracyCFiberLeave(actor->name); +#endif - END: -#ifdef TRACY_ENABLE - if (tracy_profiling_enabled) - TracyCFiberLeave(actor->name); -#endif - SDL_UnlockMutex(actor->turn); set_actor_state(actor); - return; - - KILL: -#ifdef TRACY_ENABLE - if (tracy_profiling_enabled) - TracyCFiberLeave(actor->name); -#endif - SDL_UnlockMutex(actor->turn); - actor_free(actor); } @@ -866,7 +827,7 @@ static int crank_actor(void *data) } SDL_UnlockMutex(queue_mutex); - if (actor) actor_turn(actor, 1); + if (actor) actor_turn(actor); } return 0; } @@ -887,661 +848,6 @@ static void signal_handler(int sig) exit_handler(); } -// Assume these helper functions exist or need to be implemented -const char* event_type_to_string(Uint32 event_type) { - switch (event_type) { - // Application events - case SDL_EVENT_QUIT: return "quit"; - case SDL_EVENT_TERMINATING: return "terminating"; - case SDL_EVENT_LOW_MEMORY: return "low_memory"; - case SDL_EVENT_WILL_ENTER_BACKGROUND: return "will_enter_background"; - case SDL_EVENT_DID_ENTER_BACKGROUND: return "did_enter_background"; - case SDL_EVENT_WILL_ENTER_FOREGROUND: return "will_enter_foreground"; - case SDL_EVENT_DID_ENTER_FOREGROUND: return "did_enter_foreground"; - case SDL_EVENT_LOCALE_CHANGED: return "locale_changed"; - case SDL_EVENT_SYSTEM_THEME_CHANGED: return "system_theme_changed"; - - // Display events - case SDL_EVENT_DISPLAY_ORIENTATION: return "display_orientation"; - case SDL_EVENT_DISPLAY_ADDED: return "display_added"; - case SDL_EVENT_DISPLAY_REMOVED: return "display_removed"; - case SDL_EVENT_DISPLAY_MOVED: return "display_moved"; - case SDL_EVENT_DISPLAY_DESKTOP_MODE_CHANGED: return "display_desktop_mode_changed"; - case SDL_EVENT_DISPLAY_CURRENT_MODE_CHANGED: return "display_current_mode_changed"; - case SDL_EVENT_DISPLAY_CONTENT_SCALE_CHANGED: return "display_content_scale_changed"; - - // Window events - case SDL_EVENT_WINDOW_SHOWN: return "window_shown"; - case SDL_EVENT_WINDOW_HIDDEN: return "window_hidden"; - case SDL_EVENT_WINDOW_EXPOSED: return "window_exposed"; - case SDL_EVENT_WINDOW_MOVED: return "window_moved"; - case SDL_EVENT_WINDOW_RESIZED: return "window_resized"; - case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED: return "window_pixel_size_changed"; - case SDL_EVENT_WINDOW_METAL_VIEW_RESIZED: return "window_metal_view_resized"; - case SDL_EVENT_WINDOW_MINIMIZED: return "window_minimized"; - case SDL_EVENT_WINDOW_MAXIMIZED: return "window_maximized"; - case SDL_EVENT_WINDOW_RESTORED: return "window_restored"; - case SDL_EVENT_WINDOW_MOUSE_ENTER: return "window_mouse_enter"; - case SDL_EVENT_WINDOW_MOUSE_LEAVE: return "window_mouse_leave"; - case SDL_EVENT_WINDOW_FOCUS_GAINED: return "window_focus_gained"; - case SDL_EVENT_WINDOW_FOCUS_LOST: return "window_focus_lost"; - case SDL_EVENT_WINDOW_CLOSE_REQUESTED: return "window_close_requested"; - case SDL_EVENT_WINDOW_HIT_TEST: return "window_hit_test"; - case SDL_EVENT_WINDOW_ICCPROF_CHANGED: return "window_iccprof_changed"; - case SDL_EVENT_WINDOW_DISPLAY_CHANGED: return "window_display_changed"; - case SDL_EVENT_WINDOW_DISPLAY_SCALE_CHANGED: return "window_display_scale_changed"; - case SDL_EVENT_WINDOW_SAFE_AREA_CHANGED: return "window_safe_area_changed"; - case SDL_EVENT_WINDOW_OCCLUDED: return "window_occluded"; - case SDL_EVENT_WINDOW_ENTER_FULLSCREEN: return "window_enter_fullscreen"; - case SDL_EVENT_WINDOW_LEAVE_FULLSCREEN: return "window_leave_fullscreen"; - case SDL_EVENT_WINDOW_DESTROYED: return "window_destroyed"; - case SDL_EVENT_WINDOW_HDR_STATE_CHANGED: return "window_hdr_state_changed"; - - // Keyboard events - case SDL_EVENT_KEY_DOWN: return "key_down"; - case SDL_EVENT_KEY_UP: return "key_up"; - case SDL_EVENT_TEXT_EDITING: return "text_editing"; - case SDL_EVENT_TEXT_INPUT: return "text_input"; - case SDL_EVENT_KEYMAP_CHANGED: return "keymap_changed"; - case SDL_EVENT_KEYBOARD_ADDED: return "keyboard_added"; - case SDL_EVENT_KEYBOARD_REMOVED: return "keyboard_removed"; - case SDL_EVENT_TEXT_EDITING_CANDIDATES: return "text_editing_candidates"; - - // Mouse events - case SDL_EVENT_MOUSE_MOTION: return "mouse_motion"; - case SDL_EVENT_MOUSE_BUTTON_DOWN: return "mouse_button_down"; - case SDL_EVENT_MOUSE_BUTTON_UP: return "mouse_button_up"; - case SDL_EVENT_MOUSE_WHEEL: return "mouse_wheel"; - case SDL_EVENT_MOUSE_ADDED: return "mouse_added"; - case SDL_EVENT_MOUSE_REMOVED: return "mouse_removed"; - - // Joystick events - case SDL_EVENT_JOYSTICK_AXIS_MOTION: return "joystick_axis_motion"; - case SDL_EVENT_JOYSTICK_BALL_MOTION: return "joystick_ball_motion"; - case SDL_EVENT_JOYSTICK_HAT_MOTION: return "joystick_hat_motion"; - case SDL_EVENT_JOYSTICK_BUTTON_DOWN: return "joystick_button_down"; - case SDL_EVENT_JOYSTICK_BUTTON_UP: return "joystick_button_up"; - case SDL_EVENT_JOYSTICK_ADDED: return "joystick_added"; - case SDL_EVENT_JOYSTICK_REMOVED: return "joystick_removed"; - case SDL_EVENT_JOYSTICK_BATTERY_UPDATED: return "joystick_battery_updated"; - case SDL_EVENT_JOYSTICK_UPDATE_COMPLETE: return "joystick_update_complete"; - - // Gamepad events - case SDL_EVENT_GAMEPAD_AXIS_MOTION: return "gamepad_axis_motion"; - case SDL_EVENT_GAMEPAD_BUTTON_DOWN: return "gamepad_button_down"; - case SDL_EVENT_GAMEPAD_BUTTON_UP: return "gamepad_button_up"; - case SDL_EVENT_GAMEPAD_ADDED: return "gamepad_added"; - case SDL_EVENT_GAMEPAD_REMOVED: return "gamepad_removed"; - case SDL_EVENT_GAMEPAD_REMAPPED: return "gamepad_remapped"; - case SDL_EVENT_GAMEPAD_TOUCHPAD_DOWN: return "gamepad_touchpad_down"; - case SDL_EVENT_GAMEPAD_TOUCHPAD_MOTION: return "gamepad_touchpad_motion"; - case SDL_EVENT_GAMEPAD_TOUCHPAD_UP: return "gamepad_touchpad_up"; - case SDL_EVENT_GAMEPAD_SENSOR_UPDATE: return "gamepad_sensor_update"; - case SDL_EVENT_GAMEPAD_UPDATE_COMPLETE: return "gamepad_update_complete"; - case SDL_EVENT_GAMEPAD_STEAM_HANDLE_UPDATED: return "gamepad_steam_handle_updated"; - - // Touch events - case SDL_EVENT_FINGER_DOWN: return "finger_down"; - case SDL_EVENT_FINGER_UP: return "finger_up"; - case SDL_EVENT_FINGER_MOTION: return "finger_motion"; - - // Clipboard events - case SDL_EVENT_CLIPBOARD_UPDATE: return "clipboard_update"; - - // Drag and drop events - case SDL_EVENT_DROP_FILE: return "drop_file"; - case SDL_EVENT_DROP_TEXT: return "drop_text"; - case SDL_EVENT_DROP_BEGIN: return "drop_begin"; - case SDL_EVENT_DROP_COMPLETE: return "drop_complete"; - case SDL_EVENT_DROP_POSITION: return "drop_position"; - - // Audio device events - case SDL_EVENT_AUDIO_DEVICE_ADDED: return "audio_device_added"; - case SDL_EVENT_AUDIO_DEVICE_REMOVED: return "audio_device_removed"; - case SDL_EVENT_AUDIO_DEVICE_FORMAT_CHANGED: return "audio_device_format_changed"; - - // Sensor events - case SDL_EVENT_SENSOR_UPDATE: return "sensor_update"; - - // Pen events - case SDL_EVENT_PEN_PROXIMITY_IN: return "pen_proximity_in"; - case SDL_EVENT_PEN_PROXIMITY_OUT: return "pen_proximity_out"; - case SDL_EVENT_PEN_DOWN: return "pen_down"; - case SDL_EVENT_PEN_UP: return "pen_up"; - case SDL_EVENT_PEN_BUTTON_DOWN: return "pen_button_down"; - case SDL_EVENT_PEN_BUTTON_UP: return "pen_button_up"; - case SDL_EVENT_PEN_MOTION: return "pen_motion"; - case SDL_EVENT_PEN_AXIS: return "pen_axis"; - - // Camera events - case SDL_EVENT_CAMERA_DEVICE_ADDED: return "camera_device_added"; - case SDL_EVENT_CAMERA_DEVICE_REMOVED: return "camera_device_removed"; - case SDL_EVENT_CAMERA_DEVICE_APPROVED: return "camera_device_approved"; - case SDL_EVENT_CAMERA_DEVICE_DENIED: return "camera_device_denied"; - - // Render events - case SDL_EVENT_RENDER_TARGETS_RESET: return "render_targets_reset"; - case SDL_EVENT_RENDER_DEVICE_RESET: return "render_device_reset"; - case SDL_EVENT_RENDER_DEVICE_LOST: return "render_device_lost"; - - // User event (assuming it should be included) - case SDL_EVENT_USER: return "user"; - - default: return "unknown"; - } -} - -const char* mouse_button_to_string(int mouse) { - switch (mouse) { - case SDL_BUTTON_LEFT: return "left"; - case SDL_BUTTON_MIDDLE: return "middle"; - case SDL_BUTTON_RIGHT: return "right"; - case SDL_BUTTON_X1: return "x1"; - case SDL_BUTTON_X2: return "x2"; - default: return "left"; - } -} - -static void wota_write_vec2(WotaBuffer *wb, double x, double y) { - // We'll store as WOTA_ARR of length 2, then two numbers - wota_write_array(wb, 2); - wota_write_number(wb, x); - wota_write_number(wb, y); -} - -static int event2wota_count_props(const SDL_Event *event) -{ - // We always store at least "type" and "timestamp". - int count = 2; - - switch (event->type) { - - case SDL_EVENT_AUDIO_DEVICE_ADDED: - case SDL_EVENT_AUDIO_DEVICE_REMOVED: - count += 2; // which, recording - break; - - case SDL_EVENT_DISPLAY_ORIENTATION: - case SDL_EVENT_DISPLAY_ADDED: - case SDL_EVENT_DISPLAY_REMOVED: - case SDL_EVENT_DISPLAY_MOVED: - case SDL_EVENT_DISPLAY_DESKTOP_MODE_CHANGED: - case SDL_EVENT_DISPLAY_CURRENT_MODE_CHANGED: - case SDL_EVENT_DISPLAY_CONTENT_SCALE_CHANGED: - count += 3; // which, data1, data2 - break; - - case SDL_EVENT_MOUSE_MOTION: - count += 5; - break; - - case SDL_EVENT_MOUSE_WHEEL: - // window, which, scroll, mouse => 4 extra - count += 4; - break; - - case SDL_EVENT_MOUSE_BUTTON_UP: - case SDL_EVENT_MOUSE_BUTTON_DOWN: - // window, which, down, button, clicks, mouse => 6 extra - count += 6; - break; - - case SDL_EVENT_SENSOR_UPDATE: - // which, sensor_timestamp => 2 extra - count += 2; - break; - - case SDL_EVENT_KEY_DOWN: - case SDL_EVENT_KEY_UP: - // window, which, down, repeat, key, scancode, mod => 7 extra - count += 7; - break; - - case SDL_EVENT_FINGER_MOTION: - case SDL_EVENT_FINGER_DOWN: - case SDL_EVENT_FINGER_UP: - // touch, finger, pos, d_pos, pressure, window => 6 extra - count += 6; - break; - - case SDL_EVENT_DROP_BEGIN: - case SDL_EVENT_DROP_FILE: - case SDL_EVENT_DROP_TEXT: - case SDL_EVENT_DROP_COMPLETE: - case SDL_EVENT_DROP_POSITION: - // window, pos, data, source => 4 extra - count += 4; - break; - - case SDL_EVENT_TEXT_INPUT: - // window, text, mod => 3 extra - count += 3; - break; - - case SDL_EVENT_CAMERA_DEVICE_APPROVED: - case SDL_EVENT_CAMERA_DEVICE_REMOVED: - case SDL_EVENT_CAMERA_DEVICE_ADDED: - case SDL_EVENT_CAMERA_DEVICE_DENIED: - // which => 1 extra - count += 1; - break; - - case SDL_EVENT_CLIPBOARD_UPDATE: - // owner => 1 extra - count += 1; - break; - - /* Window events (just group them all together) */ - case SDL_EVENT_WINDOW_SHOWN: - case SDL_EVENT_WINDOW_HIDDEN: - case SDL_EVENT_WINDOW_EXPOSED: - case SDL_EVENT_WINDOW_MOVED: - case SDL_EVENT_WINDOW_RESIZED: - case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED: - case SDL_EVENT_WINDOW_METAL_VIEW_RESIZED: - case SDL_EVENT_WINDOW_MINIMIZED: - case SDL_EVENT_WINDOW_MAXIMIZED: - case SDL_EVENT_WINDOW_RESTORED: - case SDL_EVENT_WINDOW_MOUSE_ENTER: - case SDL_EVENT_WINDOW_MOUSE_LEAVE: - case SDL_EVENT_WINDOW_FOCUS_GAINED: - case SDL_EVENT_WINDOW_FOCUS_LOST: - case SDL_EVENT_WINDOW_CLOSE_REQUESTED: - case SDL_EVENT_WINDOW_HIT_TEST: - case SDL_EVENT_WINDOW_ICCPROF_CHANGED: - case SDL_EVENT_WINDOW_DISPLAY_CHANGED: - case SDL_EVENT_WINDOW_DISPLAY_SCALE_CHANGED: - case SDL_EVENT_WINDOW_SAFE_AREA_CHANGED: - case SDL_EVENT_WINDOW_OCCLUDED: - case SDL_EVENT_WINDOW_ENTER_FULLSCREEN: - case SDL_EVENT_WINDOW_LEAVE_FULLSCREEN: - case SDL_EVENT_WINDOW_DESTROYED: - case SDL_EVENT_WINDOW_HDR_STATE_CHANGED: - // which, data1, data2 => 3 extra - count += 3; - break; - - case SDL_EVENT_JOYSTICK_ADDED: - case SDL_EVENT_JOYSTICK_REMOVED: - case SDL_EVENT_JOYSTICK_UPDATE_COMPLETE: - // which => 1 extra - count += 1; - break; - - case SDL_EVENT_JOYSTICK_AXIS_MOTION: - // which, axis, value => 3 extra - count += 3; - break; - - case SDL_EVENT_JOYSTICK_BALL_MOTION: - // which, ball, rel => 3 extra - count += 3; - break; - - case SDL_EVENT_JOYSTICK_BUTTON_DOWN: - case SDL_EVENT_JOYSTICK_BUTTON_UP: - // which, button, down => 3 extra - count += 3; - break; - - case SDL_EVENT_GAMEPAD_ADDED: - case SDL_EVENT_GAMEPAD_REMOVED: - case SDL_EVENT_GAMEPAD_REMAPPED: - case SDL_EVENT_GAMEPAD_UPDATE_COMPLETE: - case SDL_EVENT_GAMEPAD_STEAM_HANDLE_UPDATED: - // which => 1 extra - count += 1; - break; - - case SDL_EVENT_GAMEPAD_AXIS_MOTION: - // which, axis, value => 3 extra - count += 3; - break; - - case SDL_EVENT_GAMEPAD_BUTTON_DOWN: - case SDL_EVENT_GAMEPAD_BUTTON_UP: - // which, button, down => 3 extra - count += 3; - break; - - case SDL_EVENT_GAMEPAD_TOUCHPAD_DOWN: - case SDL_EVENT_GAMEPAD_TOUCHPAD_MOTION: - case SDL_EVENT_GAMEPAD_TOUCHPAD_UP: - // which, touchpad, finger, pos, pressure => 5 extra - count += 5; - break; - - case SDL_EVENT_GAMEPAD_SENSOR_UPDATE: - // which, sensor, sensor_timestamp => 3 extra - count += 3; - break; - - case SDL_EVENT_USER: - // cb => 1 extra - count += 1; - break; - } - - return count; -} - -static void event2wota_write(WotaBuffer *wb, const SDL_Event *e, int c) { - wota_write_record(wb, (unsigned long long)c); - wota_write_text(wb, "type"); - wota_write_text(wb, event_type_to_string(e->type)); - wota_write_text(wb, "timestamp"); - wota_write_number(wb, (double)e->common.timestamp); - switch(e->type) { - case SDL_EVENT_AUDIO_DEVICE_ADDED: - case SDL_EVENT_AUDIO_DEVICE_REMOVED: - wota_write_text(wb, "which"); - wota_write_number(wb, (double)e->adevice.which); - wota_write_text(wb, "recording"); - wota_write_sym(wb, e->adevice.recording ? WOTA_TRUE : WOTA_FALSE); - break; - case SDL_EVENT_DISPLAY_ORIENTATION: - case SDL_EVENT_DISPLAY_ADDED: - case SDL_EVENT_DISPLAY_REMOVED: - case SDL_EVENT_DISPLAY_MOVED: - case SDL_EVENT_DISPLAY_DESKTOP_MODE_CHANGED: - case SDL_EVENT_DISPLAY_CURRENT_MODE_CHANGED: - case SDL_EVENT_DISPLAY_CONTENT_SCALE_CHANGED: - wota_write_text(wb, "which"); - wota_write_number(wb, (double)e->display.displayID); - wota_write_text(wb, "data1"); - wota_write_number(wb, (double)e->display.data1); - wota_write_text(wb, "data2"); - wota_write_number(wb, (double)e->display.data2); - break; - case SDL_EVENT_MOUSE_MOTION: - wota_write_text(wb, "window"); - wota_write_number(wb, (double)e->motion.windowID); - wota_write_text(wb, "which"); - wota_write_number(wb, (double)e->motion.which); - wota_write_text(wb, "state"); - wota_write_number(wb, (double)e->motion.state); - wota_write_text(wb, "pos"); - wota_write_vec2(wb, (double)e->motion.x, (double)e->motion.y); - wota_write_text(wb, "d_pos"); - wota_write_vec2(wb, (double)e->motion.xrel, (double)e->motion.yrel); - break; - case SDL_EVENT_MOUSE_WHEEL: - wota_write_text(wb, "window"); - wota_write_number(wb, (double)e->wheel.windowID); - wota_write_text(wb, "which"); - wota_write_number(wb, (double)e->wheel.which); - wota_write_text(wb, "scroll"); - wota_write_vec2(wb, (double)e->wheel.x, (double)e->wheel.y); - wota_write_text(wb, "pos"); - wota_write_vec2(wb, (double)e->wheel.mouse_x, (double)e->wheel.mouse_y); - break; - case SDL_EVENT_MOUSE_BUTTON_UP: - case SDL_EVENT_MOUSE_BUTTON_DOWN: - wota_write_text(wb, "window"); - wota_write_number(wb, (double)e->button.windowID); - wota_write_text(wb, "which"); - wota_write_number(wb, (double)e->button.which); - wota_write_text(wb, "down"); - wota_write_sym(wb, e->button.down ? WOTA_TRUE : WOTA_FALSE); - wota_write_text(wb, "button"); - wota_write_text(wb, mouse_button_to_string(e->button.button)); - wota_write_text(wb, "clicks"); - wota_write_number(wb, (double)e->button.clicks); - wota_write_text(wb, "pos"); - wota_write_vec2(wb, (double)e->button.x, (double)e->button.y); - break; - case SDL_EVENT_SENSOR_UPDATE: - wota_write_text(wb, "which"); - wota_write_number(wb, (double)e->sensor.which); - wota_write_text(wb, "sensor_timestamp"); - wota_write_number(wb, (double)e->sensor.sensor_timestamp); - break; - case SDL_EVENT_KEY_DOWN: - case SDL_EVENT_KEY_UP: - wota_write_text(wb, "window"); - wota_write_number(wb, (double)e->key.windowID); - wota_write_text(wb, "which"); - wota_write_number(wb, (double)e->key.which); - wota_write_text(wb, "down"); - wota_write_sym(wb, e->key.down ? WOTA_TRUE : WOTA_FALSE); - wota_write_text(wb, "repeat"); - wota_write_sym(wb, e->key.repeat ? WOTA_TRUE : WOTA_FALSE); - wota_write_text(wb, "key"); - wota_write_number(wb, (double)e->key.key); - wota_write_text(wb, "scancode"); - wota_write_number(wb, (double)e->key.scancode); - wota_write_text(wb, "mod"); - wota_write_number(wb, 0); - break; - case SDL_EVENT_FINGER_MOTION: - case SDL_EVENT_FINGER_DOWN: - case SDL_EVENT_FINGER_UP: - wota_write_text(wb, "touch"); - wota_write_number(wb, (double)e->tfinger.touchID); - wota_write_text(wb, "finger"); - wota_write_number(wb, (double)e->tfinger.fingerID); - wota_write_text(wb, "pos"); - wota_write_vec2(wb, (double)e->tfinger.x, (double)e->tfinger.y); - wota_write_text(wb, "d_pos"); - wota_write_vec2(wb, (double)e->tfinger.dx, (double)e->tfinger.dy); - wota_write_text(wb, "pressure"); - wota_write_number(wb, (double)e->tfinger.pressure); - wota_write_text(wb, "window"); - wota_write_number(wb, (double)e->key.windowID); - break; - case SDL_EVENT_DROP_BEGIN: - case SDL_EVENT_DROP_FILE: - case SDL_EVENT_DROP_TEXT: - case SDL_EVENT_DROP_COMPLETE: - case SDL_EVENT_DROP_POSITION: - wota_write_text(wb, "window"); - wota_write_number(wb, (double)e->drop.windowID); - wota_write_text(wb, "pos"); - wota_write_vec2(wb, (double)e->drop.x, (double)e->drop.y); - wota_write_text(wb, "data"); - wota_write_text(wb, e->drop.data ? e->drop.data : ""); - wota_write_text(wb, "source"); - wota_write_text(wb, e->drop.source ? e->drop.source : ""); - break; - case SDL_EVENT_TEXT_INPUT: - wota_write_text(wb, "window"); - wota_write_number(wb, (double)e->text.windowID); - wota_write_text(wb, "text"); - wota_write_text(wb, e->text.text); - wota_write_text(wb, "mod"); - wota_write_number(wb, 0); - break; - case SDL_EVENT_CAMERA_DEVICE_APPROVED: - case SDL_EVENT_CAMERA_DEVICE_REMOVED: - case SDL_EVENT_CAMERA_DEVICE_ADDED: - case SDL_EVENT_CAMERA_DEVICE_DENIED: - wota_write_text(wb, "which"); - wota_write_number(wb, (double)e->cdevice.which); - break; - case SDL_EVENT_CLIPBOARD_UPDATE: - wota_write_text(wb, "owner"); - wota_write_sym(wb, e->clipboard.owner ? WOTA_TRUE : WOTA_FALSE); - break; - case SDL_EVENT_WINDOW_SHOWN: - case SDL_EVENT_WINDOW_HIDDEN: - case SDL_EVENT_WINDOW_EXPOSED: - case SDL_EVENT_WINDOW_MOVED: - case SDL_EVENT_WINDOW_RESIZED: - case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED: - case SDL_EVENT_WINDOW_METAL_VIEW_RESIZED: - case SDL_EVENT_WINDOW_MINIMIZED: - case SDL_EVENT_WINDOW_MAXIMIZED: - case SDL_EVENT_WINDOW_RESTORED: - case SDL_EVENT_WINDOW_MOUSE_ENTER: - case SDL_EVENT_WINDOW_MOUSE_LEAVE: - case SDL_EVENT_WINDOW_FOCUS_GAINED: - case SDL_EVENT_WINDOW_FOCUS_LOST: - case SDL_EVENT_WINDOW_CLOSE_REQUESTED: - case SDL_EVENT_WINDOW_HIT_TEST: - case SDL_EVENT_WINDOW_ICCPROF_CHANGED: - case SDL_EVENT_WINDOW_DISPLAY_CHANGED: - case SDL_EVENT_WINDOW_DISPLAY_SCALE_CHANGED: - case SDL_EVENT_WINDOW_SAFE_AREA_CHANGED: - case SDL_EVENT_WINDOW_OCCLUDED: - case SDL_EVENT_WINDOW_ENTER_FULLSCREEN: - case SDL_EVENT_WINDOW_LEAVE_FULLSCREEN: - case SDL_EVENT_WINDOW_DESTROYED: - case SDL_EVENT_WINDOW_HDR_STATE_CHANGED: - wota_write_text(wb, "which"); - wota_write_number(wb, (double)e->window.windowID); - wota_write_text(wb, "data1"); - wota_write_number(wb, (double)e->window.data1); - wota_write_text(wb, "data2"); - wota_write_number(wb, (double)e->window.data2); - break; - case SDL_EVENT_JOYSTICK_ADDED: - case SDL_EVENT_JOYSTICK_REMOVED: - case SDL_EVENT_JOYSTICK_UPDATE_COMPLETE: - wota_write_text(wb, "which"); - wota_write_number(wb, (double)e->jdevice.which); - break; - case SDL_EVENT_JOYSTICK_AXIS_MOTION: - wota_write_text(wb, "which"); - wota_write_number(wb, (double)e->jaxis.which); - wota_write_text(wb, "axis"); - wota_write_number(wb, (double)e->jaxis.axis); - wota_write_text(wb, "value"); - wota_write_number(wb, (double)e->jaxis.value); - break; - case SDL_EVENT_JOYSTICK_BALL_MOTION: - wota_write_text(wb, "which"); - wota_write_number(wb, (double)e->jball.which); - wota_write_text(wb, "ball"); - wota_write_number(wb, (double)e->jball.ball); - wota_write_text(wb, "rel"); - wota_write_vec2(wb, (double)e->jball.xrel, (double)e->jball.yrel); - break; - case SDL_EVENT_JOYSTICK_BUTTON_DOWN: - case SDL_EVENT_JOYSTICK_BUTTON_UP: - wota_write_text(wb, "which"); - wota_write_number(wb, (double)e->jbutton.which); - wota_write_text(wb, "button"); - wota_write_number(wb, (double)e->jbutton.button); - wota_write_text(wb, "down"); - wota_write_sym(wb, e->jbutton.down ? WOTA_TRUE : WOTA_FALSE); - break; - case SDL_EVENT_GAMEPAD_ADDED: - case SDL_EVENT_GAMEPAD_REMOVED: - case SDL_EVENT_GAMEPAD_REMAPPED: - case SDL_EVENT_GAMEPAD_UPDATE_COMPLETE: - case SDL_EVENT_GAMEPAD_STEAM_HANDLE_UPDATED: - wota_write_text(wb, "which"); - wota_write_number(wb, (double)e->gdevice.which); - break; - case SDL_EVENT_GAMEPAD_AXIS_MOTION: - wota_write_text(wb, "which"); - wota_write_number(wb, (double)e->gaxis.which); - wota_write_text(wb, "axis"); - wota_write_number(wb, (double)e->gaxis.axis); - wota_write_text(wb, "value"); - wota_write_number(wb, (double)e->gaxis.value); - break; - case SDL_EVENT_GAMEPAD_BUTTON_DOWN: - case SDL_EVENT_GAMEPAD_BUTTON_UP: - wota_write_text(wb, "which"); - wota_write_number(wb, (double)e->gbutton.which); - wota_write_text(wb, "button"); - wota_write_number(wb, (double)e->gbutton.button); - wota_write_text(wb, "down"); - wota_write_sym(wb, e->gbutton.down ? WOTA_TRUE : WOTA_FALSE); - break; - case SDL_EVENT_GAMEPAD_TOUCHPAD_DOWN: - case SDL_EVENT_GAMEPAD_TOUCHPAD_MOTION: - case SDL_EVENT_GAMEPAD_TOUCHPAD_UP: - wota_write_text(wb, "which"); - wota_write_number(wb, (double)e->gtouchpad.which); - wota_write_text(wb, "touchpad"); - wota_write_number(wb, (double)e->gtouchpad.touchpad); - wota_write_text(wb, "finger"); - wota_write_number(wb, (double)e->gtouchpad.finger); - wota_write_text(wb, "pos"); - wota_write_vec2(wb, (double)e->gtouchpad.x, (double)e->gtouchpad.y); - wota_write_text(wb, "pressure"); - wota_write_number(wb, (double)e->gtouchpad.pressure); - break; - case SDL_EVENT_GAMEPAD_SENSOR_UPDATE: - wota_write_text(wb, "which"); - wota_write_number(wb, (double)e->gsensor.which); - wota_write_text(wb, "sensor"); - wota_write_number(wb, (double)e->gsensor.sensor); - wota_write_text(wb, "sensor_timestamp"); - wota_write_number(wb, (double)e->gsensor.sensor_timestamp); - break; - case SDL_EVENT_USER: - wota_write_text(wb, "cb"); - wota_write_number(wb, (double)(uintptr_t)e->user.data1); - break; - } -} - -static WotaBuffer event2wota(const SDL_Event *event) { - WotaBuffer wb; - wota_buffer_init(&wb, 8); - int n = event2wota_count_props(event); - event2wota_write(&wb, event, n); - return wb; -} - -bool event_watch(void *data, SDL_Event *e) -{ - if (e->type == queue_event) return true; - - SDL_LockMutex(event_watchers_mutex); - int n_watchers = arrlen(event_watchers); - if (n_watchers == 0) { - SDL_UnlockMutex(event_watchers_mutex); - return true; - } - - /* Create a copy of watcher IDs while holding the lock */ - char **watchers_copy = NULL; - arrsetcap(watchers_copy, n_watchers); - for (int i = 0; i < n_watchers; i++) { - arrput(watchers_copy, strdup(event_watchers[i])); - } - SDL_UnlockMutex(event_watchers_mutex); - - WotaBuffer wb = event2wota(e); - - for (int i = 0; i < arrlen(watchers_copy); i++) { - if (actor_exists(watchers_copy[i])) { - const char *err = send_message(watchers_copy[i], wota_dup_data(&wb)); - if (err) { - /* Remove dead actor from watchers */ - SDL_LockMutex(event_watchers_mutex); - for (int j = 0; j < arrlen(event_watchers); j++) { - if (strcmp(event_watchers[j], watchers_copy[i]) == 0) { - free(event_watchers[j]); - arrdel(event_watchers, j); - break; - } - } - SDL_UnlockMutex(event_watchers_mutex); - } - } else { - /* Remove dead actor from watchers */ - SDL_LockMutex(event_watchers_mutex); - for (int j = 0; j < arrlen(event_watchers); j++) { - if (strcmp(event_watchers[j], watchers_copy[i]) == 0) { - free(event_watchers[j]); - arrdel(event_watchers, j); - break; - } - } - SDL_UnlockMutex(event_watchers_mutex); - } - free(watchers_copy[i]); - } - - arrfree(watchers_copy); - wota_buffer_free(&wb); - return true; -} int main(int argc, char **argv) { @@ -1557,7 +863,6 @@ int main(int argc, char **argv) printf("CRITICAL ERROR: %s\n", SDL_GetError()); exit(1); } - queue_event = SDL_RegisterEvents(1); #ifdef TRACY_ENABLE tracy_profiling_enabled = profile_enabled; @@ -1620,7 +925,6 @@ int main(int argc, char **argv) queue_mutex = SDL_CreateMutex(); queue_cond = SDL_CreateCondition(); actors_mutex = SDL_CreateMutex(); - event_watchers_mutex = SDL_CreateMutex(); timer_mutex = SDL_CreateMutex(); /* Create the initial actor from the command line */ @@ -1654,30 +958,10 @@ int main(int argc, char **argv) atexit(exit_handler); /* Main loop: pump ready actors */ - SDL_Event event; - const uint64_t fallback_sleep = 1000000ULL; /* 1 ms */ while (!SDL_GetAtomicInt(&engine_shutdown)) { process_due_timers(); // Process any due timers first - - /* Check for SDL events with timeout */ - uint64_t to_ns = next_timeout_ns(); - if (to_ns == UINT64_MAX || to_ns > fallback_sleep) to_ns = fallback_sleep; - - /* Convert nanoseconds to milliseconds for SDL_WaitEventTimeout */ - int timeout_ms = (int)(to_ns / 1000000ULL); - if (timeout_ms < 1) timeout_ms = 1; - - if (SDL_WaitEventTimeout(&event, timeout_ms)) { - if (event.type == queue_event) { - goto QUEUE; - } - /* Process other SDL events as needed */ - continue; - } - - /* Timeout occurred - check queues anyway */ - QUEUE: + SDL_LockMutex(queue_mutex); cell_rt *actor = NULL; if (arrlen(main_ready_queue) > 0) { @@ -1686,9 +970,20 @@ int main(int argc, char **argv) } SDL_UnlockMutex(queue_mutex); - if (actor) { - actor_turn(actor, 0); - } + if (actor) + actor_turn(actor); + + uint64_t to_ns = next_timeout_ns(); + if (to_ns == UINT64_MAX) { + // No timers pending, wait indefinitely + pselect(0, NULL, NULL, NULL, NULL, NULL); + } else { + struct timespec timeout = { + .tv_sec = to_ns / 1000000000, + .tv_nsec = to_ns % 1000000000 + }; + pselect(0, NULL, NULL, NULL, &timeout, NULL); + } } return 0; @@ -1705,7 +1000,7 @@ int actor_exists(const char *id) return 1; } -int JS_ArrayLength(JSContext *js, JSValue a) +/*int JS_ArrayLength(JSContext *js, JSValue a) { JSValue length = JS_GetPropertyStr(js, a, "length"); int len; @@ -1713,3 +1008,4 @@ int JS_ArrayLength(JSContext *js, JSValue a) JS_FreeValue(js,length); return len; } +*/ \ No newline at end of file diff --git a/source/cell.h b/source/cell.h index 658fb3f2..51148ae3 100644 --- a/source/cell.h +++ b/source/cell.h @@ -57,8 +57,7 @@ typedef struct cell_rt { JSValue *js_swapchains; /* Protects JSContext usage */ - SDL_Mutex *mutex; - SDL_Mutex *turn; + SDL_Mutex *mutex; /* for access to the JSContext */ SDL_Mutex *msg_mutex; /* For messages queue only */ char *id; @@ -111,8 +110,5 @@ int JS_ArrayLength(JSContext *js, JSValue a); int prosperon_mount_core(void); -// Event watchers for SDL events -extern char **event_watchers; -extern SDL_Mutex *event_watchers_mutex; #endif diff --git a/source/jsffi.c b/source/jsffi.c index 03d423d1..749a580d 100644 --- a/source/jsffi.c +++ b/source/jsffi.c @@ -2,6 +2,7 @@ #include "font.h" #include "datastream.h" #include "qjs_sdl.h" +#include "qjs_sdl_input.h" #include "qjs_io.h" #include "qjs_fd.h" #include "transform.h" @@ -1619,11 +1620,11 @@ void ffi_load(JSContext *js) rt->init_wota = NULL; } - cell_rt *actor = JS_GetContextOpaque(js); - JSValue actorsym = js_newsymbol(js, "actor symbol", 0); - actor->actor_sym = JS_ValueToAtom(js, actorsym); - JS_SetPropertyStr(js, hidden_fn, "ACTORDATA", JS_DupValue(js,actorsym)); - JS_FreeValue(js, actorsym); +// cell_rt *actor = JS_GetContextOpaque(js); +// JSValue actorsym = js_newsymbol(js, "actor symbol", 0); +// actor->actor_sym = JS_ValueToAtom(js, actorsym); +// JS_SetPropertyStr(js, hidden_fn, "ACTORDATA", JS_DupValue(js,actorsym)); +// JS_FreeValue(js, actorsym); JS_SetPropertyStr(js, prosp, "hidden", hidden_fn); JS_FreeValue(js,globalThis); diff --git a/source/qjs_sdl.c b/source/qjs_sdl.c index ed0f7fc6..9eac53dc 100644 --- a/source/qjs_sdl.c +++ b/source/qjs_sdl.c @@ -23,136 +23,6 @@ void SDL_AudioStream_free(JSRuntime *rt, SDL_AudioStream *st) { QJSCLASS(SDL_Camera,) QJSCLASS(SDL_AudioStream,) -// Internal keymod function for input module -static JSValue js_keymod(JSContext *js) -{ - SDL_Keymod modstate = SDL_GetModState(); - JSValue ret = JS_NewObject(js); - if (SDL_KMOD_CTRL & modstate) - JS_SetPropertyStr(js,ret,"ctrl", JS_NewBool(js,1)); - if (SDL_KMOD_SHIFT & modstate) - JS_SetPropertyStr(js,ret,"shift", JS_NewBool(js,1)); - if (SDL_KMOD_ALT & modstate) - JS_SetPropertyStr(js,ret,"alt", JS_NewBool(js,1)); - if (SDL_KMOD_GUI & modstate) - JS_SetPropertyStr(js,ret,"super", JS_NewBool(js,1)); - if (SDL_KMOD_NUM & modstate) - JS_SetPropertyStr(js,ret,"numlock", JS_NewBool(js,1)); - if (SDL_KMOD_CAPS & modstate) - JS_SetPropertyStr(js,ret,"caps", JS_NewBool(js,1)); - if (SDL_KMOD_SCROLL & modstate) - JS_SetPropertyStr(js,ret,"scrolllock", JS_NewBool(js,1)); - if (SDL_KMOD_MODE & modstate) - JS_SetPropertyStr(js,ret,"mode", JS_NewBool(js,1)); - - return ret; -} - -// INPUT FUNCTIONS -JSC_CCALL(input_mouse_lock, SDL_CaptureMouse(JS_ToBool(js,argv[0]))) - -JSC_CCALL(input_mouse_show, - if (JS_ToBool(js,argv[0])) - SDL_ShowCursor(); - else - SDL_HideCursor(); -) - -JSC_CCALL(input_keyname, - return JS_NewString(js, SDL_GetKeyName(js2number(js,argv[0]))); -) - -JSC_CCALL(input_keymod, - return js_keymod(js); -) - -JSC_CCALL(input_mousestate, - float x,y; - SDL_MouseButtonFlags flags = SDL_GetMouseState(&x,&y); - JSValue m = JS_NewObject(js); - JS_SetPropertyStr(js,m,"x", number2js(js,x)); - JS_SetPropertyStr(js,m,"y", number2js(js,y)); - - if (flags & SDL_BUTTON_LMASK) - JS_SetPropertyStr(js, m, "left", JS_NewBool(js, 1)); - if (flags & SDL_BUTTON_MMASK) - JS_SetPropertyStr(js, m, "middle", JS_NewBool(js, 1)); - if (flags & SDL_BUTTON_RMASK) - JS_SetPropertyStr(js, m, "right", JS_NewBool(js, 1)); - if (flags & SDL_BUTTON_X1MASK) - JS_SetPropertyStr(js, m, "x1", JS_NewBool(js, 1)); - if (flags & SDL_BUTTON_X2MASK) - JS_SetPropertyStr(js, m, "x2", JS_NewBool(js, 1)); - - return m; -) - -// watch events -extern char **event_watchers; -extern SDL_Mutex *event_watchers_mutex; - -JSC_CCALL(input_watch, - /* Use js2actor to get the actor from the JS object */ - cell_rt *actor = js2actor(js, argv[0]); - if (!actor) - return JS_ThrowTypeError(js, "First argument must be a valid actor object"); - - SDL_LockMutex(event_watchers_mutex); - - /* Check if already watching */ - int already_watching = 0; - for (int i = 0; i < arrlen(event_watchers); i++) { - if (strcmp(event_watchers[i], actor->id) == 0) { - already_watching = 1; - break; - } - } - - if (!already_watching) - arrput(event_watchers, strdup(actor->id)); - - SDL_UnlockMutex(event_watchers_mutex); - - return JS_UNDEFINED; -) - -JSC_CCALL(input_unwatch, - /* Use js2actor to get the actor from the JS object */ - cell_rt *actor = js2actor(js, argv[0]); - if (!actor) - return JS_ThrowTypeError(js, "First argument must be a valid actor object"); - - SDL_LockMutex(event_watchers_mutex); - - /* Find and remove from watchers */ - for (int i = 0; i < arrlen(event_watchers); i++) { - if (strcmp(event_watchers[i], actor->id) == 0) { - free(event_watchers[i]); - arrdel(event_watchers, i); - break; - } - } - - SDL_UnlockMutex(event_watchers_mutex); - - return JS_UNDEFINED; -) - -static const JSCFunctionListEntry js_input_funcs[] = { - MIST_FUNC_DEF(input, mouse_show, 1), - MIST_FUNC_DEF(input, mouse_lock, 1), - MIST_FUNC_DEF(input, keyname, 1), - MIST_FUNC_DEF(input, keymod, 0), - MIST_FUNC_DEF(input, mousestate, 0), - MIST_FUNC_DEF(input, watch, 1), - MIST_FUNC_DEF(input, unwatch, 1), -}; - -JSValue js_input_use(JSContext *js) { - JSValue mod = JS_NewObject(js); - JS_SetPropertyFunctionList(js,mod,js_input_funcs,countof(js_input_funcs)); - return mod; -} // CAMERA FUNCTIONS diff --git a/source/qjs_sdl_input.c b/source/qjs_sdl_input.c new file mode 100644 index 00000000..1e81eeb9 --- /dev/null +++ b/source/qjs_sdl_input.c @@ -0,0 +1,717 @@ +#include "qjs_sdl_input.h" +#include "jsffi.h" +#include "qjs_macros.h" +#include "cell.h" +#include "qjs_blob.h" +#include "stb_ds.h" +#include "qjs_actor.h" +#include "qjs_wota.h" + +#include + +void input_system_init(void) +{ + // No initialization needed for simplified system +} + +void input_system_cleanup(void) +{ + // No cleanup needed for simplified system +} + +// Internal keymod function for input module +static JSValue js_keymod(JSContext *js) +{ + SDL_Keymod modstate = SDL_GetModState(); + JSValue ret = JS_NewObject(js); + if (SDL_KMOD_CTRL & modstate) + JS_SetPropertyStr(js,ret,"ctrl", JS_NewBool(js,1)); + if (SDL_KMOD_SHIFT & modstate) + JS_SetPropertyStr(js,ret,"shift", JS_NewBool(js,1)); + if (SDL_KMOD_ALT & modstate) + JS_SetPropertyStr(js,ret,"alt", JS_NewBool(js,1)); + if (SDL_KMOD_GUI & modstate) + JS_SetPropertyStr(js,ret,"super", JS_NewBool(js,1)); + if (SDL_KMOD_NUM & modstate) + JS_SetPropertyStr(js,ret,"numlock", JS_NewBool(js,1)); + if (SDL_KMOD_CAPS & modstate) + JS_SetPropertyStr(js,ret,"caps", JS_NewBool(js,1)); + if (SDL_KMOD_SCROLL & modstate) + JS_SetPropertyStr(js,ret,"scrolllock", JS_NewBool(js,1)); + if (SDL_KMOD_MODE & modstate) + JS_SetPropertyStr(js,ret,"mode", JS_NewBool(js,1)); + + return ret; +} + +// INPUT FUNCTIONS +JSC_CCALL(input_mouse_lock, SDL_CaptureMouse(JS_ToBool(js,argv[0]))) + +JSC_CCALL(input_mouse_show, + if (JS_ToBool(js,argv[0])) + SDL_ShowCursor(); + else + SDL_HideCursor(); +) + +JSC_CCALL(input_keyname, + return JS_NewString(js, SDL_GetKeyName(js2number(js,argv[0]))); +) + +JSC_CCALL(input_keymod, + return js_keymod(js); +) + +JSC_CCALL(input_mousestate, + float x,y; + SDL_MouseButtonFlags flags = SDL_GetMouseState(&x,&y); + JSValue m = JS_NewObject(js); + JS_SetPropertyStr(js,m,"x", number2js(js,x)); + JS_SetPropertyStr(js,m,"y", number2js(js,y)); + + if (flags & SDL_BUTTON_LMASK) + JS_SetPropertyStr(js, m, "left", JS_NewBool(js, 1)); + if (flags & SDL_BUTTON_MMASK) + JS_SetPropertyStr(js, m, "middle", JS_NewBool(js, 1)); + if (flags & SDL_BUTTON_RMASK) + JS_SetPropertyStr(js, m, "right", JS_NewBool(js, 1)); + if (flags & SDL_BUTTON_X1MASK) + JS_SetPropertyStr(js, m, "x1", JS_NewBool(js, 1)); + if (flags & SDL_BUTTON_X2MASK) + JS_SetPropertyStr(js, m, "x2", JS_NewBool(js, 1)); + + return m; +) + +// Event processing functions (moved from cell.c) + +const char* event_type_to_string(Uint32 event_type) { + switch (event_type) { + // Application events + case SDL_EVENT_QUIT: return "quit"; + case SDL_EVENT_TERMINATING: return "terminating"; + case SDL_EVENT_LOW_MEMORY: return "low_memory"; + case SDL_EVENT_WILL_ENTER_BACKGROUND: return "will_enter_background"; + case SDL_EVENT_DID_ENTER_BACKGROUND: return "did_enter_background"; + case SDL_EVENT_WILL_ENTER_FOREGROUND: return "will_enter_foreground"; + case SDL_EVENT_DID_ENTER_FOREGROUND: return "did_enter_foreground"; + case SDL_EVENT_LOCALE_CHANGED: return "locale_changed"; + case SDL_EVENT_SYSTEM_THEME_CHANGED: return "system_theme_changed"; + + // Display events + case SDL_EVENT_DISPLAY_ORIENTATION: return "display_orientation"; + case SDL_EVENT_DISPLAY_ADDED: return "display_added"; + case SDL_EVENT_DISPLAY_REMOVED: return "display_removed"; + case SDL_EVENT_DISPLAY_MOVED: return "display_moved"; + case SDL_EVENT_DISPLAY_DESKTOP_MODE_CHANGED: return "display_desktop_mode_changed"; + case SDL_EVENT_DISPLAY_CURRENT_MODE_CHANGED: return "display_current_mode_changed"; + case SDL_EVENT_DISPLAY_CONTENT_SCALE_CHANGED: return "display_content_scale_changed"; + + // Window events + case SDL_EVENT_WINDOW_SHOWN: return "window_shown"; + case SDL_EVENT_WINDOW_HIDDEN: return "window_hidden"; + case SDL_EVENT_WINDOW_EXPOSED: return "window_exposed"; + case SDL_EVENT_WINDOW_MOVED: return "window_moved"; + case SDL_EVENT_WINDOW_RESIZED: return "window_resized"; + case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED: return "window_pixel_size_changed"; + case SDL_EVENT_WINDOW_METAL_VIEW_RESIZED: return "window_metal_view_resized"; + case SDL_EVENT_WINDOW_MINIMIZED: return "window_minimized"; + case SDL_EVENT_WINDOW_MAXIMIZED: return "window_maximized"; + case SDL_EVENT_WINDOW_RESTORED: return "window_restored"; + case SDL_EVENT_WINDOW_MOUSE_ENTER: return "window_mouse_enter"; + case SDL_EVENT_WINDOW_MOUSE_LEAVE: return "window_mouse_leave"; + case SDL_EVENT_WINDOW_FOCUS_GAINED: return "window_focus_gained"; + case SDL_EVENT_WINDOW_FOCUS_LOST: return "window_focus_lost"; + case SDL_EVENT_WINDOW_CLOSE_REQUESTED: return "window_close_requested"; + case SDL_EVENT_WINDOW_HIT_TEST: return "window_hit_test"; + case SDL_EVENT_WINDOW_ICCPROF_CHANGED: return "window_iccprof_changed"; + case SDL_EVENT_WINDOW_DISPLAY_CHANGED: return "window_display_changed"; + case SDL_EVENT_WINDOW_DISPLAY_SCALE_CHANGED: return "window_display_scale_changed"; + case SDL_EVENT_WINDOW_SAFE_AREA_CHANGED: return "window_safe_area_changed"; + case SDL_EVENT_WINDOW_OCCLUDED: return "window_occluded"; + case SDL_EVENT_WINDOW_ENTER_FULLSCREEN: return "window_enter_fullscreen"; + case SDL_EVENT_WINDOW_LEAVE_FULLSCREEN: return "window_leave_fullscreen"; + case SDL_EVENT_WINDOW_DESTROYED: return "window_destroyed"; + case SDL_EVENT_WINDOW_HDR_STATE_CHANGED: return "window_hdr_state_changed"; + + // Keyboard events + case SDL_EVENT_KEY_DOWN: return "key_down"; + case SDL_EVENT_KEY_UP: return "key_up"; + case SDL_EVENT_TEXT_EDITING: return "text_editing"; + case SDL_EVENT_TEXT_INPUT: return "text_input"; + case SDL_EVENT_KEYMAP_CHANGED: return "keymap_changed"; + case SDL_EVENT_KEYBOARD_ADDED: return "keyboard_added"; + case SDL_EVENT_KEYBOARD_REMOVED: return "keyboard_removed"; + case SDL_EVENT_TEXT_EDITING_CANDIDATES: return "text_editing_candidates"; + + // Mouse events + case SDL_EVENT_MOUSE_MOTION: return "mouse_motion"; + case SDL_EVENT_MOUSE_BUTTON_DOWN: return "mouse_button_down"; + case SDL_EVENT_MOUSE_BUTTON_UP: return "mouse_button_up"; + case SDL_EVENT_MOUSE_WHEEL: return "mouse_wheel"; + case SDL_EVENT_MOUSE_ADDED: return "mouse_added"; + case SDL_EVENT_MOUSE_REMOVED: return "mouse_removed"; + + // Joystick events + case SDL_EVENT_JOYSTICK_AXIS_MOTION: return "joystick_axis_motion"; + case SDL_EVENT_JOYSTICK_BALL_MOTION: return "joystick_ball_motion"; + case SDL_EVENT_JOYSTICK_HAT_MOTION: return "joystick_hat_motion"; + case SDL_EVENT_JOYSTICK_BUTTON_DOWN: return "joystick_button_down"; + case SDL_EVENT_JOYSTICK_BUTTON_UP: return "joystick_button_up"; + case SDL_EVENT_JOYSTICK_ADDED: return "joystick_added"; + case SDL_EVENT_JOYSTICK_REMOVED: return "joystick_removed"; + case SDL_EVENT_JOYSTICK_BATTERY_UPDATED: return "joystick_battery_updated"; + case SDL_EVENT_JOYSTICK_UPDATE_COMPLETE: return "joystick_update_complete"; + + // Gamepad events + case SDL_EVENT_GAMEPAD_AXIS_MOTION: return "gamepad_axis_motion"; + case SDL_EVENT_GAMEPAD_BUTTON_DOWN: return "gamepad_button_down"; + case SDL_EVENT_GAMEPAD_BUTTON_UP: return "gamepad_button_up"; + case SDL_EVENT_GAMEPAD_ADDED: return "gamepad_added"; + case SDL_EVENT_GAMEPAD_REMOVED: return "gamepad_removed"; + case SDL_EVENT_GAMEPAD_REMAPPED: return "gamepad_remapped"; + case SDL_EVENT_GAMEPAD_TOUCHPAD_DOWN: return "gamepad_touchpad_down"; + case SDL_EVENT_GAMEPAD_TOUCHPAD_MOTION: return "gamepad_touchpad_motion"; + case SDL_EVENT_GAMEPAD_TOUCHPAD_UP: return "gamepad_touchpad_up"; + case SDL_EVENT_GAMEPAD_SENSOR_UPDATE: return "gamepad_sensor_update"; + case SDL_EVENT_GAMEPAD_UPDATE_COMPLETE: return "gamepad_update_complete"; + case SDL_EVENT_GAMEPAD_STEAM_HANDLE_UPDATED: return "gamepad_steam_handle_updated"; + + // Touch events + case SDL_EVENT_FINGER_DOWN: return "finger_down"; + case SDL_EVENT_FINGER_UP: return "finger_up"; + case SDL_EVENT_FINGER_MOTION: return "finger_motion"; + + // Clipboard events + case SDL_EVENT_CLIPBOARD_UPDATE: return "clipboard_update"; + + // Drag and drop events + case SDL_EVENT_DROP_FILE: return "drop_file"; + case SDL_EVENT_DROP_TEXT: return "drop_text"; + case SDL_EVENT_DROP_BEGIN: return "drop_begin"; + case SDL_EVENT_DROP_COMPLETE: return "drop_complete"; + case SDL_EVENT_DROP_POSITION: return "drop_position"; + + // Audio device events + case SDL_EVENT_AUDIO_DEVICE_ADDED: return "audio_device_added"; + case SDL_EVENT_AUDIO_DEVICE_REMOVED: return "audio_device_removed"; + case SDL_EVENT_AUDIO_DEVICE_FORMAT_CHANGED: return "audio_device_format_changed"; + + // Sensor events + case SDL_EVENT_SENSOR_UPDATE: return "sensor_update"; + + // Pen events + case SDL_EVENT_PEN_PROXIMITY_IN: return "pen_proximity_in"; + case SDL_EVENT_PEN_PROXIMITY_OUT: return "pen_proximity_out"; + case SDL_EVENT_PEN_DOWN: return "pen_down"; + case SDL_EVENT_PEN_UP: return "pen_up"; + case SDL_EVENT_PEN_BUTTON_DOWN: return "pen_button_down"; + case SDL_EVENT_PEN_BUTTON_UP: return "pen_button_up"; + case SDL_EVENT_PEN_MOTION: return "pen_motion"; + case SDL_EVENT_PEN_AXIS: return "pen_axis"; + + // Camera events + case SDL_EVENT_CAMERA_DEVICE_ADDED: return "camera_device_added"; + case SDL_EVENT_CAMERA_DEVICE_REMOVED: return "camera_device_removed"; + case SDL_EVENT_CAMERA_DEVICE_APPROVED: return "camera_device_approved"; + case SDL_EVENT_CAMERA_DEVICE_DENIED: return "camera_device_denied"; + + // Render events + case SDL_EVENT_RENDER_TARGETS_RESET: return "render_targets_reset"; + case SDL_EVENT_RENDER_DEVICE_RESET: return "render_device_reset"; + case SDL_EVENT_RENDER_DEVICE_LOST: return "render_device_lost"; + + // User event (assuming it should be included) + case SDL_EVENT_USER: return "user"; + + default: return "unknown"; + } +} + +const char* mouse_button_to_string(int mouse) { + switch (mouse) { + case SDL_BUTTON_LEFT: return "left"; + case SDL_BUTTON_MIDDLE: return "middle"; + case SDL_BUTTON_RIGHT: return "right"; + case SDL_BUTTON_X1: return "x1"; + case SDL_BUTTON_X2: return "x2"; + default: return "left"; + } +} + +static void wota_write_vec2(WotaBuffer *wb, double x, double y) { + // We'll store as WOTA_ARR of length 2, then two numbers + wota_write_array(wb, 2); + wota_write_number(wb, x); + wota_write_number(wb, y); +} + +static int event2wota_count_props(const SDL_Event *event) +{ + // We always store at least "type" and "timestamp". + int count = 2; + + switch (event->type) { + + case SDL_EVENT_AUDIO_DEVICE_ADDED: + case SDL_EVENT_AUDIO_DEVICE_REMOVED: + count += 2; // which, recording + break; + + case SDL_EVENT_DISPLAY_ORIENTATION: + case SDL_EVENT_DISPLAY_ADDED: + case SDL_EVENT_DISPLAY_REMOVED: + case SDL_EVENT_DISPLAY_MOVED: + case SDL_EVENT_DISPLAY_DESKTOP_MODE_CHANGED: + case SDL_EVENT_DISPLAY_CURRENT_MODE_CHANGED: + case SDL_EVENT_DISPLAY_CONTENT_SCALE_CHANGED: + count += 3; // which, data1, data2 + break; + + case SDL_EVENT_MOUSE_MOTION: + count += 5; + break; + + case SDL_EVENT_MOUSE_WHEEL: + // window, which, scroll, mouse => 4 extra + count += 4; + break; + + case SDL_EVENT_MOUSE_BUTTON_UP: + case SDL_EVENT_MOUSE_BUTTON_DOWN: + // window, which, down, button, clicks, mouse => 6 extra + count += 6; + break; + + case SDL_EVENT_SENSOR_UPDATE: + // which, sensor_timestamp => 2 extra + count += 2; + break; + + case SDL_EVENT_KEY_DOWN: + case SDL_EVENT_KEY_UP: + // window, which, down, repeat, key, scancode, mod => 7 extra + count += 7; + break; + + case SDL_EVENT_FINGER_MOTION: + case SDL_EVENT_FINGER_DOWN: + case SDL_EVENT_FINGER_UP: + // touch, finger, pos, d_pos, pressure, window => 6 extra + count += 6; + break; + + case SDL_EVENT_DROP_BEGIN: + case SDL_EVENT_DROP_FILE: + case SDL_EVENT_DROP_TEXT: + case SDL_EVENT_DROP_COMPLETE: + case SDL_EVENT_DROP_POSITION: + // window, pos, data, source => 4 extra + count += 4; + break; + + case SDL_EVENT_TEXT_INPUT: + // window, text, mod => 3 extra + count += 3; + break; + + case SDL_EVENT_CAMERA_DEVICE_APPROVED: + case SDL_EVENT_CAMERA_DEVICE_REMOVED: + case SDL_EVENT_CAMERA_DEVICE_ADDED: + case SDL_EVENT_CAMERA_DEVICE_DENIED: + // which => 1 extra + count += 1; + break; + + case SDL_EVENT_CLIPBOARD_UPDATE: + // owner => 1 extra + count += 1; + break; + + /* Window events (just group them all together) */ + case SDL_EVENT_WINDOW_SHOWN: + case SDL_EVENT_WINDOW_HIDDEN: + case SDL_EVENT_WINDOW_EXPOSED: + case SDL_EVENT_WINDOW_MOVED: + case SDL_EVENT_WINDOW_RESIZED: + case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED: + case SDL_EVENT_WINDOW_METAL_VIEW_RESIZED: + case SDL_EVENT_WINDOW_MINIMIZED: + case SDL_EVENT_WINDOW_MAXIMIZED: + case SDL_EVENT_WINDOW_RESTORED: + case SDL_EVENT_WINDOW_MOUSE_ENTER: + case SDL_EVENT_WINDOW_MOUSE_LEAVE: + case SDL_EVENT_WINDOW_FOCUS_GAINED: + case SDL_EVENT_WINDOW_FOCUS_LOST: + case SDL_EVENT_WINDOW_CLOSE_REQUESTED: + case SDL_EVENT_WINDOW_HIT_TEST: + case SDL_EVENT_WINDOW_ICCPROF_CHANGED: + case SDL_EVENT_WINDOW_DISPLAY_CHANGED: + case SDL_EVENT_WINDOW_DISPLAY_SCALE_CHANGED: + case SDL_EVENT_WINDOW_SAFE_AREA_CHANGED: + case SDL_EVENT_WINDOW_OCCLUDED: + case SDL_EVENT_WINDOW_ENTER_FULLSCREEN: + case SDL_EVENT_WINDOW_LEAVE_FULLSCREEN: + case SDL_EVENT_WINDOW_DESTROYED: + case SDL_EVENT_WINDOW_HDR_STATE_CHANGED: + // which, data1, data2 => 3 extra + count += 3; + break; + + case SDL_EVENT_JOYSTICK_ADDED: + case SDL_EVENT_JOYSTICK_REMOVED: + case SDL_EVENT_JOYSTICK_UPDATE_COMPLETE: + // which => 1 extra + count += 1; + break; + + case SDL_EVENT_JOYSTICK_AXIS_MOTION: + // which, axis, value => 3 extra + count += 3; + break; + + case SDL_EVENT_JOYSTICK_BALL_MOTION: + // which, ball, rel => 3 extra + count += 3; + break; + + case SDL_EVENT_JOYSTICK_BUTTON_DOWN: + case SDL_EVENT_JOYSTICK_BUTTON_UP: + // which, button, down => 3 extra + count += 3; + break; + + case SDL_EVENT_GAMEPAD_ADDED: + case SDL_EVENT_GAMEPAD_REMOVED: + case SDL_EVENT_GAMEPAD_REMAPPED: + case SDL_EVENT_GAMEPAD_UPDATE_COMPLETE: + case SDL_EVENT_GAMEPAD_STEAM_HANDLE_UPDATED: + // which => 1 extra + count += 1; + break; + + case SDL_EVENT_GAMEPAD_AXIS_MOTION: + // which, axis, value => 3 extra + count += 3; + break; + + case SDL_EVENT_GAMEPAD_BUTTON_DOWN: + case SDL_EVENT_GAMEPAD_BUTTON_UP: + // which, button, down => 3 extra + count += 3; + break; + + case SDL_EVENT_GAMEPAD_TOUCHPAD_DOWN: + case SDL_EVENT_GAMEPAD_TOUCHPAD_MOTION: + case SDL_EVENT_GAMEPAD_TOUCHPAD_UP: + // which, touchpad, finger, pos, pressure => 5 extra + count += 5; + break; + + case SDL_EVENT_GAMEPAD_SENSOR_UPDATE: + // which, sensor, sensor_timestamp => 3 extra + count += 3; + break; + + case SDL_EVENT_USER: + // cb => 1 extra + count += 1; + break; + } + + return count; +} + +static void event2wota_write(WotaBuffer *wb, const SDL_Event *e, int c) { + wota_write_record(wb, (unsigned long long)c); + wota_write_text(wb, "type"); + wota_write_text(wb, event_type_to_string(e->type)); + wota_write_text(wb, "timestamp"); + wota_write_number(wb, (double)e->common.timestamp); + switch(e->type) { + case SDL_EVENT_AUDIO_DEVICE_ADDED: + case SDL_EVENT_AUDIO_DEVICE_REMOVED: + wota_write_text(wb, "which"); + wota_write_number(wb, (double)e->adevice.which); + wota_write_text(wb, "recording"); + wota_write_sym(wb, e->adevice.recording ? WOTA_TRUE : WOTA_FALSE); + break; + case SDL_EVENT_DISPLAY_ORIENTATION: + case SDL_EVENT_DISPLAY_ADDED: + case SDL_EVENT_DISPLAY_REMOVED: + case SDL_EVENT_DISPLAY_MOVED: + case SDL_EVENT_DISPLAY_DESKTOP_MODE_CHANGED: + case SDL_EVENT_DISPLAY_CURRENT_MODE_CHANGED: + case SDL_EVENT_DISPLAY_CONTENT_SCALE_CHANGED: + wota_write_text(wb, "which"); + wota_write_number(wb, (double)e->display.displayID); + wota_write_text(wb, "data1"); + wota_write_number(wb, (double)e->display.data1); + wota_write_text(wb, "data2"); + wota_write_number(wb, (double)e->display.data2); + break; + case SDL_EVENT_MOUSE_MOTION: + wota_write_text(wb, "window"); + wota_write_number(wb, (double)e->motion.windowID); + wota_write_text(wb, "which"); + wota_write_number(wb, (double)e->motion.which); + wota_write_text(wb, "state"); + wota_write_number(wb, (double)e->motion.state); + wota_write_text(wb, "pos"); + wota_write_vec2(wb, (double)e->motion.x, (double)e->motion.y); + wota_write_text(wb, "d_pos"); + wota_write_vec2(wb, (double)e->motion.xrel, (double)e->motion.yrel); + break; + case SDL_EVENT_MOUSE_WHEEL: + wota_write_text(wb, "window"); + wota_write_number(wb, (double)e->wheel.windowID); + wota_write_text(wb, "which"); + wota_write_number(wb, (double)e->wheel.which); + wota_write_text(wb, "scroll"); + wota_write_vec2(wb, (double)e->wheel.x, (double)e->wheel.y); + wota_write_text(wb, "pos"); + wota_write_vec2(wb, (double)e->wheel.mouse_x, (double)e->wheel.mouse_y); + break; + case SDL_EVENT_MOUSE_BUTTON_UP: + case SDL_EVENT_MOUSE_BUTTON_DOWN: + wota_write_text(wb, "window"); + wota_write_number(wb, (double)e->button.windowID); + wota_write_text(wb, "which"); + wota_write_number(wb, (double)e->button.which); + wota_write_text(wb, "down"); + wota_write_sym(wb, e->button.down ? WOTA_TRUE : WOTA_FALSE); + wota_write_text(wb, "button"); + wota_write_text(wb, mouse_button_to_string(e->button.button)); + wota_write_text(wb, "clicks"); + wota_write_number(wb, (double)e->button.clicks); + wota_write_text(wb, "pos"); + wota_write_vec2(wb, (double)e->button.x, (double)e->button.y); + break; + case SDL_EVENT_SENSOR_UPDATE: + wota_write_text(wb, "which"); + wota_write_number(wb, (double)e->sensor.which); + wota_write_text(wb, "sensor_timestamp"); + wota_write_number(wb, (double)e->sensor.sensor_timestamp); + break; + case SDL_EVENT_KEY_DOWN: + case SDL_EVENT_KEY_UP: + wota_write_text(wb, "window"); + wota_write_number(wb, (double)e->key.windowID); + wota_write_text(wb, "which"); + wota_write_number(wb, (double)e->key.which); + wota_write_text(wb, "down"); + wota_write_sym(wb, e->key.down ? WOTA_TRUE : WOTA_FALSE); + wota_write_text(wb, "repeat"); + wota_write_sym(wb, e->key.repeat ? WOTA_TRUE : WOTA_FALSE); + wota_write_text(wb, "key"); + wota_write_number(wb, (double)e->key.key); + wota_write_text(wb, "scancode"); + wota_write_number(wb, (double)e->key.scancode); + wota_write_text(wb, "mod"); + wota_write_number(wb, 0); + break; + case SDL_EVENT_FINGER_MOTION: + case SDL_EVENT_FINGER_DOWN: + case SDL_EVENT_FINGER_UP: + wota_write_text(wb, "touch"); + wota_write_number(wb, (double)e->tfinger.touchID); + wota_write_text(wb, "finger"); + wota_write_number(wb, (double)e->tfinger.fingerID); + wota_write_text(wb, "pos"); + wota_write_vec2(wb, (double)e->tfinger.x, (double)e->tfinger.y); + wota_write_text(wb, "d_pos"); + wota_write_vec2(wb, (double)e->tfinger.dx, (double)e->tfinger.dy); + wota_write_text(wb, "pressure"); + wota_write_number(wb, (double)e->tfinger.pressure); + wota_write_text(wb, "window"); + wota_write_number(wb, (double)e->key.windowID); + break; + case SDL_EVENT_DROP_BEGIN: + case SDL_EVENT_DROP_FILE: + case SDL_EVENT_DROP_TEXT: + case SDL_EVENT_DROP_COMPLETE: + case SDL_EVENT_DROP_POSITION: + wota_write_text(wb, "window"); + wota_write_number(wb, (double)e->drop.windowID); + wota_write_text(wb, "pos"); + wota_write_vec2(wb, (double)e->drop.x, (double)e->drop.y); + wota_write_text(wb, "data"); + wota_write_text(wb, e->drop.data ? e->drop.data : ""); + wota_write_text(wb, "source"); + wota_write_text(wb, e->drop.source ? e->drop.source : ""); + break; + case SDL_EVENT_TEXT_INPUT: + wota_write_text(wb, "window"); + wota_write_number(wb, (double)e->text.windowID); + wota_write_text(wb, "text"); + wota_write_text(wb, e->text.text); + wota_write_text(wb, "mod"); + wota_write_number(wb, 0); + break; + case SDL_EVENT_CAMERA_DEVICE_APPROVED: + case SDL_EVENT_CAMERA_DEVICE_REMOVED: + case SDL_EVENT_CAMERA_DEVICE_ADDED: + case SDL_EVENT_CAMERA_DEVICE_DENIED: + wota_write_text(wb, "which"); + wota_write_number(wb, (double)e->cdevice.which); + break; + case SDL_EVENT_CLIPBOARD_UPDATE: + wota_write_text(wb, "owner"); + wota_write_sym(wb, e->clipboard.owner ? WOTA_TRUE : WOTA_FALSE); + break; + case SDL_EVENT_WINDOW_SHOWN: + case SDL_EVENT_WINDOW_HIDDEN: + case SDL_EVENT_WINDOW_EXPOSED: + case SDL_EVENT_WINDOW_MOVED: + case SDL_EVENT_WINDOW_RESIZED: + case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED: + case SDL_EVENT_WINDOW_METAL_VIEW_RESIZED: + case SDL_EVENT_WINDOW_MINIMIZED: + case SDL_EVENT_WINDOW_MAXIMIZED: + case SDL_EVENT_WINDOW_RESTORED: + case SDL_EVENT_WINDOW_MOUSE_ENTER: + case SDL_EVENT_WINDOW_MOUSE_LEAVE: + case SDL_EVENT_WINDOW_FOCUS_GAINED: + case SDL_EVENT_WINDOW_FOCUS_LOST: + case SDL_EVENT_WINDOW_CLOSE_REQUESTED: + case SDL_EVENT_WINDOW_HIT_TEST: + case SDL_EVENT_WINDOW_ICCPROF_CHANGED: + case SDL_EVENT_WINDOW_DISPLAY_CHANGED: + case SDL_EVENT_WINDOW_DISPLAY_SCALE_CHANGED: + case SDL_EVENT_WINDOW_SAFE_AREA_CHANGED: + case SDL_EVENT_WINDOW_OCCLUDED: + case SDL_EVENT_WINDOW_ENTER_FULLSCREEN: + case SDL_EVENT_WINDOW_LEAVE_FULLSCREEN: + case SDL_EVENT_WINDOW_DESTROYED: + case SDL_EVENT_WINDOW_HDR_STATE_CHANGED: + wota_write_text(wb, "which"); + wota_write_number(wb, (double)e->window.windowID); + wota_write_text(wb, "data1"); + wota_write_number(wb, (double)e->window.data1); + wota_write_text(wb, "data2"); + wota_write_number(wb, (double)e->window.data2); + break; + case SDL_EVENT_JOYSTICK_ADDED: + case SDL_EVENT_JOYSTICK_REMOVED: + case SDL_EVENT_JOYSTICK_UPDATE_COMPLETE: + wota_write_text(wb, "which"); + wota_write_number(wb, (double)e->jdevice.which); + break; + case SDL_EVENT_JOYSTICK_AXIS_MOTION: + wota_write_text(wb, "which"); + wota_write_number(wb, (double)e->jaxis.which); + wota_write_text(wb, "axis"); + wota_write_number(wb, (double)e->jaxis.axis); + wota_write_text(wb, "value"); + wota_write_number(wb, (double)e->jaxis.value); + break; + case SDL_EVENT_JOYSTICK_BALL_MOTION: + wota_write_text(wb, "which"); + wota_write_number(wb, (double)e->jball.which); + wota_write_text(wb, "ball"); + wota_write_number(wb, (double)e->jball.ball); + wota_write_text(wb, "rel"); + wota_write_vec2(wb, (double)e->jball.xrel, (double)e->jball.yrel); + break; + case SDL_EVENT_JOYSTICK_BUTTON_DOWN: + case SDL_EVENT_JOYSTICK_BUTTON_UP: + wota_write_text(wb, "which"); + wota_write_number(wb, (double)e->jbutton.which); + wota_write_text(wb, "button"); + wota_write_number(wb, (double)e->jbutton.button); + wota_write_text(wb, "down"); + wota_write_sym(wb, e->jbutton.down ? WOTA_TRUE : WOTA_FALSE); + break; + case SDL_EVENT_GAMEPAD_ADDED: + case SDL_EVENT_GAMEPAD_REMOVED: + case SDL_EVENT_GAMEPAD_REMAPPED: + case SDL_EVENT_GAMEPAD_UPDATE_COMPLETE: + case SDL_EVENT_GAMEPAD_STEAM_HANDLE_UPDATED: + wota_write_text(wb, "which"); + wota_write_number(wb, (double)e->gdevice.which); + break; + case SDL_EVENT_GAMEPAD_AXIS_MOTION: + wota_write_text(wb, "which"); + wota_write_number(wb, (double)e->gaxis.which); + wota_write_text(wb, "axis"); + wota_write_number(wb, (double)e->gaxis.axis); + wota_write_text(wb, "value"); + wota_write_number(wb, (double)e->gaxis.value); + break; + case SDL_EVENT_GAMEPAD_BUTTON_DOWN: + case SDL_EVENT_GAMEPAD_BUTTON_UP: + wota_write_text(wb, "which"); + wota_write_number(wb, (double)e->gbutton.which); + wota_write_text(wb, "button"); + wota_write_number(wb, (double)e->gbutton.button); + wota_write_text(wb, "down"); + wota_write_sym(wb, e->gbutton.down ? WOTA_TRUE : WOTA_FALSE); + break; + case SDL_EVENT_GAMEPAD_TOUCHPAD_DOWN: + case SDL_EVENT_GAMEPAD_TOUCHPAD_MOTION: + case SDL_EVENT_GAMEPAD_TOUCHPAD_UP: + wota_write_text(wb, "which"); + wota_write_number(wb, (double)e->gtouchpad.which); + wota_write_text(wb, "touchpad"); + wota_write_number(wb, (double)e->gtouchpad.touchpad); + wota_write_text(wb, "finger"); + wota_write_number(wb, (double)e->gtouchpad.finger); + wota_write_text(wb, "pos"); + wota_write_vec2(wb, (double)e->gtouchpad.x, (double)e->gtouchpad.y); + wota_write_text(wb, "pressure"); + wota_write_number(wb, (double)e->gtouchpad.pressure); + break; + case SDL_EVENT_GAMEPAD_SENSOR_UPDATE: + wota_write_text(wb, "which"); + wota_write_number(wb, (double)e->gsensor.which); + wota_write_text(wb, "sensor"); + wota_write_number(wb, (double)e->gsensor.sensor); + wota_write_text(wb, "sensor_timestamp"); + wota_write_number(wb, (double)e->gsensor.sensor_timestamp); + break; + case SDL_EVENT_USER: + wota_write_text(wb, "cb"); + wota_write_number(wb, (double)(uintptr_t)e->user.data1); + break; + } +} + +static WotaBuffer event2wota(const SDL_Event *event) { + WotaBuffer wb; + wota_buffer_init(&wb, 8); + int n = event2wota_count_props(event); + event2wota_write(&wb, event, n); + return wb; +} + +// Get all events directly from SDL event queue +JSC_CCALL(input_get_events, + JSValue events_array = JS_NewArray(js); + SDL_Event event; + int event_count = 0; + + while (SDL_PollEvent(&event)) { + WotaBuffer wb = event2wota(&event); + JSValue event_obj = wota2value(js, wb.data); + JS_SetPropertyUint32(js, events_array, event_count, event_obj); + wota_buffer_free(&wb); + event_count++; + } + + return events_array; +) + +static const JSCFunctionListEntry js_input_funcs[] = { + MIST_FUNC_DEF(input, mouse_show, 1), + MIST_FUNC_DEF(input, mouse_lock, 1), + MIST_FUNC_DEF(input, keyname, 1), + MIST_FUNC_DEF(input, keymod, 0), + MIST_FUNC_DEF(input, mousestate, 0), + MIST_FUNC_DEF(input, get_events, 0), +}; + +JSValue js_input_use(JSContext *js) { + JSValue mod = JS_NewObject(js); + JS_SetPropertyFunctionList(js,mod,js_input_funcs,countof(js_input_funcs)); + return mod; +} \ No newline at end of file diff --git a/source/qjs_sdl_input.h b/source/qjs_sdl_input.h new file mode 100644 index 00000000..d7eb749a --- /dev/null +++ b/source/qjs_sdl_input.h @@ -0,0 +1,18 @@ +#ifndef QJS_SDL_INPUT_H +#define QJS_SDL_INPUT_H + +#include +#include + +// Initialization and cleanup functions +void input_system_init(void); +void input_system_cleanup(void); + +// Event conversion functions +const char* event_type_to_string(Uint32 event_type); +const char* mouse_button_to_string(int mouse); + +// JavaScript module entry point +JSValue js_input_use(JSContext *js); + +#endif // QJS_SDL_INPUT_H \ No newline at end of file