changeset 1256:bfb75c934f4e

add: window focus handling, improve window api a bit
author sam <sam@basx.dev>
date Sun, 28 Jul 2024 17:33:41 +0700
parents 2b5ca798f6d6
children e9b8d87b9883
files semiconginev2/events.nim semiconginev2/input.nim semiconginev2/rendering.nim semiconginev2/rendering/platform/linux.nim semiconginev2/rendering/platform/windows.nim tests/test_gltf.nim
diffstat 6 files changed, 42 insertions(+), 23 deletions(-) [+]
line wrap: on
line diff
--- 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
--- 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
--- 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"
--- 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:
--- 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
--- 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)