core: darwin: More input callbacks, correct framebuffer/window sizes, core has responsibility of swapchain
This commit is contained in:
parent
a10cbc3419
commit
98c303aefc
2 changed files with 178 additions and 209 deletions
239
src/Core.zig
239
src/Core.zig
|
|
@ -209,8 +209,8 @@ pub fn initWindow(core: *Core, window_id: mach.ObjectID) !void {
|
||||||
.label = "main swap chain",
|
.label = "main swap chain",
|
||||||
.usage = core_window.swap_chain_usage,
|
.usage = core_window.swap_chain_usage,
|
||||||
.format = .bgra8_unorm,
|
.format = .bgra8_unorm,
|
||||||
.width = core_window.width,
|
.width = core_window.framebuffer_width,
|
||||||
.height = core_window.height,
|
.height = core_window.framebuffer_height,
|
||||||
.present_mode = switch (core_window.vsync_mode) {
|
.present_mode = switch (core_window.vsync_mode) {
|
||||||
.none => .immediate,
|
.none => .immediate,
|
||||||
.double => .fifo,
|
.double => .fifo,
|
||||||
|
|
@ -218,10 +218,6 @@ pub fn initWindow(core: *Core, window_id: mach.ObjectID) !void {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
core_window.swap_chain = core_window.device.createSwapChain(core_window.surface, &core_window.swap_chain_descriptor);
|
core_window.swap_chain = core_window.device.createSwapChain(core_window.surface, &core_window.swap_chain_descriptor);
|
||||||
core_window.framebuffer_format = core_window.swap_chain_descriptor.format;
|
|
||||||
core_window.framebuffer_width = core_window.swap_chain_descriptor.width;
|
|
||||||
core_window.framebuffer_height = core_window.swap_chain_descriptor.height;
|
|
||||||
|
|
||||||
core.pushEvent(.{ .window_open = .{ .window_id = window_id } });
|
core.pushEvent(.{ .window_open = .{ .window_id = window_id } });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -236,6 +232,32 @@ pub fn tick(core: *Core, core_mod: mach.Mod(Core)) !void {
|
||||||
core_mod.call(.presentFrame);
|
core_mod.call(.presentFrame);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn presentFrame(core: *Core, core_mod: mach.Mod(Core)) !void {
|
||||||
|
var windows = core.windows.slice();
|
||||||
|
while (windows.next()) |window_id| {
|
||||||
|
var core_window = core.windows.getValue(window_id);
|
||||||
|
defer core.windows.setValueRaw(window_id, core_window);
|
||||||
|
|
||||||
|
mach.sysgpu.Impl.deviceTick(core_window.device);
|
||||||
|
|
||||||
|
core_window.swap_chain.present();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Record to frame rate frequency monitor that a frame was finished.
|
||||||
|
core.frame.tick();
|
||||||
|
|
||||||
|
switch (core.state) {
|
||||||
|
.running => {},
|
||||||
|
.exiting => {
|
||||||
|
core.state = .deinitializing;
|
||||||
|
core_mod.run(core.on_exit.?);
|
||||||
|
core_mod.call(.deinit);
|
||||||
|
},
|
||||||
|
.deinitializing => {},
|
||||||
|
.exited => @panic("application not running"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn main(core: *Core, core_mod: mach.Mod(Core)) !void {
|
pub fn main(core: *Core, core_mod: mach.Mod(Core)) !void {
|
||||||
if (core.on_tick == null) @panic("core.on_tick callback must be set");
|
if (core.on_tick == null) @panic("core.on_tick callback must be set");
|
||||||
if (core.on_exit == null) @panic("core.on_exit callback must be set");
|
if (core.on_exit == null) @panic("core.on_exit callback must be set");
|
||||||
|
|
@ -286,11 +308,14 @@ fn platform_update_callback(core: *Core, core_mod: mach.Mod(Core)) !bool {
|
||||||
|
|
||||||
core_mod.run(core.on_tick.?);
|
core_mod.run(core.on_tick.?);
|
||||||
core_mod.call(.presentFrame);
|
core_mod.call(.presentFrame);
|
||||||
//core_mod.call(.processWindowUpdates);
|
|
||||||
|
|
||||||
return core.state != .exited;
|
return core.state != .exited;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn exit(core: *Core) void {
|
||||||
|
core.state = .exiting;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn deinit(core: *Core) !void {
|
pub fn deinit(core: *Core) !void {
|
||||||
core.state = .exited;
|
core.state = .exited;
|
||||||
|
|
||||||
|
|
@ -369,206 +394,6 @@ pub fn mousePosition(core: *@This()) Position {
|
||||||
return core.input_state.mouse_position;
|
return core.input_state.mouse_position;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(object)
|
|
||||||
// /// Set refresh rate synchronization mode. Default `.triple`
|
|
||||||
// ///
|
|
||||||
// /// Calling this function also implicitly calls setFrameRateLimit for you:
|
|
||||||
// /// ```
|
|
||||||
// /// .none => setFrameRateLimit(0) // unlimited
|
|
||||||
// /// .double => setFrameRateLimit(0) // unlimited
|
|
||||||
// /// .triple => setFrameRateLimit(2 * max_monitor_refresh_rate)
|
|
||||||
// /// ```
|
|
||||||
// pub inline fn setVSync(core: *@This(), mode: VSyncMode) void {
|
|
||||||
// return core.platform.setVSync(mode);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// TODO(object)
|
|
||||||
// /// Returns refresh rate synchronization mode.
|
|
||||||
// pub inline fn vsync(core: *@This()) VSyncMode {
|
|
||||||
// return core.platform.vsync_mode;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// TODO(object)
|
|
||||||
// /// Sets the frame rate limit. Default 0 (unlimited)
|
|
||||||
// ///
|
|
||||||
// /// This is applied *in addition* to the vsync mode.
|
|
||||||
// pub inline fn setFrameRateLimit(core: *@This(), limit: u32) void {
|
|
||||||
// core.frame.target = limit;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// TODO(object)
|
|
||||||
// /// Returns the frame rate limit, or zero if unlimited.
|
|
||||||
// pub inline fn frameRateLimit(core: *@This()) u32 {
|
|
||||||
// return core.frame.target;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// TODO(object)
|
|
||||||
// /// Set the window size, in subpixel units.
|
|
||||||
// pub inline fn setSize(core: *@This(), value: Size) void {
|
|
||||||
// return core.platform.setSize(value);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// TODO(object)
|
|
||||||
// /// Returns the window size, in subpixel units.
|
|
||||||
// pub inline fn size(core: *@This()) Size {
|
|
||||||
// return core.platform.size;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// TODO(object)
|
|
||||||
// pub inline fn setCursorMode(core: *@This(), mode: CursorMode) void {
|
|
||||||
// return core.platform.setCursorMode(mode);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// TODO(object)
|
|
||||||
// pub inline fn cursorMode(core: *@This()) CursorMode {
|
|
||||||
// return core.platform.cursorMode();
|
|
||||||
// }
|
|
||||||
|
|
||||||
// TODO(object)
|
|
||||||
// pub inline fn setCursorShape(core: *@This(), cursor: CursorShape) void {
|
|
||||||
// return core.platform.setCursorShape(cursor);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// TODO(object)
|
|
||||||
// pub inline fn cursorShape(core: *@This()) CursorShape {
|
|
||||||
// return core.platform.cursorShape();
|
|
||||||
// }
|
|
||||||
|
|
||||||
// TODO(object)
|
|
||||||
// /// Sets the minimum target frequency of the input handling thread.
|
|
||||||
// ///
|
|
||||||
// /// Input handling (the main thread) runs at a variable frequency. The thread blocks until there are
|
|
||||||
// /// input events available, or until it needs to unblock in order to achieve the minimum target
|
|
||||||
// /// frequency which is your collaboration point of opportunity with the main thread.
|
|
||||||
// ///
|
|
||||||
// /// For example, by default (`setInputFrequency(1)`) mach-core will aim to invoke `updateMainThread`
|
|
||||||
// /// at least once per second (but potentially much more, e.g. once per every mouse movement or
|
|
||||||
// /// keyboard button press.) If you were to increase the input frequency to say 60hz e.g.
|
|
||||||
// /// `setInputFrequency(60)` then mach-core will aim to invoke your `updateMainThread` 60 times per
|
|
||||||
// /// second.
|
|
||||||
// ///
|
|
||||||
// /// An input frequency of zero implies unlimited, in which case the main thread will busy-wait.
|
|
||||||
// ///
|
|
||||||
// /// # Multithreaded mach-core behavior
|
|
||||||
// ///
|
|
||||||
// /// On some platforms, mach-core is able to handle input and rendering independently for
|
|
||||||
// /// improved performance and responsiveness.
|
|
||||||
// ///
|
|
||||||
// /// | Platform | Threading |
|
|
||||||
// /// |----------|-----------------|
|
|
||||||
// /// | Desktop | Multi threaded |
|
|
||||||
// /// | Browser | Single threaded |
|
|
||||||
// /// | Mobile | TBD |
|
|
||||||
// ///
|
|
||||||
// /// On single-threaded platforms, `update` and the (optional) `updateMainThread` callback are
|
|
||||||
// /// invoked in sequence, one after the other, on the same thread.
|
|
||||||
// ///
|
|
||||||
// /// On multi-threaded platforms, `init` and `deinit` are called on the main thread, while `update`
|
|
||||||
// /// is called on a separate rendering thread. The (optional) `updateMainThread` callback can be
|
|
||||||
// /// used in cases where you must run a function on the main OS thread (such as to open a native
|
|
||||||
// /// file dialog on macOS, since many system GUI APIs must be run on the main OS thread.) It is
|
|
||||||
// /// advised you do not use this callback to run any code except when absolutely neccessary, as
|
|
||||||
// /// it is in direct contention with input handling.
|
|
||||||
// ///
|
|
||||||
// /// APIs which are not accessible from a specific thread are declared as such, otherwise can be
|
|
||||||
// /// called from any thread as they are internally synchronized.
|
|
||||||
// pub inline fn setInputFrequency(core: *@This(), input_frequency: u32) void {
|
|
||||||
// core.input.target = input_frequency;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// TODO(object)
|
|
||||||
// /// Returns the input frequency, or zero if unlimited (busy-waiting mode)
|
|
||||||
// pub inline fn inputFrequency(core: *@This()) u32 {
|
|
||||||
// return core.input.target;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// TODO(object)
|
|
||||||
// /// Returns the actual number of frames rendered (`update` calls that returned) in the last second.
|
|
||||||
// ///
|
|
||||||
// /// This is updated once per second.
|
|
||||||
// pub inline fn frameRate(core: *@This()) u32 {
|
|
||||||
// return core.frame.rate;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// TODO(object)
|
|
||||||
// /// Returns the actual number of input thread iterations in the last second. See setInputFrequency
|
|
||||||
// /// for what this means.
|
|
||||||
// ///
|
|
||||||
// /// This is updated once per second.
|
|
||||||
// pub inline fn inputRate(core: *@This()) u32 {
|
|
||||||
// return core.input.rate;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// TODO(object)
|
|
||||||
// /// Returns the underlying native NSWindow pointer
|
|
||||||
// ///
|
|
||||||
// /// May only be called on macOS.
|
|
||||||
// pub fn nativeWindowCocoa(core: *@This()) *anyopaque {
|
|
||||||
// return core.platform.nativeWindowCocoa();
|
|
||||||
// }
|
|
||||||
|
|
||||||
// TODO(object)
|
|
||||||
// /// Returns the underlying native Windows' HWND pointer
|
|
||||||
// ///
|
|
||||||
// /// May only be called on Windows.
|
|
||||||
// pub fn nativeWindowWin32(core: *@This()) std.os.windows.HWND {
|
|
||||||
// return core.platform.nativeWindowWin32();
|
|
||||||
// }
|
|
||||||
|
|
||||||
pub fn presentFrame(core: *Core, core_mod: mach.Mod(Core)) !void {
|
|
||||||
var windows = core.windows.slice();
|
|
||||||
while (windows.next()) |window_id| {
|
|
||||||
var core_window = core.windows.getValue(window_id);
|
|
||||||
defer core.windows.setValueRaw(window_id, core_window);
|
|
||||||
|
|
||||||
mach.sysgpu.Impl.deviceTick(core_window.device);
|
|
||||||
|
|
||||||
core_window.swap_chain.present();
|
|
||||||
|
|
||||||
// Update swapchain for the next frame
|
|
||||||
if (core_window.swap_chain_update.isSet()) blk: {
|
|
||||||
core_window.swap_chain_update.reset();
|
|
||||||
|
|
||||||
switch (core_window.vsync_mode) {
|
|
||||||
.triple => core.frame.target = 2 * core_window.refresh_rate,
|
|
||||||
else => core.frame.target = 0,
|
|
||||||
}
|
|
||||||
|
|
||||||
if (core_window.width == 0 or core_window.height == 0) break :blk;
|
|
||||||
|
|
||||||
core_window.swap_chain_descriptor.present_mode = switch (core_window.vsync_mode) {
|
|
||||||
.none => .immediate,
|
|
||||||
.double => .fifo,
|
|
||||||
.triple => .mailbox,
|
|
||||||
};
|
|
||||||
|
|
||||||
core_window.swap_chain_descriptor.width = core_window.width;
|
|
||||||
core_window.swap_chain_descriptor.height = core_window.height;
|
|
||||||
core_window.swap_chain.release();
|
|
||||||
|
|
||||||
core_window.swap_chain = core_window.device.createSwapChain(core_window.surface, &core_window.swap_chain_descriptor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Record to frame rate frequency monitor that a frame was finished.
|
|
||||||
core.frame.tick();
|
|
||||||
|
|
||||||
switch (core.state) {
|
|
||||||
.running => {},
|
|
||||||
.exiting => {
|
|
||||||
core.state = .deinitializing;
|
|
||||||
core_mod.run(core.on_exit.?);
|
|
||||||
core_mod.call(.deinit);
|
|
||||||
},
|
|
||||||
.deinitializing => {},
|
|
||||||
.exited => @panic("application not running"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn exit(core: *Core) void {
|
|
||||||
core.state = .exiting;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline fn requestAdapterCallback(
|
inline fn requestAdapterCallback(
|
||||||
context: *RequestAdapterResponse,
|
context: *RequestAdapterResponse,
|
||||||
status: gpu.RequestAdapterStatus,
|
status: gpu.RequestAdapterStatus,
|
||||||
|
|
|
||||||
|
|
@ -165,9 +165,19 @@ fn initWindow(
|
||||||
screen,
|
screen,
|
||||||
);
|
);
|
||||||
if (native_window_opt) |native_window| {
|
if (native_window_opt) |native_window| {
|
||||||
|
const framebuffer_scale: f32 = @floatCast(native_window.backingScaleFactor());
|
||||||
|
const window_width: f32 = @floatFromInt(core_window.width);
|
||||||
|
const window_height: f32 = @floatFromInt(core_window.height);
|
||||||
|
|
||||||
|
core_window.framebuffer_width = @intFromFloat(window_width * framebuffer_scale);
|
||||||
|
core_window.framebuffer_height = @intFromFloat(window_height * framebuffer_scale);
|
||||||
|
|
||||||
native_window.setReleasedWhenClosed(false);
|
native_window.setReleasedWhenClosed(false);
|
||||||
|
|
||||||
var view = objc.mach.View.allocInit();
|
var view = objc.mach.View.allocInit();
|
||||||
|
|
||||||
|
// initWithFrame is overridden in our MACHView, which creates a tracking area for mouse tracking
|
||||||
|
view = view.initWithFrame(rect);
|
||||||
view.setLayer(@ptrCast(layer));
|
view.setLayer(@ptrCast(layer));
|
||||||
|
|
||||||
const context = try core.allocator.create(Context);
|
const context = try core.allocator.create(Context);
|
||||||
|
|
@ -190,6 +200,46 @@ fn initWindow(
|
||||||
null,
|
null,
|
||||||
);
|
);
|
||||||
view.setBlock_keyUp(keyUp.asBlock().copy());
|
view.setBlock_keyUp(keyUp.asBlock().copy());
|
||||||
|
|
||||||
|
var flagsChanged = objc.foundation.stackBlockLiteral(
|
||||||
|
ViewCallbacks.flagsChanged,
|
||||||
|
context,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
view.setBlock_flagsChanged(flagsChanged.asBlock().copy());
|
||||||
|
|
||||||
|
var mouseMoved = objc.foundation.stackBlockLiteral(
|
||||||
|
ViewCallbacks.mouseMoved,
|
||||||
|
context,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
view.setBlock_mouseMoved(mouseMoved.asBlock().copy());
|
||||||
|
|
||||||
|
var mouseDown = objc.foundation.stackBlockLiteral(
|
||||||
|
ViewCallbacks.mouseDown,
|
||||||
|
context,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
view.setBlock_mouseDown(mouseDown.asBlock().copy());
|
||||||
|
|
||||||
|
var mouseUp = objc.foundation.stackBlockLiteral(
|
||||||
|
ViewCallbacks.mouseUp,
|
||||||
|
context,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
view.setBlock_mouseUp(mouseUp.asBlock().copy());
|
||||||
|
|
||||||
|
var scrollWheel = objc.foundation.stackBlockLiteral(
|
||||||
|
ViewCallbacks.scrollWheel,
|
||||||
|
context,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
view.setBlock_scrollWheel(scrollWheel.asBlock().copy());
|
||||||
}
|
}
|
||||||
native_window.setContentView(@ptrCast(view));
|
native_window.setContentView(@ptrCast(view));
|
||||||
native_window.center();
|
native_window.center();
|
||||||
|
|
@ -261,12 +311,23 @@ const WindowDelegateCallbacks = struct {
|
||||||
const native_window: *objc.app_kit.Window = native.window;
|
const native_window: *objc.app_kit.Window = native.window;
|
||||||
|
|
||||||
const frame = native_window.frame();
|
const frame = native_window.frame();
|
||||||
|
|
||||||
const content_rect = native_window.contentRectForFrameRect(frame);
|
const content_rect = native_window.contentRectForFrameRect(frame);
|
||||||
|
|
||||||
core_window.width = @intFromFloat(content_rect.size.width);
|
core_window.width = @intFromFloat(content_rect.size.width);
|
||||||
core_window.height = @intFromFloat(content_rect.size.height);
|
core_window.height = @intFromFloat(content_rect.size.height);
|
||||||
core_window.swap_chain_update.set();
|
|
||||||
|
const framebuffer_scale: f32 = @floatCast(native_window.backingScaleFactor());
|
||||||
|
const window_width: f32 = @floatFromInt(core_window.width);
|
||||||
|
const window_height: f32 = @floatFromInt(core_window.height);
|
||||||
|
|
||||||
|
core_window.framebuffer_width = @intFromFloat(window_width * framebuffer_scale);
|
||||||
|
core_window.framebuffer_height = @intFromFloat(window_height * framebuffer_scale);
|
||||||
|
|
||||||
|
core_window.swap_chain_descriptor.width = core_window.framebuffer_width;
|
||||||
|
core_window.swap_chain_descriptor.height = core_window.framebuffer_height;
|
||||||
|
core_window.swap_chain.release();
|
||||||
|
|
||||||
|
core_window.swap_chain = core_window.device.createSwapChain(core_window.surface, &core_window.swap_chain_descriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
core.windows.setValueRaw(block.context.window_id, core_window);
|
core.windows.setValueRaw(block.context.window_id, core_window);
|
||||||
|
|
@ -288,6 +349,62 @@ const WindowDelegateCallbacks = struct {
|
||||||
};
|
};
|
||||||
|
|
||||||
const ViewCallbacks = struct {
|
const ViewCallbacks = struct {
|
||||||
|
pub fn mouseMoved(block: *objc.foundation.BlockLiteral(*Context), event: *objc.app_kit.Event) callconv(.C) void {
|
||||||
|
const core: *Core = block.context.core;
|
||||||
|
const window_id = block.context.window_id;
|
||||||
|
|
||||||
|
const mouse_location = event.locationInWindow();
|
||||||
|
|
||||||
|
const window_height: f32 = @floatFromInt(core.windows.get(window_id, .height));
|
||||||
|
|
||||||
|
core.pushEvent(.{ .mouse_motion = .{
|
||||||
|
.window_id = window_id,
|
||||||
|
.pos = .{ .x = mouse_location.x, .y = window_height - mouse_location.y },
|
||||||
|
} });
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mouseDown(block: *objc.foundation.BlockLiteral(*Context), event: *objc.app_kit.Event) callconv(.C) void {
|
||||||
|
const core: *Core = block.context.core;
|
||||||
|
const window_id = block.context.window_id;
|
||||||
|
|
||||||
|
core.pushEvent(.{ .mouse_press = .{
|
||||||
|
.window_id = window_id,
|
||||||
|
.button = @enumFromInt(event.buttonNumber()),
|
||||||
|
.pos = .{ .x = event.locationInWindow().x, .y = event.locationInWindow().y },
|
||||||
|
.mods = machModifierFromModifierFlag(event.modifierFlags()),
|
||||||
|
} });
|
||||||
|
}
|
||||||
|
pub fn mouseUp(block: *objc.foundation.BlockLiteral(*Context), event: *objc.app_kit.Event) callconv(.C) void {
|
||||||
|
const core: *Core = block.context.core;
|
||||||
|
const window_id = block.context.window_id;
|
||||||
|
|
||||||
|
core.pushEvent(.{ .mouse_release = .{
|
||||||
|
.window_id = window_id,
|
||||||
|
.button = @enumFromInt(event.buttonNumber()),
|
||||||
|
.pos = .{ .x = event.locationInWindow().x, .y = event.locationInWindow().y },
|
||||||
|
.mods = machModifierFromModifierFlag(event.modifierFlags()),
|
||||||
|
} });
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn scrollWheel(block: *objc.foundation.BlockLiteral(*Context), event: *objc.app_kit.Event) callconv(.C) void {
|
||||||
|
const core: *Core = block.context.core;
|
||||||
|
const window_id = block.context.window_id;
|
||||||
|
|
||||||
|
var scroll_delta_x = event.scrollingDeltaX();
|
||||||
|
var scroll_delta_y = event.scrollingDeltaY();
|
||||||
|
|
||||||
|
if (event.hasPreciseScrollingDeltas()) {
|
||||||
|
scroll_delta_x *= 0.1;
|
||||||
|
scroll_delta_y *= 0.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
core.pushEvent(.{ .mouse_scroll = .{
|
||||||
|
.window_id = window_id,
|
||||||
|
.xoffset = @floatCast(scroll_delta_x),
|
||||||
|
.yoffset = @floatCast(scroll_delta_y),
|
||||||
|
} });
|
||||||
|
}
|
||||||
|
|
||||||
pub fn keyDown(block: *objc.foundation.BlockLiteral(*Context), event: *objc.app_kit.Event) callconv(.C) void {
|
pub fn keyDown(block: *objc.foundation.BlockLiteral(*Context), event: *objc.app_kit.Event) callconv(.C) void {
|
||||||
const core: *Core = block.context.core;
|
const core: *Core = block.context.core;
|
||||||
const window_id = block.context.window_id;
|
const window_id = block.context.window_id;
|
||||||
|
|
@ -316,6 +433,33 @@ const ViewCallbacks = struct {
|
||||||
.mods = machModifierFromModifierFlag(event.modifierFlags()),
|
.mods = machModifierFromModifierFlag(event.modifierFlags()),
|
||||||
} });
|
} });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn flagsChanged(block: *objc.foundation.BlockLiteral(*Context), event: *objc.app_kit.Event) callconv(.C) void {
|
||||||
|
const core: *Core = block.context.core;
|
||||||
|
const window_id = block.context.window_id;
|
||||||
|
|
||||||
|
const key = machKeyFromKeycode(event.keyCode());
|
||||||
|
const mods = machModifierFromModifierFlag(event.modifierFlags());
|
||||||
|
|
||||||
|
const key_flag = switch (key) {
|
||||||
|
.left_shift, .right_shift => objc.app_kit.EventModifierFlagShift,
|
||||||
|
.left_control, .right_control => objc.app_kit.EventModifierFlagControl,
|
||||||
|
.left_alt, .right_alt => objc.app_kit.EventModifierFlagOption,
|
||||||
|
.left_super, .right_super => objc.app_kit.EventModifierFlagCommand,
|
||||||
|
.caps_lock => objc.app_kit.EventModifierFlagCapsLock,
|
||||||
|
else => 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (event.modifierFlags() & key_flag != 0) {
|
||||||
|
if (core.input_state.isKeyPressed(key)) {
|
||||||
|
core.pushEvent(.{ .key_release = .{ .window_id = window_id, .key = key, .mods = mods } });
|
||||||
|
} else {
|
||||||
|
core.pushEvent(.{ .key_press = .{ .window_id = window_id, .key = key, .mods = mods } });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
core.pushEvent(.{ .key_release = .{ .window_id = window_id, .key = key, .mods = mods } });
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
fn machModifierFromModifierFlag(modifier_flag: usize) Core.KeyMods {
|
fn machModifierFromModifierFlag(modifier_flag: usize) Core.KeyMods {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue