From 5bb740f89e346d88d8b4bf63a3040a7561d3a841 Mon Sep 17 00:00:00 2001 From: Jamie Brandon Date: Fri, 1 Jul 2022 16:47:06 -0700 Subject: [PATCH] mach: flesh out mach.Event (#377) * Flesh out mach.Event --- src/platform/mach.js | 30 ++++++++---- src/platform/native.zig | 98 ++++++++++++++++++++++++++----------- src/platform/wasm.zig | 104 +++++++++++++++++++++++++++++++++------- src/structs.zig | 52 ++++++++++++++------ 4 files changed, 218 insertions(+), 66 deletions(-) diff --git a/src/platform/mach.js b/src/platform/mach.js index e8bde028..b105ac75 100644 --- a/src/platform/mach.js +++ b/src/platform/mach.js @@ -196,29 +196,41 @@ const mach = { canvas.addEventListener("contextmenu", (ev) => ev.preventDefault()); canvas.addEventListener("keydown", (ev) => { - mach.events.push(...[1, convertKeyCode(ev.code)]); + if (ev.repeat) { + mach.events.push(...[2, convertKeyCode(ev.code)]); + } else { + mach.events.push(...[1, convertKeyCode(ev.code)]); + } }); canvas.addEventListener("keyup", (ev) => { - mach.events.push(...[2, convertKeyCode(ev.code)]); + mach.events.push(...[3, convertKeyCode(ev.code)]); }); canvas.addEventListener("mousemove", (ev) => { - mach.events.push(...[3, ev.clientX, ev.clientY]); + mach.events.push(...[4, ev.clientX, ev.clientY]); }); canvas.addEventListener("mousedown", (ev) => { - mach.events.push(...[4, ev.button]); - }); - - canvas.addEventListener("mouseup", (ev) => { mach.events.push(...[5, ev.button]); }); - canvas.addEventListener("wheel", (ev) => { - mach.events.push(...[6, ev.deltaX, ev.deltaY]); + canvas.addEventListener("mouseup", (ev) => { + mach.events.push(...[6, ev.button]); }); + canvas.addEventListener("wheel", (ev) => { + mach.events.push(...[7, ev.deltaX, ev.deltaY]); + }); + + canvas.addEventListener("focus", (ev) => { + mach.events.push(...[8]); + }); + + canvas.addEventListener("blur", (ev) => { + mach.events.push(...[9]); + }); + canvas.addEventListener("mach-canvas-resize", (ev) => { const cv_index = mach.canvases.findIndex((el) => el.canvas === ev.currentTarget); const cv = mach.canvases[cv_index]; diff --git a/src/platform/native.zig b/src/platform/native.zig index 2d650c84..9ce7c99c 100644 --- a/src/platform/native.zig +++ b/src/platform/native.zig @@ -29,6 +29,8 @@ pub const Platform = struct { native_instance: gpu.NativeInstance, + last_cursor_position: structs.WindowPos, + const EventQueue = std.TailQueue(structs.Event); const EventNode = EventQueue.Node; @@ -180,6 +182,8 @@ pub const Platform = struct { engine.current_desc = descriptor; engine.target_desc = descriptor; + const cursor_pos = try window.getCursorPos(); + return Platform{ .window = window, .backend_type = backend_type, @@ -187,6 +191,10 @@ pub const Platform = struct { .last_window_size = .{ .width = window_size.width, .height = window_size.height }, .last_framebuffer_size = .{ .width = framebuffer_size.width, .height = framebuffer_size.height }, .last_position = try window.getPos(), + .last_cursor_position = .{ + .x = cursor_pos.xpos, + .y = cursor_pos.ypos, + }, .native_instance = native_instance, }; } @@ -210,37 +218,48 @@ pub const Platform = struct { platform.window.setUserPointer(&platform.user_ptr); - const callback = struct { + const key_callback = struct { fn callback(window: glfw.Window, key: glfw.Key, scancode: i32, action: glfw.Action, mods: glfw.Mods) void { const pf = (window.getUserPointer(UserPtr) orelse unreachable).platform; - + const key_event = structs.KeyEvent{ + .key = toMachKey(key), + .mods = toMachMods(mods), + }; switch (action) { - .press => pf.pushEvent(.{ - .key_press = .{ - .key = toMachKey(key), - }, - }), - .release => pf.pushEvent(.{ - .key_release = .{ - .key = toMachKey(key), - }, - }), - else => {}, + .press => pf.pushEvent(.{ .key_press = key_event }), + .repeat => pf.pushEvent(.{ .key_repeat = key_event }), + .release => pf.pushEvent(.{ .key_release = key_event }), } - _ = scancode; - _ = mods; } }.callback; - platform.window.setKeyCallback(callback); + platform.window.setKeyCallback(key_callback); + + const char_callback = struct { + fn callback(window: glfw.Window, codepoint: u21) void { + const pf = (window.getUserPointer(UserPtr) orelse unreachable).platform; + pf.pushEvent(.{ + .char_input = .{ + .codepoint = codepoint, + }, + }); + } + }.callback; + platform.window.setCharCallback(char_callback); const mouse_motion_callback = struct { fn callback(window: glfw.Window, xpos: f64, ypos: f64) void { const pf = (window.getUserPointer(UserPtr) orelse unreachable).platform; + pf.last_cursor_position = .{ + .x = xpos, + .y = ypos, + }; pf.pushEvent(.{ .mouse_motion = .{ - .x = xpos, - .y = ypos, + .pos = .{ + .x = xpos, + .y = ypos, + }, }, }); } @@ -250,17 +269,15 @@ pub const Platform = struct { const mouse_button_callback = struct { fn callback(window: glfw.Window, button: glfw.mouse_button.MouseButton, action: glfw.Action, mods: glfw.Mods) void { const pf = (window.getUserPointer(UserPtr) orelse unreachable).platform; - + const mouse_button_event = structs.MouseButtonEvent{ + .button = toMachButton(button), + .pos = pf.last_cursor_position, + .mods = toMachMods(mods), + }; switch (action) { - .press => pf.pushEvent(.{ - .mouse_press = .{ - .button = toMachButton(button), - }, - }), + .press => pf.pushEvent(.{ .mouse_press = mouse_button_event }), .release => pf.pushEvent(.{ - .mouse_release = .{ - .button = toMachButton(button), - }, + .mouse_release = mouse_button_event, }), else => {}, } @@ -283,6 +300,22 @@ pub const Platform = struct { }.callback; platform.window.setScrollCallback(scroll_callback); + const focus_callback = struct { + fn callback(window: glfw.Window, focused: bool) void { + const pf = (window.getUserPointer(UserPtr) orelse unreachable).platform; + pf.pushEvent(if (focused) .focus_gained else .focus_lost); + } + }.callback; + platform.window.setFocusCallback(focus_callback); + + const close_callback = struct { + fn callback(window: glfw.Window) void { + const pf = (window.getUserPointer(UserPtr) orelse unreachable).platform; + pf.pushEvent(.closed); + } + }.callback; + platform.window.setCloseCallback(close_callback); + const size_callback = struct { fn callback(window: glfw.Window, width: i32, height: i32) void { const pf = (window.getUserPointer(UserPtr) orelse unreachable).platform; @@ -526,6 +559,17 @@ pub const Platform = struct { }; } + fn toMachMods(mods: glfw.Mods) structs.KeyMods { + return .{ + .shift = mods.shift, + .control = mods.control, + .alt = mods.alt, + .super = mods.super, + .caps_lock = mods.caps_lock, + .num_lock = mods.num_lock, + }; + } + /// Default GLFW error handling callback fn errorCallback(error_code: glfw.Error, description: [:0]const u8) void { std.debug.print("glfw: {}: {s}\n", .{ error_code, description }); diff --git a/src/platform/wasm.zig b/src/platform/wasm.zig index 13da5883..6bae74ab 100644 --- a/src/platform/wasm.zig +++ b/src/platform/wasm.zig @@ -38,6 +38,9 @@ pub const Platform = struct { last_window_size: structs.Size, last_framebuffer_size: structs.Size, + last_cursor_position: structs.WindowPos, + last_key_mods: structs.KeyMods, + pub fn init(allocator: std.mem.Allocator, eng: *Engine) !Platform { var selector = [1]u8{0} ** 15; const id = js.machCanvasInit(&selector[0]); @@ -53,6 +56,20 @@ pub const Platform = struct { .width = js.machCanvasGetFramebufferWidth(id), .height = js.machCanvasGetFramebufferHeight(id), }, + + // TODO initialize these properly + .last_cursor_position = .{ + .x = 0, + .y = 0, + }, + .last_key_mods = .{ + .shift = false, + .control = false, + .alt = false, + .super = false, + .caps_lock = false, + .num_lock = false, + }, }; try platform.setOptions(eng.options); @@ -117,38 +134,93 @@ pub const Platform = struct { return js.machHasEvent(); } - pub fn pollEvent(_: *Platform) ?structs.Event { + pub fn pollEvent(platform: *Platform) ?structs.Event { const event_type = js.machEventShift(); return switch (event_type) { - 1 => structs.Event{ - .key_press = .{ .key = @intToEnum(enums.Key, js.machEventShift()) }, + 1, 2 => key_down: { + const key = @intToEnum(enums.Key, js.machEventShift()); + switch (key) { + .left_shift, .right_shift => platform.last_key_mods.shift = true, + .left_control, .right_control => platform.last_key_mods.control = true, + .left_alt, .right_alt => platform.last_key_mods.alt = true, + .left_super, .right_super => platform.last_key_mods.super = true, + .caps_lock => platform.last_key_mods.caps_lock = true, + .num_lock => platform.last_key_mods.num_lock = true, + else => {}, + } + break :key_down switch (event_type) { + 1 => structs.Event{ + .key_press = .{ + .key = key, + .mods = platform.last_key_mods, + }, + }, + 2 => structs.Event{ + .key_repeat = .{ + .key = key, + .mods = platform.last_key_mods, + }, + }, + else => unreachable, + }; }, - 2 => structs.Event{ - .key_release = .{ .key = @intToEnum(enums.Key, js.machEventShift()) }, + 3 => key_release: { + const key = @intToEnum(enums.Key, js.machEventShift()); + switch (key) { + .left_shift, .right_shift => platform.last_key_mods.shift = false, + .left_control, .right_control => platform.last_key_mods.control = false, + .left_alt, .right_alt => platform.last_key_mods.alt = false, + .left_super, .right_super => platform.last_key_mods.super = false, + .caps_lock => platform.last_key_mods.caps_lock = false, + .num_lock => platform.last_key_mods.num_lock = false, + else => {}, + } + break :key_release structs.Event{ + .key_release = .{ + .key = key, + .mods = platform.last_key_mods, + }, + }; }, - 3 => structs.Event{ - .mouse_motion = .{ - .x = @intToFloat(f64, js.machEventShift()), - .y = @intToFloat(f64, js.machEventShift()), - }, - }, - 4 => structs.Event{ - .mouse_press = .{ - .button = toMachButton(js.machEventShift()), - }, + 4 => mouse_motion: { + const x = @intToFloat(f64, js.machEventShift()); + const y = @intToFloat(f64, js.machEventShift()); + platform.last_cursor_position = .{ + .x = x, + .y = y, + }; + break :mouse_motion structs.Event{ + .mouse_motion = .{ + .pos = .{ + .x = x, + .y = y, + }, + }, + }; }, 5 => structs.Event{ - .mouse_release = .{ + .mouse_press = .{ .button = toMachButton(js.machEventShift()), + .pos = platform.last_cursor_position, + .mods = platform.last_key_mods, }, }, 6 => structs.Event{ + .mouse_release = .{ + .button = toMachButton(js.machEventShift()), + .pos = platform.last_cursor_position, + .mods = platform.last_key_mods, + }, + }, + 7 => structs.Event{ .mouse_scroll = .{ .xoffset = @floatCast(f32, sign(js.machEventShiftFloat())), .yoffset = @floatCast(f32, sign(js.machEventShiftFloat())), }, }, + 8 => structs.Event.focus_gained, + 9 => structs.Event.focus_lost, else => null, }; } diff --git a/src/structs.zig b/src/structs.zig index 512377ab..c2eb7579 100644 --- a/src/structs.zig +++ b/src/structs.zig @@ -48,25 +48,49 @@ pub const Options = struct { }; pub const Event = union(enum) { - key_press: struct { - key: enums.Key, - }, - key_release: struct { - key: enums.Key, + key_press: KeyEvent, + key_repeat: KeyEvent, + key_release: KeyEvent, + char_input: struct { + codepoint: u21, }, mouse_motion: struct { - // These are in window coordinates (not framebuffer coords) - x: f64, - y: f64, - }, - mouse_press: struct { - button: enums.MouseButton, - }, - mouse_release: struct { - button: enums.MouseButton, + pos: WindowPos, }, + mouse_press: MouseButtonEvent, + mouse_release: MouseButtonEvent, mouse_scroll: struct { xoffset: f32, yoffset: f32, }, + focus_gained, + focus_lost, + closed, +}; + +pub const KeyEvent = struct { + key: enums.Key, + mods: KeyMods, +}; + +pub const MouseButtonEvent = struct { + button: enums.MouseButton, + pos: WindowPos, + mods: KeyMods, +}; + +pub const KeyMods = packed struct { + shift: bool, + control: bool, + alt: bool, + super: bool, + caps_lock: bool, + num_lock: bool, + _reserved: u2 = 0, +}; + +pub const WindowPos = struct { + // These are in window coordinates (not framebuffer coords) + x: f64, + y: f64, };