core: windows: refactor everything
This commit is contained in:
parent
1e2cbc4d71
commit
f9e1a9087f
5 changed files with 821 additions and 203 deletions
|
|
@ -402,6 +402,7 @@ fn buildExamples(
|
||||||
.root_source_file = b.path(b.fmt("examples/{s}/main.zig", .{example.name})),
|
.root_source_file = b.path(b.fmt("examples/{s}/main.zig", .{example.name})),
|
||||||
.target = target,
|
.target = target,
|
||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
|
.win32_manifest = b.path("src/core/windows/win32.manifest"),
|
||||||
});
|
});
|
||||||
exe.root_module.addImport("mach", mach_mod);
|
exe.root_module.addImport("mach", mach_mod);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@ const w = @import("../win32.zig");
|
||||||
const mach = @import("../main.zig");
|
const mach = @import("../main.zig");
|
||||||
const Core = @import("../Core.zig");
|
const Core = @import("../Core.zig");
|
||||||
|
|
||||||
|
const windowmsg = @import("windowmsg.zig");
|
||||||
|
|
||||||
const gpu = mach.gpu;
|
const gpu = mach.gpu;
|
||||||
const Event = Core.Event;
|
const Event = Core.Event;
|
||||||
const KeyEvent = Core.KeyEvent;
|
const KeyEvent = Core.KeyEvent;
|
||||||
|
|
@ -17,20 +19,19 @@ const Position = Core.Position;
|
||||||
const Key = Core.Key;
|
const Key = Core.Key;
|
||||||
const KeyMods = Core.KeyMods;
|
const KeyMods = Core.KeyMods;
|
||||||
|
|
||||||
|
const log = std.log.scoped(.mach);
|
||||||
const EventQueue = std.fifo.LinearFifo(Event, .Dynamic);
|
const EventQueue = std.fifo.LinearFifo(Event, .Dynamic);
|
||||||
const Win32 = @This();
|
const Win32 = @This();
|
||||||
|
|
||||||
pub const Native = struct {
|
const window_ex_style: w.WINDOW_EX_STYLE = .{
|
||||||
window: w.HWND = undefined,
|
.APPWINDOW = 1,
|
||||||
surrogate: u16 = 0,
|
.NOREDIRECTIONBITMAP = 1,
|
||||||
dinput: *w.IDirectInput8W = undefined,
|
|
||||||
saved_window_rect: w.RECT = undefined,
|
|
||||||
surface_descriptor_from_hwnd: gpu.Surface.DescriptorFromWindowsHWND = undefined,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Context = struct {
|
pub const Native = struct {
|
||||||
core: *Core,
|
hwnd: w.HWND,
|
||||||
window_id: mach.ObjectID,
|
surrogate: u16 = 0,
|
||||||
|
// dinput: *w.IDirectInput8W = undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn run(comptime on_each_update_fn: anytype, args_tuple: std.meta.ArgsTuple(@TypeOf(on_each_update_fn))) void {
|
pub fn run(comptime on_each_update_fn: anytype, args_tuple: std.meta.ArgsTuple(@TypeOf(on_each_update_fn))) void {
|
||||||
|
|
@ -38,140 +39,250 @@ pub fn run(comptime on_each_update_fn: anytype, args_tuple: std.meta.ArgsTuple(@
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tick(core: *Core) !void {
|
pub fn tick(core: *Core) !void {
|
||||||
var windows = core.windows.slice();
|
{
|
||||||
while (windows.next()) |window_id| {
|
var windows = core.windows.slice();
|
||||||
const native_opt: ?Native = core.windows.get(window_id, .native);
|
while (windows.next()) |window_id| {
|
||||||
|
if (core.windows.get(window_id, .native) != null) {
|
||||||
if (native_opt) |native| {
|
// TODO: propagate window.decorated and all others
|
||||||
_ = native; // autofix
|
// Handle resizing the window when the user changes width or height
|
||||||
var msg: w.MSG = undefined;
|
if (core.windows.updated(window_id, .width) or core.windows.updated(window_id, .height)) {
|
||||||
while (w.PeekMessageW(&msg, null, 0, 0, w.PM_REMOVE) != 0) {
|
setWindowSize(
|
||||||
_ = w.TranslateMessage(&msg);
|
core.windows.get(window_id, .native).?.hwnd,
|
||||||
_ = w.DispatchMessageW(&msg);
|
.{
|
||||||
|
.width = core.windows.get(window_id, .width),
|
||||||
|
.height = core.windows.get(window_id, .height),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
try initWindow(core, window_id);
|
||||||
|
std.debug.assert(core.windows.getValue(window_id).native != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle resizing the window when the user changes width or height
|
|
||||||
if (core.windows.updated(window_id, .width) or core.windows.updated(window_id, .height)) {}
|
|
||||||
} else {
|
|
||||||
try initWindow(core, window_id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var msg: w.MSG = undefined;
|
||||||
|
while (true) {
|
||||||
|
const result = w.PeekMessageW(&msg, null, 0, 0, w.PM_REMOVE);
|
||||||
|
if (result < 0) fatalWin32("PeekMessage", w.GetLastError());
|
||||||
|
if (result == 0) break;
|
||||||
|
if (msg.message == w.WM_QUIT) {
|
||||||
|
std.log.info("quit (exit code {})", .{msg.wParam});
|
||||||
|
w.ExitProcess(std.math.cast(u32, msg.wParam) orelse 0xffffffff);
|
||||||
|
}
|
||||||
|
_ = w.TranslateMessage(&msg);
|
||||||
|
_ = w.DispatchMessageW(&msg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn setWindowSize(hwnd: w.HWND, size_pt: Size) void {
|
||||||
|
const dpi = w.dpiFromHwnd(hwnd);
|
||||||
|
const style = styleFromHwnd(hwnd);
|
||||||
|
var rect: w.RECT = .{
|
||||||
|
.left = 0,
|
||||||
|
.top = 0,
|
||||||
|
.right = w.pxFromPt(i32, @intCast(size_pt.width), dpi),
|
||||||
|
.bottom = w.pxFromPt(i32, @intCast(size_pt.height), dpi),
|
||||||
|
};
|
||||||
|
if (0 == w.AdjustWindowRectExForDpi(&rect, style, w.FALSE, window_ex_style, dpi)) fatalWin32(
|
||||||
|
"AdjustWindowRectExForDpi",
|
||||||
|
w.GetLastError(),
|
||||||
|
);
|
||||||
|
if (0 == w.SetWindowPos(
|
||||||
|
hwnd,
|
||||||
|
null,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
rect.right - rect.left,
|
||||||
|
rect.bottom - rect.top,
|
||||||
|
.{ .NOZORDER = 1, .NOMOVE = 1 },
|
||||||
|
)) fatalWin32("SetWindowPos", w.GetLastError());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn updateWindowSize(
|
||||||
|
dpi: u32,
|
||||||
|
window_style: w.WINDOW_STYLE,
|
||||||
|
hwnd: w.HWND,
|
||||||
|
requested_client_size: w.SIZE,
|
||||||
|
) void {
|
||||||
|
const monitor = blk: {
|
||||||
|
var rect: w.RECT = undefined;
|
||||||
|
if (0 == w.GetWindowRect(hwnd, &rect)) fatalWin32("GetWindowRect", w.GetLastError());
|
||||||
|
|
||||||
|
break :blk w.MonitorFromPoint(
|
||||||
|
.{ .x = rect.left, .y = rect.top },
|
||||||
|
w.MONITOR_DEFAULTTONULL,
|
||||||
|
) orelse {
|
||||||
|
log.warn("MonitorFromPoint {},{} failed with {}", .{ rect.left, rect.top, w.GetLastError() });
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const work_rect: w.RECT = blk: {
|
||||||
|
var info: w.MONITORINFO = undefined;
|
||||||
|
info.cbSize = @sizeOf(w.MONITORINFO);
|
||||||
|
if (0 == w.GetMonitorInfoW(monitor, &info)) {
|
||||||
|
log.warn("GetMonitorInfo failed with {}", .{w.GetLastError()});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break :blk info.rcWork;
|
||||||
|
};
|
||||||
|
|
||||||
|
const work_size: w.SIZE = .{
|
||||||
|
.cx = work_rect.right - work_rect.left,
|
||||||
|
.cy = work_rect.bottom - work_rect.top,
|
||||||
|
};
|
||||||
|
log.debug(
|
||||||
|
"primary monitor work topleft={},{} size={}x{}",
|
||||||
|
.{ work_rect.left, work_rect.top, work_size.cx, work_size.cy },
|
||||||
|
);
|
||||||
|
|
||||||
|
const wanted_size: w.SIZE = blk: {
|
||||||
|
var rect: w.RECT = .{
|
||||||
|
.left = 0,
|
||||||
|
.top = 0,
|
||||||
|
.right = requested_client_size.cx,
|
||||||
|
.bottom = requested_client_size.cy,
|
||||||
|
};
|
||||||
|
if (0 == w.AdjustWindowRectExForDpi(&rect, window_style, w.FALSE, window_ex_style, dpi)) fatalWin32(
|
||||||
|
"AdjustWindowRectExForDpi",
|
||||||
|
w.GetLastError(),
|
||||||
|
);
|
||||||
|
break :blk .{
|
||||||
|
.cx = rect.right - rect.left,
|
||||||
|
.cy = rect.bottom - rect.top,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const window_size: w.SIZE = .{
|
||||||
|
.cx = @min(wanted_size.cx, work_size.cx),
|
||||||
|
.cy = @min(wanted_size.cy, work_size.cy),
|
||||||
|
};
|
||||||
|
if (0 == w.SetWindowPos(
|
||||||
|
hwnd,
|
||||||
|
null,
|
||||||
|
work_rect.left + @divTrunc(work_size.cx - window_size.cx, 2),
|
||||||
|
work_rect.top + @divTrunc(work_size.cy - window_size.cy, 2),
|
||||||
|
window_size.cx,
|
||||||
|
window_size.cy,
|
||||||
|
.{ .NOZORDER = 1 },
|
||||||
|
)) fatalWin32("SetWindowPos", w.GetLastError());
|
||||||
|
}
|
||||||
|
|
||||||
|
const CreateWindowArgs = struct {
|
||||||
|
window_id: mach.ObjectID,
|
||||||
|
};
|
||||||
|
|
||||||
|
var wndproc_core: *Core = undefined;
|
||||||
|
|
||||||
fn initWindow(
|
fn initWindow(
|
||||||
core: *Core,
|
core: *Core,
|
||||||
window_id: mach.ObjectID,
|
window_id: mach.ObjectID,
|
||||||
) !void {
|
) !void {
|
||||||
|
wndproc_core = core;
|
||||||
|
|
||||||
var core_window = core.windows.getValue(window_id);
|
var core_window = core.windows.getValue(window_id);
|
||||||
|
|
||||||
const hInstance = w.GetModuleHandleW(null);
|
const hInstance = w.GetModuleHandleW(null);
|
||||||
const class_name = w.L("mach");
|
const class_name = w.L("mach");
|
||||||
const class = std.mem.zeroInit(w.WNDCLASSW, .{
|
{
|
||||||
.style = w.CS_OWNDC,
|
const class: w.WNDCLASSW = .{
|
||||||
.lpfnWndProc = wndProc,
|
.style = .{},
|
||||||
.hInstance = hInstance,
|
.lpfnWndProc = wndProc,
|
||||||
.hIcon = w.LoadIconW(null, @as([*:0]align(1) const u16, @ptrFromInt(@as(u32, w.IDI_APPLICATION)))),
|
.cbClsExtra = 0,
|
||||||
.hCursor = w.LoadCursorW(null, @as([*:0]align(1) const u16, @ptrFromInt(@as(u32, w.IDC_ARROW)))),
|
.cbWndExtra = @sizeOf(mach.ObjectID),
|
||||||
.lpszClassName = class_name,
|
.hInstance = hInstance,
|
||||||
});
|
.hIcon = w.LoadIconW(null, w.IDI_APPLICATION),
|
||||||
if (w.RegisterClassW(&class) == 0) return error.Unexpected;
|
.hCursor = w.LoadCursorW(null, w.IDC_ARROW),
|
||||||
|
.hbrBackground = null,
|
||||||
|
.lpszMenuName = null,
|
||||||
|
.lpszClassName = class_name,
|
||||||
|
};
|
||||||
|
if (w.RegisterClassW(&class) == 0) fatalWin32("RegisterClass", w.GetLastError());
|
||||||
|
}
|
||||||
|
|
||||||
const title = try std.unicode.utf8ToUtf16LeAllocZ(core.allocator, core_window.title);
|
const title = try std.unicode.utf8ToUtf16LeAllocZ(core.allocator, core_window.title);
|
||||||
defer core.allocator.free(title);
|
defer core.allocator.free(title);
|
||||||
|
|
||||||
var request_window_width: i32 = @bitCast(core_window.width);
|
|
||||||
var request_window_height: i32 = @bitCast(core_window.height);
|
|
||||||
|
|
||||||
const window_ex_style: w.WINDOW_EX_STYLE = .{ .APPWINDOW = 1 };
|
|
||||||
const window_style: w.WINDOW_STYLE = if (core_window.decorated) w.WS_OVERLAPPEDWINDOW else w.WS_POPUPWINDOW; // w.WINDOW_STYLE{.POPUP = 1};
|
const window_style: w.WINDOW_STYLE = if (core_window.decorated) w.WS_OVERLAPPEDWINDOW else w.WS_POPUPWINDOW; // w.WINDOW_STYLE{.POPUP = 1};
|
||||||
|
|
||||||
var rect: w.RECT = .{ .left = 0, .top = 0, .right = request_window_width, .bottom = request_window_height };
|
const create_args: CreateWindowArgs = .{
|
||||||
|
.window_id = window_id,
|
||||||
if (w.TRUE == w.AdjustWindowRectEx(&rect, window_style, w.FALSE, window_ex_style)) {
|
};
|
||||||
request_window_width = rect.right - rect.left;
|
const hwnd = w.CreateWindowExW(
|
||||||
request_window_height = rect.bottom - rect.top;
|
|
||||||
}
|
|
||||||
|
|
||||||
const native_window = w.CreateWindowExW(
|
|
||||||
window_ex_style,
|
window_ex_style,
|
||||||
class_name,
|
class_name,
|
||||||
title,
|
title,
|
||||||
window_style,
|
window_style,
|
||||||
w.CW_USEDEFAULT,
|
w.CW_USEDEFAULT,
|
||||||
w.CW_USEDEFAULT,
|
w.CW_USEDEFAULT,
|
||||||
request_window_width,
|
w.CW_USEDEFAULT,
|
||||||
request_window_height,
|
w.CW_USEDEFAULT,
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
hInstance,
|
hInstance,
|
||||||
null,
|
@constCast(@ptrCast(&create_args)),
|
||||||
) orelse return error.Unexpected;
|
) orelse return error.Unexpected;
|
||||||
|
|
||||||
var native: Native = .{};
|
const dpi = w.dpiFromHwnd(hwnd);
|
||||||
|
|
||||||
var dinput: ?*w.IDirectInput8W = undefined;
|
updateWindowSize(dpi, window_style, hwnd, .{
|
||||||
const ptr: ?*?*anyopaque = @ptrCast(&dinput);
|
.cx = @bitCast(core_window.width),
|
||||||
if (w.DirectInput8Create(hInstance, w.DIRECTINPUT_VERSION, w.IID_IDirectInput8W, ptr, null) != w.DI_OK) {
|
.cy = @bitCast(core_window.height),
|
||||||
return error.Unexpected;
|
});
|
||||||
}
|
|
||||||
native.dinput = dinput.?;
|
|
||||||
|
|
||||||
native.surface_descriptor_from_hwnd = .{
|
// const dinput = blk: {
|
||||||
.hinstance = std.os.windows.kernel32.GetModuleHandleW(null).?,
|
// var dinput: ?*w.IDirectInput8W = undefined;
|
||||||
.hwnd = native_window,
|
// const ptr: ?*?*anyopaque = @ptrCast(&dinput);
|
||||||
};
|
// if (w.DirectInput8Create(hInstance, w.DIRECTINPUT_VERSION, w.IID_IDirectInput8W, ptr, null) != w.DI_OK) {
|
||||||
|
// return error.Unexpected;
|
||||||
|
// }
|
||||||
|
// break :blk dinput;
|
||||||
|
// };
|
||||||
|
|
||||||
core_window.surface_descriptor = .{ .next_in_chain = .{
|
const size = getClientSize(hwnd);
|
||||||
.from_windows_hwnd = &native.surface_descriptor_from_hwnd,
|
|
||||||
} };
|
|
||||||
|
|
||||||
const context = try core.allocator.create(Context);
|
|
||||||
context.* = .{ .core = core, .window_id = window_id };
|
|
||||||
|
|
||||||
_ = w.SetWindowLongPtrW(native_window, w.GWLP_USERDATA, @bitCast(@intFromPtr(context)));
|
|
||||||
|
|
||||||
restoreWindowPosition(core, window_id);
|
|
||||||
|
|
||||||
const size = getClientRect(core, window_id);
|
|
||||||
core_window.width = size.width;
|
core_window.width = size.width;
|
||||||
core_window.height = size.height;
|
core_window.height = size.height;
|
||||||
|
|
||||||
_ = w.GetWindowRect(native.window, &native.saved_window_rect);
|
_ = w.ShowWindow(hwnd, w.SW_SHOW);
|
||||||
|
|
||||||
core_window.native = native;
|
// try some things to bring our window to the top
|
||||||
core.windows.setValueRaw(window_id, core_window);
|
const HWND_TOP: ?w.HWND = null;
|
||||||
try core.initWindow(window_id);
|
_ = w.SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, .{ .NOMOVE = 1, .NOSIZE = 1 });
|
||||||
_ = w.ShowWindow(native_window, w.SW_SHOW);
|
_ = w.SetForegroundWindow(hwnd);
|
||||||
|
_ = w.BringWindowToTop(hwnd);
|
||||||
|
|
||||||
|
{
|
||||||
|
// TODO: make this lifetime better
|
||||||
|
var surface_descriptor_from_hwnd: gpu.Surface.DescriptorFromWindowsHWND = .{
|
||||||
|
.hinstance = std.os.windows.kernel32.GetModuleHandleW(null).?,
|
||||||
|
.hwnd = hwnd,
|
||||||
|
};
|
||||||
|
core.windows.setRaw(window_id, .surface_descriptor, .{ .next_in_chain = .{
|
||||||
|
.from_windows_hwnd = &surface_descriptor_from_hwnd,
|
||||||
|
} });
|
||||||
|
try core.initWindow(window_id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn windowIdFromHwnd(hwnd: w.HWND) mach.ObjectID {
|
||||||
|
const userdata: usize = @bitCast(w.GetWindowLongPtrW(hwnd, @enumFromInt(0)));
|
||||||
|
if (userdata == 0) unreachable;
|
||||||
|
return @bitCast(userdata - 1);
|
||||||
|
}
|
||||||
|
fn styleFromHwnd(hwnd: w.HWND) w.WINDOW_STYLE {
|
||||||
|
return @bitCast(@as(u32, @truncate(@as(usize, @bitCast(w.GetWindowLongPtrW(hwnd, w.GWL_EXSTYLE))))));
|
||||||
|
}
|
||||||
// -----------------------------
|
// -----------------------------
|
||||||
// Internal functions
|
// Internal functions
|
||||||
// -----------------------------
|
// -----------------------------
|
||||||
fn getClientRect(core: *Core, window_id: mach.ObjectID) Size {
|
fn getClientSize(hwnd: w.HWND) Size {
|
||||||
const window = core.windows.getValue(window_id);
|
var rect: w.RECT = undefined;
|
||||||
|
if (0 == w.GetClientRect(hwnd, &rect))
|
||||||
if (window.native) |native| {
|
fatalWin32("GetClientRect", w.GetLastError());
|
||||||
var rect: w.RECT = undefined;
|
std.debug.assert(rect.left == 0);
|
||||||
_ = w.GetClientRect(native.window, &rect);
|
std.debug.assert(rect.top == 0);
|
||||||
|
return .{ .width = @intCast(rect.right), .height = @intCast(rect.bottom) };
|
||||||
const width: u32 = @intCast(rect.right - rect.left);
|
|
||||||
const height: u32 = @intCast(rect.bottom - rect.top);
|
|
||||||
|
|
||||||
return .{ .width = width, .height = height };
|
|
||||||
}
|
|
||||||
|
|
||||||
return .{ .width = 0, .height = 0 };
|
|
||||||
}
|
|
||||||
|
|
||||||
fn restoreWindowPosition(core: *Core, window_id: mach.ObjectID) void {
|
|
||||||
const window = core.windows.getValue(window_id);
|
|
||||||
if (window.native) |native| {
|
|
||||||
if (native.saved_window_rect.right - native.saved_window_rect.left == 0) {
|
|
||||||
_ = w.ShowWindow(native.window, w.SW_RESTORE);
|
|
||||||
} else {
|
|
||||||
_ = w.SetWindowPos(native.window, null, native.saved_window_rect.left, native.saved_window_rect.top, native.saved_window_rect.right - native.saved_window_rect.left, native.saved_window_rect.bottom - native.saved_window_rect.top, w.SWP_SHOWWINDOW);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn getKeyboardModifiers() mach.Core.KeyMods {
|
fn getKeyboardModifiers() mach.Core.KeyMods {
|
||||||
|
|
@ -186,52 +297,79 @@ fn getKeyboardModifiers() mach.Core.KeyMods {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wndProc(wnd: w.HWND, msg: u32, wParam: w.WPARAM, lParam: w.LPARAM) callconv(w.WINAPI) w.LRESULT {
|
const debug_wndproc_log = false;
|
||||||
const context = blk: {
|
var global_msg_tail: ?*windowmsg.MessageNode = null;
|
||||||
const userdata: usize = @bitCast(w.GetWindowLongPtrW(wnd, w.GWLP_USERDATA));
|
|
||||||
const ptr: ?*Context = @ptrFromInt(userdata);
|
fn wndProc(hwnd: w.HWND, msg: u32, wParam: w.WPARAM, lParam: w.LPARAM) callconv(w.WINAPI) w.LRESULT {
|
||||||
break :blk ptr orelse return w.DefWindowProcW(wnd, msg, wParam, lParam);
|
var msg_node: windowmsg.MessageNode = undefined;
|
||||||
|
if (debug_wndproc_log) msg_node.init(&global_msg_tail, hwnd, msg, wParam, lParam);
|
||||||
|
defer if (debug_wndproc_log) msg_node.deinit();
|
||||||
|
if (debug_wndproc_log) switch (msg) {
|
||||||
|
w.WM_MOUSEMOVE => {},
|
||||||
|
else => std.log.info("{}", .{msg_node.fmtPath()}),
|
||||||
};
|
};
|
||||||
|
|
||||||
const core = context.core;
|
const core = wndproc_core;
|
||||||
const window_id = context.window_id;
|
|
||||||
|
|
||||||
var core_window = core.windows.getValue(window_id);
|
|
||||||
|
|
||||||
switch (msg) {
|
switch (msg) {
|
||||||
w.WM_CLOSE => {
|
w.WM_CREATE => {
|
||||||
core.pushEvent(.{ .close = .{ .window_id = window_id } });
|
const create_struct: *w.CREATESTRUCTW = @ptrFromInt(@as(usize, @bitCast(lParam)));
|
||||||
|
const create_args: *CreateWindowArgs = @alignCast(@ptrCast(create_struct.lpCreateParams));
|
||||||
|
const window_id = create_args.window_id;
|
||||||
|
|
||||||
|
core.windows.setRaw(window_id, .native, .{ .hwnd = hwnd });
|
||||||
|
// we add 1 to distinguish between a valid window id and an uninitialized slot
|
||||||
|
std.debug.assert(0 == w.SetWindowLongPtrW(hwnd, @enumFromInt(0), @bitCast(create_args.window_id + 1)));
|
||||||
|
std.debug.assert(create_args.window_id == windowIdFromHwnd(hwnd));
|
||||||
return 0;
|
return 0;
|
||||||
},
|
},
|
||||||
w.WM_SIZE => {
|
w.WM_DESTROY => @panic("Mach doesn't support destroying windows yet"),
|
||||||
const width: u32 = @as(u32, @intCast(lParam & 0xFFFF));
|
w.WM_CLOSE => {
|
||||||
const height: u32 = @as(u32, @intCast((lParam >> 16) & 0xFFFF));
|
core.pushEvent(.{ .close = .{ .window_id = windowIdFromHwnd(hwnd) } });
|
||||||
|
return 0;
|
||||||
|
},
|
||||||
|
w.WM_DPICHANGED, w.WM_WINDOWPOSCHANGED => {
|
||||||
|
const client_size_px = getClientSize(hwnd);
|
||||||
|
|
||||||
if (core_window.width != width or core_window.height != height) {
|
const window_id = windowIdFromHwnd(hwnd);
|
||||||
|
var core_window = core.windows.getValue(window_id);
|
||||||
|
|
||||||
|
var change = false;
|
||||||
|
if (core_window.framebuffer_width != client_size_px.width or core_window.framebuffer_height != client_size_px.height) {
|
||||||
|
change = true;
|
||||||
// Recreate the swap_chain
|
// Recreate the swap_chain
|
||||||
core_window.swap_chain.release();
|
core_window.swap_chain.release();
|
||||||
core_window.swap_chain_descriptor.width = width;
|
core_window.swap_chain_descriptor.width = client_size_px.width;
|
||||||
core_window.swap_chain_descriptor.height = height;
|
core_window.swap_chain_descriptor.height = client_size_px.height;
|
||||||
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_width = client_size_px.width;
|
||||||
core_window.width = width;
|
core_window.framebuffer_height = client_size_px.height;
|
||||||
core_window.height = height;
|
|
||||||
core_window.framebuffer_width = width;
|
|
||||||
core_window.framebuffer_height = height;
|
|
||||||
|
|
||||||
core.pushEvent(.{ .window_resize = .{ .window_id = window_id, .size = .{ .width = width, .height = height } } });
|
|
||||||
|
|
||||||
core.windows.setValueRaw(window_id, core_window);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO (win32): only send resize event when sizing is done.
|
const dpi = w.dpiFromHwnd(hwnd);
|
||||||
// the main mach loops does not run while resizing.
|
const client_size_pt: Size = .{
|
||||||
// Which means if events are pushed here they will
|
.width = w.ptFromPx(u32, client_size_px.width, dpi),
|
||||||
// queue up until resize is done.
|
.height = w.ptFromPx(u32, client_size_px.height, dpi),
|
||||||
|
};
|
||||||
|
if (core_window.width != client_size_pt.width or core_window.height != client_size_pt.height) {
|
||||||
|
change = true;
|
||||||
|
core_window.width = client_size_pt.width;
|
||||||
|
core_window.height = client_size_pt.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (change) {
|
||||||
|
core.pushEvent(.{ .window_resize = .{
|
||||||
|
.window_id = window_id,
|
||||||
|
.size = .{ .width = client_size_pt.width, .height = client_size_pt.height },
|
||||||
|
} });
|
||||||
|
core.windows.setValueRaw(window_id, core_window);
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
},
|
},
|
||||||
w.WM_KEYDOWN, w.WM_KEYUP, w.WM_SYSKEYDOWN, w.WM_SYSKEYUP => {
|
w.WM_KEYDOWN, w.WM_KEYUP, w.WM_SYSKEYDOWN, w.WM_SYSKEYUP => {
|
||||||
|
// ScanCode: Unique Identifier for a physical button.
|
||||||
|
// Virtulkey: A key with a name, multiple physical buttons can produce the same virtual key.
|
||||||
|
const window_id = windowIdFromHwnd(hwnd);
|
||||||
|
|
||||||
const vkey: w.VIRTUAL_KEY = @enumFromInt(wParam);
|
const vkey: w.VIRTUAL_KEY = @enumFromInt(wParam);
|
||||||
if (vkey == w.VK_PROCESSKEY) return 0;
|
if (vkey == w.VK_PROCESSKEY) return 0;
|
||||||
|
|
||||||
|
|
@ -241,43 +379,47 @@ fn wndProc(wnd: w.HWND, msg: u32, wParam: w.WPARAM, lParam: w.LPARAM) callconv(w
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const flags = lParam >> 16;
|
const WinKeyFlags = packed struct(u32) {
|
||||||
const scancode: u9 = @intCast(flags & 0x1FF);
|
repeat_count: u16,
|
||||||
|
scancode: u8,
|
||||||
|
extended: bool,
|
||||||
|
reserved: u4,
|
||||||
|
context: bool,
|
||||||
|
previous: bool,
|
||||||
|
transition: bool,
|
||||||
|
};
|
||||||
|
|
||||||
|
const flags: WinKeyFlags = @bitCast(@as(u32, @truncate(@as(usize, @bitCast(lParam)))));
|
||||||
|
const scancode: u9 = flags.scancode | (@as(u9, if (flags.extended) 1 else 0) << 8);
|
||||||
if (scancode == 0x1D) {
|
if (scancode == 0x1D) {
|
||||||
// right alt sends left control first
|
// right alt sends left control first
|
||||||
var next: w.MSG = undefined;
|
var next: w.MSG = undefined;
|
||||||
const time = w.GetMessageTime();
|
const time = w.GetMessageTime();
|
||||||
if (core_window.native) |native| {
|
if (w.PeekMessageW(&next, hwnd, 0, 0, w.PM_NOREMOVE) != 0 and
|
||||||
if (w.PeekMessageW(&next, native.window, 0, 0, w.PM_NOREMOVE) != 0 and
|
next.time == time and
|
||||||
next.time == time and
|
(next.message == msg or (msg == w.WM_SYSKEYDOWN and next.message == w.WM_KEYUP)) and
|
||||||
(next.message == msg or (msg == w.WM_SYSKEYDOWN and next.message == w.WM_KEYUP)) and
|
((next.lParam >> 16) & 0x1FF) == 0x138)
|
||||||
((next.lParam >> 16) & 0x1FF) == 0x138)
|
{
|
||||||
{
|
return 0;
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const mods = getKeyboardModifiers();
|
const mods = getKeyboardModifiers();
|
||||||
const key = keyFromScancode(scancode);
|
const key = keyFromScancode(scancode);
|
||||||
if (msg == w.WM_KEYDOWN or msg == w.WM_SYSKEYDOWN) {
|
if (msg == w.WM_KEYDOWN or msg == w.WM_SYSKEYDOWN) {
|
||||||
if (flags & w.KF_REPEAT == 0)
|
if (flags.previous) core.pushEvent(.{
|
||||||
core.pushEvent(.{
|
.key_repeat = .{
|
||||||
.key_press = .{
|
.window_id = window_id,
|
||||||
.window_id = window_id,
|
.key = key,
|
||||||
.key = key,
|
.mods = mods,
|
||||||
.mods = mods,
|
},
|
||||||
},
|
}) else core.pushEvent(.{
|
||||||
})
|
.key_press = .{
|
||||||
else
|
.window_id = window_id,
|
||||||
core.pushEvent(.{
|
.key = key,
|
||||||
.key_repeat = .{
|
.mods = mods,
|
||||||
.window_id = window_id,
|
},
|
||||||
.key = key,
|
});
|
||||||
.mods = mods,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
} else core.pushEvent(.{
|
} else core.pushEvent(.{
|
||||||
.key_release = .{
|
.key_release = .{
|
||||||
.window_id = window_id,
|
.window_id = window_id,
|
||||||
|
|
@ -289,29 +431,32 @@ fn wndProc(wnd: w.HWND, msg: u32, wParam: w.WPARAM, lParam: w.LPARAM) callconv(w
|
||||||
return 0;
|
return 0;
|
||||||
},
|
},
|
||||||
w.WM_CHAR => {
|
w.WM_CHAR => {
|
||||||
if (core_window.native) |*native| {
|
const window_id = windowIdFromHwnd(hwnd);
|
||||||
const char: u16 = @truncate(wParam);
|
|
||||||
var chars: []const u16 = undefined;
|
const chars: [2]u16 = blk: {
|
||||||
if (native.surrogate != 0) {
|
var native = core.windows.get(window_id, .native).?;
|
||||||
chars = &.{ native.surrogate, char };
|
defer core.windows.setRaw(window_id, .native, native);
|
||||||
native.surrogate = 0;
|
const chars = [2]u16{ native.surrogate, @truncate(wParam) };
|
||||||
} else if (std.unicode.utf16IsHighSurrogate(char)) {
|
if (std.unicode.utf16IsHighSurrogate(chars[1])) {
|
||||||
native.surrogate = char;
|
native.surrogate = chars[1];
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
|
||||||
chars = &.{char};
|
|
||||||
}
|
}
|
||||||
var iter = std.unicode.Utf16LeIterator.init(chars);
|
native.surrogate = 0;
|
||||||
if (iter.nextCodepoint()) |codepoint| {
|
break :blk chars;
|
||||||
core.pushEvent(.{ .char_input = .{
|
};
|
||||||
.window_id = window_id,
|
const codepoint: u21 = blk: {
|
||||||
.codepoint = codepoint.?,
|
if (std.unicode.utf16IsHighSurrogate(chars[0])) {
|
||||||
} });
|
if (std.unicode.utf16DecodeSurrogatePair(&chars)) |c| break :blk c else |e| switch (e) {
|
||||||
} else |err| {
|
error.ExpectedSecondSurrogateHalf => {},
|
||||||
err catch {};
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
break :blk chars[1];
|
||||||
}
|
};
|
||||||
|
core.pushEvent(.{ .char_input = .{
|
||||||
|
.window_id = window_id,
|
||||||
|
.codepoint = codepoint,
|
||||||
|
} });
|
||||||
|
return 0;
|
||||||
},
|
},
|
||||||
w.WM_LBUTTONDOWN,
|
w.WM_LBUTTONDOWN,
|
||||||
w.WM_LBUTTONUP,
|
w.WM_LBUTTONUP,
|
||||||
|
|
@ -322,15 +467,26 @@ fn wndProc(wnd: w.HWND, msg: u32, wParam: w.WPARAM, lParam: w.LPARAM) callconv(w
|
||||||
w.WM_XBUTTONDOWN,
|
w.WM_XBUTTONDOWN,
|
||||||
w.WM_XBUTTONUP,
|
w.WM_XBUTTONUP,
|
||||||
=> {
|
=> {
|
||||||
|
const window_id = windowIdFromHwnd(hwnd);
|
||||||
const mods = getKeyboardModifiers();
|
const mods = getKeyboardModifiers();
|
||||||
const x: f64 = @floatFromInt(@as(i16, @truncate(lParam & 0xFFFF)));
|
const point = w.pointFromLparam(lParam);
|
||||||
const y: f64 = @floatFromInt(@as(i16, @truncate((lParam >> 16) & 0xFFFF)));
|
|
||||||
const xbutton: u32 = @truncate(wParam >> 16);
|
const MouseFlags = packed struct(u8) {
|
||||||
|
left_down: bool,
|
||||||
|
right_down: bool,
|
||||||
|
shift_down: bool,
|
||||||
|
control_down: bool,
|
||||||
|
middle_down: bool,
|
||||||
|
xbutton1_down: bool,
|
||||||
|
xbutton2_down: bool,
|
||||||
|
_: bool,
|
||||||
|
};
|
||||||
|
const flags: MouseFlags = @bitCast(@as(u8, @truncate(wParam)));
|
||||||
const button: MouseButton = switch (msg) {
|
const button: MouseButton = switch (msg) {
|
||||||
w.WM_LBUTTONDOWN, w.WM_LBUTTONUP => .left,
|
w.WM_LBUTTONDOWN, w.WM_LBUTTONUP => .left,
|
||||||
w.WM_RBUTTONDOWN, w.WM_RBUTTONUP => .right,
|
w.WM_RBUTTONDOWN, w.WM_RBUTTONUP => .right,
|
||||||
w.WM_MBUTTONDOWN, w.WM_MBUTTONUP => .middle,
|
w.WM_MBUTTONDOWN, w.WM_MBUTTONUP => .middle,
|
||||||
else => if (xbutton == @as(u32, @bitCast(w.XBUTTON1))) .four else .five,
|
else => if (flags.xbutton1_down) .four else .five,
|
||||||
};
|
};
|
||||||
|
|
||||||
switch (msg) {
|
switch (msg) {
|
||||||
|
|
@ -343,7 +499,7 @@ fn wndProc(wnd: w.HWND, msg: u32, wParam: w.WPARAM, lParam: w.LPARAM) callconv(w
|
||||||
.window_id = window_id,
|
.window_id = window_id,
|
||||||
.button = button,
|
.button = button,
|
||||||
.mods = mods,
|
.mods = mods,
|
||||||
.pos = .{ .x = x, .y = y },
|
.pos = .{ .x = @floatFromInt(point.x), .y = @floatFromInt(point.y) },
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
else => core.pushEvent(.{
|
else => core.pushEvent(.{
|
||||||
|
|
@ -351,7 +507,7 @@ fn wndProc(wnd: w.HWND, msg: u32, wParam: w.WPARAM, lParam: w.LPARAM) callconv(w
|
||||||
.window_id = window_id,
|
.window_id = window_id,
|
||||||
.button = button,
|
.button = button,
|
||||||
.mods = mods,
|
.mods = mods,
|
||||||
.pos = .{ .x = x, .y = y },
|
.pos = .{ .x = @floatFromInt(point.x), .y = @floatFromInt(point.y) },
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
|
@ -359,20 +515,21 @@ fn wndProc(wnd: w.HWND, msg: u32, wParam: w.WPARAM, lParam: w.LPARAM) callconv(w
|
||||||
return if (msg == w.WM_XBUTTONDOWN or msg == w.WM_XBUTTONUP) w.TRUE else 0;
|
return if (msg == w.WM_XBUTTONDOWN or msg == w.WM_XBUTTONUP) w.TRUE else 0;
|
||||||
},
|
},
|
||||||
w.WM_MOUSEMOVE => {
|
w.WM_MOUSEMOVE => {
|
||||||
const x: f64 = @floatFromInt(@as(i16, @truncate(lParam & 0xFFFF)));
|
const window_id = windowIdFromHwnd(hwnd);
|
||||||
const y: f64 = @floatFromInt(@as(i16, @truncate((lParam >> 16) & 0xFFFF)));
|
const point = w.pointFromLparam(lParam);
|
||||||
core.pushEvent(.{
|
core.pushEvent(.{
|
||||||
.mouse_motion = .{
|
.mouse_motion = .{
|
||||||
.window_id = window_id,
|
.window_id = window_id,
|
||||||
.pos = .{
|
.pos = .{
|
||||||
.x = x,
|
.x = @floatFromInt(point.x),
|
||||||
.y = y,
|
.y = @floatFromInt(point.y),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
return 0;
|
return 0;
|
||||||
},
|
},
|
||||||
w.WM_MOUSEWHEEL => {
|
w.WM_MOUSEWHEEL => {
|
||||||
|
const window_id = windowIdFromHwnd(hwnd);
|
||||||
const WHEEL_DELTA = 120.0;
|
const WHEEL_DELTA = 120.0;
|
||||||
const wheel_high_word: u16 = @truncate((wParam >> 16) & 0xffff);
|
const wheel_high_word: u16 = @truncate((wParam >> 16) & 0xffff);
|
||||||
const delta_y: f32 = @as(f32, @floatFromInt(@as(i16, @bitCast(wheel_high_word)))) / WHEEL_DELTA;
|
const delta_y: f32 = @as(f32, @floatFromInt(@as(i16, @bitCast(wheel_high_word)))) / WHEEL_DELTA;
|
||||||
|
|
@ -387,17 +544,17 @@ fn wndProc(wnd: w.HWND, msg: u32, wParam: w.WPARAM, lParam: w.LPARAM) callconv(w
|
||||||
return 0;
|
return 0;
|
||||||
},
|
},
|
||||||
w.WM_SETFOCUS => {
|
w.WM_SETFOCUS => {
|
||||||
|
const window_id = windowIdFromHwnd(hwnd);
|
||||||
core.pushEvent(.{ .focus_gained = .{ .window_id = window_id } });
|
core.pushEvent(.{ .focus_gained = .{ .window_id = window_id } });
|
||||||
return 0;
|
return 0;
|
||||||
},
|
},
|
||||||
w.WM_KILLFOCUS => {
|
w.WM_KILLFOCUS => {
|
||||||
|
const window_id = windowIdFromHwnd(hwnd);
|
||||||
core.pushEvent(.{ .focus_lost = .{ .window_id = window_id } });
|
core.pushEvent(.{ .focus_lost = .{ .window_id = window_id } });
|
||||||
return 0;
|
return 0;
|
||||||
},
|
},
|
||||||
else => return w.DefWindowProcW(wnd, msg, wParam, lParam),
|
else => return w.DefWindowProcW(hwnd, msg, wParam, lParam),
|
||||||
}
|
}
|
||||||
|
|
||||||
return w.DefWindowProcW(wnd, msg, wParam, lParam);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn keyFromScancode(scancode: u9) Key {
|
fn keyFromScancode(scancode: u9) Key {
|
||||||
|
|
@ -542,7 +699,10 @@ fn keyFromScancode(scancode: u9) Key {
|
||||||
return if (scancode > 0 and scancode <= table.len) table[scancode - 1] else .unknown;
|
return if (scancode > 0 and scancode <= table.len) table[scancode - 1] else .unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn fatalWin32(what: []const u8, last_error: u32) noreturn {
|
||||||
|
std.debug.panic("{s} failed, error={}", .{ what, last_error });
|
||||||
|
}
|
||||||
|
|
||||||
// TODO (win32) Implement consistent error handling when interfacing with the Windows API.
|
// TODO (win32) Implement consistent error handling when interfacing with the Windows API.
|
||||||
// TODO (win32) Support High DPI awareness
|
|
||||||
// TODO (win32) Consider to add support for mouse capture
|
// TODO (win32) Consider to add support for mouse capture
|
||||||
// TODO (win32) Change to using WM_INPUT for mouse movement.
|
// TODO (win32) Change to using WM_INPUT for mouse movement.
|
||||||
|
|
|
||||||
349
src/core/windowmsg.zig
Normal file
349
src/core/windowmsg.zig
Normal file
|
|
@ -0,0 +1,349 @@
|
||||||
|
const std = @import("std");
|
||||||
|
const win32 = @import("../win32.zig");
|
||||||
|
|
||||||
|
pub fn pointFromLparam(lparam: win32.LPARAM) win32.POINT {
|
||||||
|
return .{
|
||||||
|
.x = @as(i16, @bitCast(win32.loword(lparam))),
|
||||||
|
.y = @as(i16, @bitCast(win32.hiword(lparam))),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const MessageNode = struct {
|
||||||
|
tail_ref: *?*MessageNode,
|
||||||
|
hwnd: win32.HWND,
|
||||||
|
msg: u32,
|
||||||
|
wparam: win32.WPARAM,
|
||||||
|
lparam: win32.LPARAM,
|
||||||
|
old_tail: ?*MessageNode,
|
||||||
|
pub fn init(
|
||||||
|
self: *MessageNode,
|
||||||
|
tail_ref: *?*MessageNode,
|
||||||
|
hwnd: win32.HWND,
|
||||||
|
msg: u32,
|
||||||
|
wparam: win32.WPARAM,
|
||||||
|
lparam: win32.LPARAM,
|
||||||
|
) void {
|
||||||
|
if (tail_ref.*) |old_tail| {
|
||||||
|
std.debug.assert(old_tail.hwnd == hwnd);
|
||||||
|
}
|
||||||
|
self.* = .{
|
||||||
|
.tail_ref = tail_ref,
|
||||||
|
.hwnd = hwnd,
|
||||||
|
.msg = msg,
|
||||||
|
.wparam = wparam,
|
||||||
|
.lparam = lparam,
|
||||||
|
.old_tail = tail_ref.*,
|
||||||
|
};
|
||||||
|
tail_ref.* = self;
|
||||||
|
}
|
||||||
|
pub fn deinit(self: *MessageNode) void {
|
||||||
|
std.debug.assert(self.tail_ref.* == self);
|
||||||
|
self.tail_ref.* = self.old_tail;
|
||||||
|
}
|
||||||
|
pub fn fmtPath(self: *MessageNode) FmtPath {
|
||||||
|
return .{ .node = self };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fn writeMessageNodePath(
|
||||||
|
writer: anytype,
|
||||||
|
node: *MessageNode,
|
||||||
|
) !void {
|
||||||
|
if (node.old_tail) |old_tail| {
|
||||||
|
try writeMessageNodePath(writer, old_tail);
|
||||||
|
try writer.writeAll(" > ");
|
||||||
|
}
|
||||||
|
try writer.print("{s}:{}", .{ msg_name(node.msg) orelse "?", node.msg });
|
||||||
|
switch (node.msg) {
|
||||||
|
win32.WM_CAPTURECHANGED => {
|
||||||
|
try writer.print("({})", .{node.lparam});
|
||||||
|
},
|
||||||
|
win32.WM_SYSCOMMAND => {
|
||||||
|
try writer.print("(type=0x{x})", .{0xfff0 & node.wparam});
|
||||||
|
},
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const FmtPath = struct {
|
||||||
|
node: *MessageNode,
|
||||||
|
const Self = @This();
|
||||||
|
pub fn format(
|
||||||
|
self: Self,
|
||||||
|
comptime fmt: []const u8,
|
||||||
|
options: std.fmt.FormatOptions,
|
||||||
|
writer: anytype,
|
||||||
|
) @TypeOf(writer).Error!void {
|
||||||
|
_ = fmt;
|
||||||
|
_ = options;
|
||||||
|
try writeMessageNodePath(writer, self.node);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn msg_name(msg: u32) ?[]const u8 {
|
||||||
|
return switch (msg) {
|
||||||
|
0 => "WM_NULL",
|
||||||
|
1 => "WM_CREATE",
|
||||||
|
2 => "WM_DESTROY",
|
||||||
|
3 => "WM_MOVE",
|
||||||
|
5 => "WM_SIZE",
|
||||||
|
6 => "WM_ACTIVATE",
|
||||||
|
7 => "WM_SETFOCUS",
|
||||||
|
8 => "WM_KILLFOCUS",
|
||||||
|
10 => "WM_ENABLE",
|
||||||
|
11 => "WM_SETREDRAW",
|
||||||
|
12 => "WM_SETTEXT",
|
||||||
|
13 => "WM_GETTEXT",
|
||||||
|
14 => "WM_GETTEXTLENGTH",
|
||||||
|
15 => "WM_PAINT",
|
||||||
|
16 => "WM_CLOSE",
|
||||||
|
17 => "WM_QUERYENDSESSION",
|
||||||
|
18 => "WM_QUIT",
|
||||||
|
19 => "WM_QUERYOPEN",
|
||||||
|
20 => "WM_ERASEBKGND",
|
||||||
|
21 => "WM_SYSCOLORCHANGE",
|
||||||
|
22 => "WM_ENDSESSION",
|
||||||
|
24 => "WM_SHOWWINDOW",
|
||||||
|
25 => "WM_CTLCOLOR",
|
||||||
|
26 => "WM_WININICHANGE",
|
||||||
|
27 => "WM_DEVMODECHANGE",
|
||||||
|
28 => "WM_ACTIVATEAPP",
|
||||||
|
29 => "WM_FONTCHANGE",
|
||||||
|
30 => "WM_TIMECHANGE",
|
||||||
|
31 => "WM_CANCELMODE",
|
||||||
|
32 => "WM_SETCURSOR",
|
||||||
|
33 => "WM_MOUSEACTIVATE",
|
||||||
|
34 => "WM_CHILDACTIVATE",
|
||||||
|
35 => "WM_QUEUESYNC",
|
||||||
|
36 => "WM_GETMINMAXINFO",
|
||||||
|
38 => "WM_PAINTICON",
|
||||||
|
39 => "WM_ICONERASEBKGND",
|
||||||
|
40 => "WM_NEXTDLGCTL",
|
||||||
|
42 => "WM_SPOOLERSTATUS",
|
||||||
|
43 => "WM_DRAWITEM",
|
||||||
|
44 => "WM_MEASUREITEM",
|
||||||
|
45 => "WM_DELETEITEM",
|
||||||
|
46 => "WM_VKEYTOITEM",
|
||||||
|
47 => "WM_CHARTOITEM",
|
||||||
|
48 => "WM_SETFONT",
|
||||||
|
49 => "WM_GETFONT",
|
||||||
|
50 => "WM_SETHOTKEY",
|
||||||
|
51 => "WM_GETHOTKEY",
|
||||||
|
55 => "WM_QUERYDRAGICON",
|
||||||
|
57 => "WM_COMPAREITEM",
|
||||||
|
61 => "WM_GETOBJECT",
|
||||||
|
65 => "WM_COMPACTING",
|
||||||
|
68 => "WM_COMMNOTIFY",
|
||||||
|
70 => "WM_WINDOWPOSCHANGING",
|
||||||
|
71 => "WM_WINDOWPOSCHANGED",
|
||||||
|
72 => "WM_POWER",
|
||||||
|
73 => "WM_COPYGLOBALDATA",
|
||||||
|
74 => "WM_COPYDATA",
|
||||||
|
75 => "WM_CANCELJOURNAL",
|
||||||
|
78 => "WM_NOTIFY",
|
||||||
|
80 => "WM_INPUTLANGCHANGEREQUEST",
|
||||||
|
81 => "WM_INPUTLANGCHANGE",
|
||||||
|
82 => "WM_TCARD",
|
||||||
|
83 => "WM_HELP",
|
||||||
|
84 => "WM_USERCHANGED",
|
||||||
|
85 => "WM_NOTIFYFORMAT",
|
||||||
|
123 => "WM_CONTEXTMENU",
|
||||||
|
124 => "WM_STYLECHANGING",
|
||||||
|
125 => "WM_STYLECHANGED",
|
||||||
|
126 => "WM_DISPLAYCHANGE",
|
||||||
|
127 => "WM_GETICON",
|
||||||
|
128 => "WM_SETICON",
|
||||||
|
129 => "WM_NCCREATE",
|
||||||
|
130 => "WM_NCDESTROY",
|
||||||
|
131 => "WM_NCCALCSIZE",
|
||||||
|
132 => "WM_NCHITTEST",
|
||||||
|
133 => "WM_NCPAINT",
|
||||||
|
134 => "WM_NCACTIVATE",
|
||||||
|
135 => "WM_GETDLGCODE",
|
||||||
|
136 => "WM_SYNCPAINT",
|
||||||
|
160 => "WM_NCMOUSEMOVE",
|
||||||
|
161 => "WM_NCLBUTTONDOWN",
|
||||||
|
162 => "WM_NCLBUTTONUP",
|
||||||
|
163 => "WM_NCLBUTTONDBLCLK",
|
||||||
|
164 => "WM_NCRBUTTONDOWN",
|
||||||
|
165 => "WM_NCRBUTTONUP",
|
||||||
|
166 => "WM_NCRBUTTONDBLCLK",
|
||||||
|
167 => "WM_NCMBUTTONDOWN",
|
||||||
|
168 => "WM_NCMBUTTONUP",
|
||||||
|
169 => "WM_NCMBUTTONDBLCLK",
|
||||||
|
171 => "WM_NCXBUTTONDOWN",
|
||||||
|
172 => "WM_NCXBUTTONUP",
|
||||||
|
173 => "WM_NCXBUTTONDBLCLK",
|
||||||
|
255 => "WM_INPUT",
|
||||||
|
256 => "WM_KEYDOWN",
|
||||||
|
257 => "WM_KEYUP",
|
||||||
|
258 => "WM_CHAR",
|
||||||
|
259 => "WM_DEADCHAR",
|
||||||
|
260 => "WM_SYSKEYDOWN",
|
||||||
|
261 => "WM_SYSKEYUP",
|
||||||
|
262 => "WM_SYSCHAR",
|
||||||
|
263 => "WM_SYSDEADCHAR",
|
||||||
|
265 => "WM_UNICHAR",
|
||||||
|
266 => "WM_CONVERTREQUEST",
|
||||||
|
267 => "WM_CONVERTRESULT",
|
||||||
|
268 => "WM_INTERIM",
|
||||||
|
269 => "WM_IME_STARTCOMPOSITION",
|
||||||
|
270 => "WM_IME_ENDCOMPOSITION",
|
||||||
|
271 => "WM_IME_COMPOSITION",
|
||||||
|
272 => "WM_INITDIALOG",
|
||||||
|
273 => "WM_COMMAND",
|
||||||
|
274 => "WM_SYSCOMMAND",
|
||||||
|
275 => "WM_TIMER",
|
||||||
|
276 => "WM_HSCROLL",
|
||||||
|
277 => "WM_VSCROLL",
|
||||||
|
278 => "WM_INITMENU",
|
||||||
|
279 => "WM_INITMENUPOPUP",
|
||||||
|
280 => "WM_SYSTIMER",
|
||||||
|
287 => "WM_MENUSELECT",
|
||||||
|
288 => "WM_MENUCHAR",
|
||||||
|
289 => "WM_ENTERIDLE",
|
||||||
|
290 => "WM_MENURBUTTONUP",
|
||||||
|
291 => "WM_MENUDRAG",
|
||||||
|
292 => "WM_MENUGETOBJECT",
|
||||||
|
293 => "WM_UNINITMENUPOPUP",
|
||||||
|
294 => "WM_MENUCOMMAND",
|
||||||
|
295 => "WM_CHANGEUISTATE",
|
||||||
|
296 => "WM_UPDATEUISTATE",
|
||||||
|
297 => "WM_QUERYUISTATE",
|
||||||
|
305 => "WM_LBTRACKPOINT",
|
||||||
|
306 => "WM_CTLCOLORMSGBOX",
|
||||||
|
307 => "WM_CTLCOLOREDIT",
|
||||||
|
308 => "WM_CTLCOLORLISTBOX",
|
||||||
|
309 => "WM_CTLCOLORBTN",
|
||||||
|
310 => "WM_CTLCOLORDLG",
|
||||||
|
311 => "WM_CTLCOLORSCROLLBAR",
|
||||||
|
312 => "WM_CTLCOLORSTATIC",
|
||||||
|
512 => "WM_MOUSEMOVE",
|
||||||
|
513 => "WM_LBUTTONDOWN",
|
||||||
|
514 => "WM_LBUTTONUP",
|
||||||
|
515 => "WM_LBUTTONDBLCLK",
|
||||||
|
516 => "WM_RBUTTONDOWN",
|
||||||
|
517 => "WM_RBUTTONUP",
|
||||||
|
518 => "WM_RBUTTONDBLCLK",
|
||||||
|
519 => "WM_MBUTTONDOWN",
|
||||||
|
520 => "WM_MBUTTONUP",
|
||||||
|
521 => "WM_MBUTTONDBLCLK",
|
||||||
|
522 => "WM_MOUSEWHEEL",
|
||||||
|
523 => "WM_XBUTTONDOWN",
|
||||||
|
524 => "WM_XBUTTONUP",
|
||||||
|
525 => "WM_XBUTTONDBLCLK",
|
||||||
|
526 => "WM_MOUSEHWHEEL",
|
||||||
|
528 => "WM_PARENTNOTIFY",
|
||||||
|
529 => "WM_ENTERMENULOOP",
|
||||||
|
530 => "WM_EXITMENULOOP",
|
||||||
|
531 => "WM_NEXTMENU",
|
||||||
|
532 => "WM_SIZING",
|
||||||
|
533 => "WM_CAPTURECHANGED",
|
||||||
|
534 => "WM_MOVING",
|
||||||
|
536 => "WM_POWERBROADCAST",
|
||||||
|
537 => "WM_DEVICECHANGE",
|
||||||
|
544 => "WM_MDICREATE",
|
||||||
|
545 => "WM_MDIDESTROY",
|
||||||
|
546 => "WM_MDIACTIVATE",
|
||||||
|
547 => "WM_MDIRESTORE",
|
||||||
|
548 => "WM_MDINEXT",
|
||||||
|
549 => "WM_MDIMAXIMIZE",
|
||||||
|
550 => "WM_MDITILE",
|
||||||
|
551 => "WM_MDICASCADE",
|
||||||
|
552 => "WM_MDIICONARRANGE",
|
||||||
|
553 => "WM_MDIGETACTIVE",
|
||||||
|
560 => "WM_MDISETMENU",
|
||||||
|
561 => "WM_ENTERSIZEMOVE",
|
||||||
|
562 => "WM_EXITSIZEMOVE",
|
||||||
|
563 => "WM_DROPFILES",
|
||||||
|
564 => "WM_MDIREFRESHMENU",
|
||||||
|
640 => "WM_IME_REPORT",
|
||||||
|
641 => "WM_IME_SETCONTEXT",
|
||||||
|
642 => "WM_IME_NOTIFY",
|
||||||
|
643 => "WM_IME_CONTROL",
|
||||||
|
644 => "WM_IME_COMPOSITIONFULL",
|
||||||
|
645 => "WM_IME_SELECT",
|
||||||
|
646 => "WM_IME_CHAR",
|
||||||
|
648 => "WM_IME_REQUEST",
|
||||||
|
656 => "WM_IME_KEYDOWN",
|
||||||
|
657 => "WM_IME_KEYUP",
|
||||||
|
672 => "WM_NCMOUSEHOVER",
|
||||||
|
673 => "WM_MOUSEHOVER",
|
||||||
|
674 => "WM_NCMOUSELEAVE",
|
||||||
|
675 => "WM_MOUSELEAVE",
|
||||||
|
768 => "WM_CUT",
|
||||||
|
769 => "WM_COPY",
|
||||||
|
770 => "WM_PASTE",
|
||||||
|
771 => "WM_CLEAR",
|
||||||
|
772 => "WM_UNDO",
|
||||||
|
773 => "WM_RENDERFORMAT",
|
||||||
|
774 => "WM_RENDERALLFORMATS",
|
||||||
|
775 => "WM_DESTROYCLIPBOARD",
|
||||||
|
776 => "WM_DRAWCLIPBOARD",
|
||||||
|
777 => "WM_PAINTCLIPBOARD",
|
||||||
|
778 => "WM_VSCROLLCLIPBOARD",
|
||||||
|
779 => "WM_SIZECLIPBOARD",
|
||||||
|
780 => "WM_ASKCBFORMATNAME",
|
||||||
|
781 => "WM_CHANGECBCHAIN",
|
||||||
|
782 => "WM_HSCROLLCLIPBOARD",
|
||||||
|
783 => "WM_QUERYNEWPALETTE",
|
||||||
|
784 => "WM_PALETTEISCHANGING",
|
||||||
|
785 => "WM_PALETTECHANGED",
|
||||||
|
786 => "WM_HOTKEY",
|
||||||
|
791 => "WM_PRINT",
|
||||||
|
792 => "WM_PRINTCLIENT",
|
||||||
|
793 => "WM_APPCOMMAND",
|
||||||
|
799 => "WM_DWMNCRENDERINGCHANGED",
|
||||||
|
856 => "WM_HANDHELDFIRST",
|
||||||
|
863 => "WM_HANDHELDLAST",
|
||||||
|
864 => "WM_AFXFIRST",
|
||||||
|
895 => "WM_AFXLAST",
|
||||||
|
896 => "WM_PENWINFIRST",
|
||||||
|
897 => "WM_RCRESULT",
|
||||||
|
898 => "WM_HOOKRCRESULT",
|
||||||
|
899 => "WM_GLOBALRCCHANGE",
|
||||||
|
900 => "WM_SKB",
|
||||||
|
901 => "WM_PENCTL",
|
||||||
|
902 => "WM_PENMISC",
|
||||||
|
903 => "WM_CTLINIT",
|
||||||
|
904 => "WM_PENEVENT",
|
||||||
|
911 => "WM_PENWINLAST",
|
||||||
|
1024 => "WM_USER+0",
|
||||||
|
1025 => "WM_USER+1",
|
||||||
|
1026 => "WM_USER+2",
|
||||||
|
1027 => "WM_USER+3",
|
||||||
|
1028 => "WM_USER+4",
|
||||||
|
1029 => "WM_USER+5",
|
||||||
|
1030 => "WM_USER+6",
|
||||||
|
else => null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getHitName(hit: win32.LRESULT) ?[]const u8 {
|
||||||
|
return switch (hit) {
|
||||||
|
win32.HTERROR => "err",
|
||||||
|
win32.HTTRANSPARENT => "transprnt",
|
||||||
|
win32.HTNOWHERE => "nowhere",
|
||||||
|
win32.HTCLIENT => "client",
|
||||||
|
win32.HTCAPTION => "caption",
|
||||||
|
win32.HTSYSMENU => "sysmnu",
|
||||||
|
win32.HTSIZE => "size",
|
||||||
|
win32.HTMENU => "menu",
|
||||||
|
win32.HTHSCROLL => "hscroll",
|
||||||
|
win32.HTVSCROLL => "vscroll",
|
||||||
|
win32.HTMINBUTTON => "minbtn",
|
||||||
|
win32.HTMAXBUTTON => "max",
|
||||||
|
win32.HTLEFT => "left",
|
||||||
|
win32.HTRIGHT => "right",
|
||||||
|
win32.HTTOP => "top",
|
||||||
|
win32.HTTOPLEFT => "topleft",
|
||||||
|
win32.HTTOPRIGHT => "topright",
|
||||||
|
win32.HTBOTTOM => "bottom",
|
||||||
|
win32.HTBOTTOMLEFT => "botmleft",
|
||||||
|
win32.HTBOTTOMRIGHT => "botmright",
|
||||||
|
win32.HTBORDER => "border",
|
||||||
|
win32.HTCLOSE => "close",
|
||||||
|
win32.HTHELP => "help",
|
||||||
|
else => null,
|
||||||
|
};
|
||||||
|
}
|
||||||
14
src/core/windows/win32.manifest
Normal file
14
src/core/windows/win32.manifest
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
|
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
|
||||||
|
<asmv3:application>
|
||||||
|
<asmv3:windowsSettings>
|
||||||
|
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/pm</dpiAware>
|
||||||
|
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
|
||||||
|
</asmv3:windowsSettings>
|
||||||
|
</asmv3:application>
|
||||||
|
<dependency>
|
||||||
|
<dependentAssembly>
|
||||||
|
<assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*" />
|
||||||
|
</dependentAssembly>
|
||||||
|
</dependency>
|
||||||
|
</assembly>
|
||||||
116
src/win32.zig
116
src/win32.zig
|
|
@ -27,6 +27,13 @@ pub const WINAPI = w.WINAPI;
|
||||||
pub const TRUE = w.TRUE;
|
pub const TRUE = w.TRUE;
|
||||||
pub const FALSE = w.FALSE;
|
pub const FALSE = w.FALSE;
|
||||||
|
|
||||||
|
pub const SIZE = extern struct {
|
||||||
|
cx: i32,
|
||||||
|
cy: i32,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub extern "kernel32" fn GetLastError() callconv(w.WINAPI) u32;
|
||||||
|
|
||||||
//pub const GetModuleHandleW = w.kernel32.GetModuleHandleW;
|
//pub const GetModuleHandleW = w.kernel32.GetModuleHandleW;
|
||||||
// TODO: this type is limited to platform 'windows5.1.2600'
|
// TODO: this type is limited to platform 'windows5.1.2600'
|
||||||
pub extern "kernel32" fn GetModuleHandleW(
|
pub extern "kernel32" fn GetModuleHandleW(
|
||||||
|
|
@ -99,19 +106,12 @@ pub extern "user32" fn GetWindowRect(
|
||||||
lpRect: ?*RECT,
|
lpRect: ?*RECT,
|
||||||
) callconv(@import("std").os.windows.WINAPI) BOOL;
|
) callconv(@import("std").os.windows.WINAPI) BOOL;
|
||||||
|
|
||||||
// TODO: this type is limited to platform 'windows5.0'
|
pub extern "user32" fn AdjustWindowRectExForDpi(
|
||||||
pub extern "user32" fn AdjustWindowRect(
|
|
||||||
lpRect: ?*RECT,
|
|
||||||
dwStyle: WINDOW_STYLE,
|
|
||||||
bMenu: BOOL,
|
|
||||||
) callconv(@import("std").os.windows.WINAPI) BOOL;
|
|
||||||
|
|
||||||
// TODO: this type is limited to platform 'windows5.0'
|
|
||||||
pub extern "user32" fn AdjustWindowRectEx(
|
|
||||||
lpRect: ?*RECT,
|
lpRect: ?*RECT,
|
||||||
dwStyle: WINDOW_STYLE,
|
dwStyle: WINDOW_STYLE,
|
||||||
bMenu: BOOL,
|
bMenu: BOOL,
|
||||||
dwExStyle: WINDOW_EX_STYLE,
|
dwExStyle: WINDOW_EX_STYLE,
|
||||||
|
dpi: u32,
|
||||||
) callconv(@import("std").os.windows.WINAPI) BOOL;
|
) callconv(@import("std").os.windows.WINAPI) BOOL;
|
||||||
|
|
||||||
// TODO: this type is limited to platform 'windows5.0'
|
// TODO: this type is limited to platform 'windows5.0'
|
||||||
|
|
@ -271,6 +271,14 @@ pub extern "user32" fn SetWindowLongW(
|
||||||
dwNewLong: i32,
|
dwNewLong: i32,
|
||||||
) callconv(@import("std").os.windows.WINAPI) i32;
|
) callconv(@import("std").os.windows.WINAPI) i32;
|
||||||
|
|
||||||
|
pub extern "user32" fn BringWindowToTop(
|
||||||
|
hWnd: ?HWND,
|
||||||
|
) callconv(@import("std").os.windows.WINAPI) BOOL;
|
||||||
|
|
||||||
|
pub extern "user32" fn SetForegroundWindow(
|
||||||
|
hWnd: ?HWND,
|
||||||
|
) callconv(@import("std").os.windows.WINAPI) BOOL;
|
||||||
|
|
||||||
//pub extern "user32" fn SetWindowPos(hWnd: HWND, hWndInsertAfter: HWND, X: i32, Y: i32, cx: i32, cy: i32, uFlags: u32) callconv(WINAPI) BOOL;
|
//pub extern "user32" fn SetWindowPos(hWnd: HWND, hWndInsertAfter: HWND, X: i32, Y: i32, cx: i32, cy: i32, uFlags: u32) callconv(WINAPI) BOOL;
|
||||||
pub extern "user32" fn SetWindowPos(
|
pub extern "user32" fn SetWindowPos(
|
||||||
hWnd: ?HWND,
|
hWnd: ?HWND,
|
||||||
|
|
@ -1206,13 +1214,13 @@ pub const LPDIENUMDEVICEOBJECTSCALLBACKW = switch (@import("builtin").zig_backen
|
||||||
) callconv(@import("std").os.windows.WINAPI) BOOL,
|
) callconv(@import("std").os.windows.WINAPI) BOOL,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const IDI_APPLICATION = 32512;
|
pub const IDI_APPLICATION: [*:0]align(1) const u16 = @ptrFromInt(32512);
|
||||||
pub extern "user32" fn LoadIconW(
|
pub extern "user32" fn LoadIconW(
|
||||||
hInstance: ?HINSTANCE,
|
hInstance: ?HINSTANCE,
|
||||||
lpIconName: ?[*:0]align(1) const u16,
|
lpIconName: ?[*:0]align(1) const u16,
|
||||||
) callconv(@import("std").os.windows.WINAPI) ?HICON;
|
) callconv(@import("std").os.windows.WINAPI) ?HICON;
|
||||||
|
|
||||||
pub const IDC_ARROW = 32512;
|
pub const IDC_ARROW: [*:0]align(1) const u16 = @ptrFromInt(32512);
|
||||||
pub const IDC_HAND = 32649;
|
pub const IDC_HAND = 32649;
|
||||||
pub const IDC_HELP = 32651;
|
pub const IDC_HELP = 32651;
|
||||||
pub const IDC_IBEAM = 32513;
|
pub const IDC_IBEAM = 32513;
|
||||||
|
|
@ -1636,6 +1644,7 @@ pub const WM_QUERYOPEN = @as(u32, 19);
|
||||||
pub const WM_ENDSESSION = @as(u32, 22);
|
pub const WM_ENDSESSION = @as(u32, 22);
|
||||||
pub const WM_QUIT = @as(u32, 18);
|
pub const WM_QUIT = @as(u32, 18);
|
||||||
pub const WM_GETMINMAXINFO = @as(u32, 36);
|
pub const WM_GETMINMAXINFO = @as(u32, 36);
|
||||||
|
pub const WM_WINDOWPOSCHANGED = @as(u32, 71);
|
||||||
pub const WM_KEYFIRST = @as(u32, 256);
|
pub const WM_KEYFIRST = @as(u32, 256);
|
||||||
pub const WM_KEYDOWN = @as(u32, 256);
|
pub const WM_KEYDOWN = @as(u32, 256);
|
||||||
pub const WM_KEYUP = @as(u32, 257);
|
pub const WM_KEYUP = @as(u32, 257);
|
||||||
|
|
@ -1712,6 +1721,7 @@ pub const WM_SIZING = @as(u32, 532);
|
||||||
pub const WM_CAPTURECHANGED = @as(u32, 533);
|
pub const WM_CAPTURECHANGED = @as(u32, 533);
|
||||||
pub const WM_MOVING = @as(u32, 534);
|
pub const WM_MOVING = @as(u32, 534);
|
||||||
pub const WM_POWERBROADCAST = @as(u32, 536);
|
pub const WM_POWERBROADCAST = @as(u32, 536);
|
||||||
|
pub const WM_DPICHANGED = @as(u32, 736);
|
||||||
|
|
||||||
pub const KEYBD_EVENT_FLAGS = packed struct(u32) {
|
pub const KEYBD_EVENT_FLAGS = packed struct(u32) {
|
||||||
EXTENDEDKEY: u1 = 0,
|
EXTENDEDKEY: u1 = 0,
|
||||||
|
|
@ -2604,6 +2614,10 @@ pub extern "kernel32" fn GetProcAddress(
|
||||||
hModule: ?*anyopaque,
|
hModule: ?*anyopaque,
|
||||||
lpProcName: ?[*:0]const u8,
|
lpProcName: ?[*:0]const u8,
|
||||||
) callconv(WINAPI) ?*const fn () callconv(WINAPI) isize;
|
) callconv(WINAPI) ?*const fn () callconv(WINAPI) isize;
|
||||||
|
pub extern "kernel32" fn ExitProcess(
|
||||||
|
uExitCode: u32,
|
||||||
|
) callconv(@import("std").os.windows.WINAPI) noreturn;
|
||||||
|
|
||||||
pub const INFINITE = 4294967295;
|
pub const INFINITE = 4294967295;
|
||||||
pub const SECURITY_ATTRIBUTES = extern struct {
|
pub const SECURITY_ATTRIBUTES = extern struct {
|
||||||
nLength: u32,
|
nLength: u32,
|
||||||
|
|
@ -4157,3 +4171,83 @@ pub const AUDCLNT_E_HEADTRACKING_ENABLED = -2004287440;
|
||||||
pub const AUDCLNT_E_HEADTRACKING_UNSUPPORTED = -2004287424;
|
pub const AUDCLNT_E_HEADTRACKING_UNSUPPORTED = -2004287424;
|
||||||
pub const AUDCLNT_E_EFFECT_NOT_AVAILABLE = -2004287423;
|
pub const AUDCLNT_E_EFFECT_NOT_AVAILABLE = -2004287423;
|
||||||
pub const AUDCLNT_E_EFFECT_STATE_READ_ONLY = -2004287422;
|
pub const AUDCLNT_E_EFFECT_STATE_READ_ONLY = -2004287422;
|
||||||
|
|
||||||
|
pub extern "user32" fn GetDpiForWindow(
|
||||||
|
hwnd: ?HWND,
|
||||||
|
) callconv(@import("std").os.windows.WINAPI) u32;
|
||||||
|
|
||||||
|
pub fn dpiFromHwnd(hwnd: HWND) u32 {
|
||||||
|
const value = GetDpiForWindow(hwnd);
|
||||||
|
if (value == 0) std.debug.panic(
|
||||||
|
"GetDpiForWindow failed, error={}",
|
||||||
|
.{GetLastError()},
|
||||||
|
);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn getDpiFactor(dpi: u32) f32 {
|
||||||
|
std.debug.assert(dpi >= 96);
|
||||||
|
return @as(f32, @floatFromInt(dpi)) / 96.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pxFromPt(comptime T: type, value: T, dpi: u32) T {
|
||||||
|
switch (@typeInfo(T)) {
|
||||||
|
.float => return value * getDpiFactor(dpi),
|
||||||
|
.int => return @intFromFloat(@round(@as(f32, @floatFromInt(value)) * getDpiFactor(dpi))),
|
||||||
|
else => @compileError("scaleDpi does not support type " ++ @typeName(@TypeOf(value))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ptFromPx(comptime T: type, value: T, dpi: u32) T {
|
||||||
|
switch (@typeInfo(T)) {
|
||||||
|
.float => return value / getDpiFactor(dpi),
|
||||||
|
.int => return @intFromFloat(@round(@as(f32, @floatFromInt(value)) / getDpiFactor(dpi))),
|
||||||
|
else => @compileError("scaleDpi does not support type " ++ @typeName(@TypeOf(value))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const CREATESTRUCTW = extern struct {
|
||||||
|
lpCreateParams: ?*anyopaque,
|
||||||
|
hInstance: ?HINSTANCE,
|
||||||
|
hMenu: ?HMENU,
|
||||||
|
hwndParent: ?HWND,
|
||||||
|
cy: i32,
|
||||||
|
cx: i32,
|
||||||
|
y: i32,
|
||||||
|
x: i32,
|
||||||
|
style: i32,
|
||||||
|
lpszName: ?[*:0]const u16,
|
||||||
|
lpszClass: ?[*:0]const u16,
|
||||||
|
dwExStyle: u32,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn loword(value: anytype) u16 {
|
||||||
|
switch (@typeInfo(@TypeOf(value))) {
|
||||||
|
.int => |int| switch (int.signedness) {
|
||||||
|
.signed => return loword(@as(@Type(.{ .int = .{ .signedness = .unsigned, .bits = int.bits } }), @bitCast(value))),
|
||||||
|
.unsigned => return if (int.bits <= 16) value else @intCast(0xffff & value),
|
||||||
|
},
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
@compileError("unsupported type " ++ @typeName(@TypeOf(value)));
|
||||||
|
}
|
||||||
|
pub fn hiword(value: anytype) u16 {
|
||||||
|
switch (@typeInfo(@TypeOf(value))) {
|
||||||
|
.int => |int| switch (int.signedness) {
|
||||||
|
.signed => return hiword(@as(@Type(.{ .int = .{ .signedness = .unsigned, .bits = int.bits } }), @bitCast(value))),
|
||||||
|
.unsigned => return @intCast(0xffff & (value >> 16)),
|
||||||
|
},
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
@compileError("unsupported type " ++ @typeName(@TypeOf(value)));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn xFromLparam(lparam: LPARAM) i16 {
|
||||||
|
return @bitCast(loword(lparam));
|
||||||
|
}
|
||||||
|
fn yFromLparam(lparam: LPARAM) i16 {
|
||||||
|
return @bitCast(hiword(lparam));
|
||||||
|
}
|
||||||
|
pub fn pointFromLparam(lparam: LPARAM) POINT {
|
||||||
|
return POINT{ .x = xFromLparam(lparam), .y = yFromLparam(lparam) };
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue