# HG changeset patch # User sam # Date 1722162821 -25200 # Node ID bfb75c934f4e5ff9bf4d35e270fac2f638871737 # Parent 2b5ca798f6d6fda6e9e3dd35807a983d47c2b3e2 add: window focus handling, improve window api a bit diff -r 2b5ca798f6d6 -r bfb75c934f4e semiconginev2/events.nim --- a/semiconginev2/events.nim Sun Jul 28 00:17:34 2024 +0700 +++ b/semiconginev2/events.nim Sun Jul 28 17:33:41 2024 +0700 @@ -5,6 +5,7 @@ KeyPressed, KeyReleased MousePressed, MouseReleased, MouseMoved, MouseWheel + GotFocus, LostFocus Key* {.size: sizeof(cint), pure.} = enum UNKNOWN Escape, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12 @@ -31,5 +32,9 @@ x*, y*: int of MouseWheel: amount*: float32 + of GotFocus: + discard + of LostFocus: + discard else: discard diff -r 2b5ca798f6d6 -r bfb75c934f4e semiconginev2/input.nim --- a/semiconginev2/input.nim Sun Jul 28 00:17:34 2024 +0700 +++ b/semiconginev2/input.nim Sun Jul 28 17:33:41 2024 +0700 @@ -12,9 +12,10 @@ windowWasResized: bool = true windowIsMinimized: bool = false lockMouse: bool = false + hasFocus: bool = false # warning, shit is not thread safe -var input: Input +var input = Input() proc UpdateInputs*(): bool = # reset input states @@ -26,7 +27,7 @@ input.mouseMove = NewVec2f() input.windowWasResized = false - if input.lockMouse: + if input.lockMouse and input.hasFocus: SetMousePosition(vulkan.window, x=int(vulkan.swapchain.width div 2), y=int(vulkan.swapchain.height div 2)) var killed = false @@ -58,6 +59,10 @@ input.windowIsMinimized = true of RestoredWindow: input.windowIsMinimized = false + of GotFocus: + input.hasFocus = true + of LostFocus: + input.hasFocus = false return not killed @@ -81,6 +86,7 @@ proc WindowWasResized*(): auto = input.windowWasResized proc WindowIsMinimized*(): auto = input.windowIsMinimized proc LockMouse*(value: bool) = input.lockMouse = value +proc HasFocus*(): bool = input.hasFocus # actions as a slight abstraction over raw input diff -r 2b5ca798f6d6 -r bfb75c934f4e semiconginev2/rendering.nim --- a/semiconginev2/rendering.nim Sun Jul 28 00:17:34 2024 +0700 +++ b/semiconginev2/rendering.nim Sun Jul 28 17:33:41 2024 +0700 @@ -331,13 +331,12 @@ vkDestroyDebugUtilsMessengerEXT(vulkan.instance, vulkan.debugMessenger, nil) vkDestroyInstance(vulkan.instance, nil) -proc ShowSystemCursor*() = vulkan.window.ShowSystemCursor() -proc HideSystemCursor*() = vulkan.window.HideSystemCursor() +proc ShowSystemCursor*(value: bool) = vulkan.window.ShowSystemCursor(value) proc Fullscreen*(): bool = fullscreen -proc `Fullscreen=`*(enable: bool) = +proc SetFullscreen*(enable: bool) = if enable != fullscreen: fullscreen = enable - vulkan.window.Fullscreen(fullscreen) + vulkan.window.SetFullscreen(fullscreen) proc GetAspectRatio*(): float32 = assert vulkan.swapchain != nil, "Swapchain has not been initialized yet" diff -r 2b5ca798f6d6 -r bfb75c934f4e semiconginev2/rendering/platform/linux.nim --- a/semiconginev2/rendering/platform/linux.nim Sun Jul 28 00:17:34 2024 +0700 +++ b/semiconginev2/rendering/platform/linux.nim Sun Jul 28 17:33:41 2024 +0700 @@ -81,7 +81,7 @@ # foregroundColor, backgroundColor ) checkXlibResult XSetStandardProperties(display, window, title, "window", 0, nil, 0, nil) - checkXlibResult XSelectInput(display, window, PointerMotionMask or ButtonPressMask or ButtonReleaseMask or KeyPressMask or KeyReleaseMask or ExposureMask) + checkXlibResult XSelectInput(display, window, PointerMotionMask or ButtonPressMask or ButtonReleaseMask or KeyPressMask or KeyReleaseMask or ExposureMask or FocusChangeMask) checkXlibResult XMapWindow(display, window) deleteMessage = XInternAtom(display, "WM_DELETE_WINDOW", XBool(false)) @@ -97,7 +97,7 @@ proc SetTitle*(window: NativeWindow, title: string) = checkXlibResult XSetStandardProperties(window.display, window.window, title, "window", 0, nil, 0, nil) -proc Fullscreen*(window: var NativeWindow, enable: bool) = +proc SetFullscreen*(window: var NativeWindow, enable: bool) = var wm_state = window.display.XInternAtom("_NET_WM_STATE", 0) wm_fullscreen = window.display.XInternAtom("_NET_WM_STATE_FULLSCREEN", 0) @@ -127,13 +127,13 @@ ) checkXlibResult window.display.XFlush() -proc HideSystemCursor*(window: NativeWindow) = - checkXlibResult XDefineCursor(window.display, window.window, window.emptyCursor) - checkXlibResult window.display.XFlush() - -proc ShowSystemCursor*(window: NativeWindow) = - checkXlibResult XUndefineCursor(window.display, window.window) - checkXlibResult window.display.XFlush() +proc ShowSystemCursor*(window: NativeWindow, value: bool) = + if value == true: + checkXlibResult XUndefineCursor(window.display, window.window) + checkXlibResult window.display.XFlush() + else: + checkXlibResult XDefineCursor(window.display, window.window, window.emptyCursor) + checkXlibResult window.display.XFlush() proc Destroy*(window: NativeWindow) = checkXlibResult window.display.XFreeCursor(window.emptyCursor) @@ -175,6 +175,10 @@ of MotionNotify: let motion = cast[PXMotionEvent](addr(event)) result.add Event(eventType: MouseMoved, x: motion.x, y: motion.y) + of FocusIn: + result.add Event(eventType: GotFocus) + of FocusOut: + result.add Event(eventType: LostFocus) of ConfigureNotify, Expose: result.add Event(eventType: ResizedWindow) else: diff -r 2b5ca798f6d6 -r bfb75c934f4e semiconginev2/rendering/platform/windows.nim --- a/semiconginev2/rendering/platform/windows.nim Sun Jul 28 00:17:34 2024 +0700 +++ b/semiconginev2/rendering/platform/windows.nim Sun Jul 28 17:33:41 2024 +0700 @@ -96,6 +96,10 @@ currentEvents.add(Event(eventType: MinimizedWindow)) elif wParam == SIZE_RESTORED: currentEvents.add(Event(eventType: RestoredWindow)) + of WM_SETFOCUS: + currentEvents.add(Event(eventType: GotFocus)) + of WM_KILLFOCUS: + currentEvents.add(Event(eventType: LostFocus)) of WM_SETCURSOR: if LOWORD(lParam) == HTCLIENT: SetCursor(currentCursor) @@ -148,7 +152,7 @@ # inspired by the one and only, Raymond Chen # https://devblogs.microsoft.com/oldnewthing/20100412-00/?p=14353 -proc Fullscreen*(window: var NativeWindow, enable: bool) = +proc SetFullscreen*(window: var NativeWindow, enable: bool) = let dwStyle: DWORD = GetWindowLong(window.hwnd, GWL_STYLE) if enable: var mi = MONITORINFO(cbSize: DWORD(sizeof(MONITORINFO))) @@ -160,13 +164,13 @@ SetWindowPlacement(window.hwnd, addr window.g_wpPrev) SetWindowPos(window.hwnd, HWND(0), 0, 0, 0, 0, SWP_NOMOVE or SWP_NOSIZE or SWP_NOZORDER or SWP_NOOWNERZORDER or SWP_FRAMECHANGED) -proc HideSystemCursor*(window: NativeWindow) = - currentCursor = invisibleCursor - SetCursor(currentCursor) - -proc ShowSystemCursor*(window: NativeWindow) = - currentCursor = defaultCursor - SetCursor(currentCursor) +proc ShowSystemCursor*(window: NativeWindow, value: bool) = + if value == true: + currentCursor = defaultCursor + SetCursor(currentCursor) + else: + currentCursor = invisibleCursor + SetCursor(currentCursor) proc Destroy*(window: NativeWindow) = discard diff -r 2b5ca798f6d6 -r bfb75c934f4e tests/test_gltf.nim --- a/tests/test_gltf.nim Sun Jul 28 00:17:34 2024 +0700 +++ b/tests/test_gltf.nim Sun Jul 28 17:33:41 2024 +0700 @@ -171,6 +171,7 @@ var renderpass = CreateDirectPresentationRenderPass(depthBuffer = true, samples = VK_SAMPLE_COUNT_4_BIT) SetupSwapchain(renderpass = renderpass) LockMouse(true) + ShowSystemCursor(false) # tests a simple triangle with minimalistic shader and vertex format test_gltf(time)