view semiconginev2/input.nim @ 1264:cb4d626ca671

Added tag main for changeset e0f0a0be7880
author sam <sam@basx.dev>
date Sun, 28 Jul 2024 21:58:53 +0700
parents bfb75c934f4e
children
line wrap: on
line source

type
  Input = object
    keyIsDown: set[Key]
    keyWasPressed: set[Key]
    keyWasReleased: set[Key]
    mouseIsDown: set[MouseButton]
    mouseWasPressed: set[MouseButton]
    mouseWasReleased: set[MouseButton]
    mousePosition: Vec2f
    mouseMove: Vec2f
    mouseWheel: float32
    windowWasResized: bool = true
    windowIsMinimized: bool = false
    lockMouse: bool = false
    hasFocus: bool = false

# warning, shit is not thread safe
var input = Input()

proc UpdateInputs*(): bool =
  # reset input states
  input.keyWasPressed = {}
  input.keyWasReleased = {}
  input.mouseWasPressed = {}
  input.mouseWasReleased = {}
  input.mouseWheel = 0
  input.mouseMove = NewVec2f()
  input.windowWasResized = false

  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
  for event in vulkan.window.PendingEvents():
    case event.eventType:
      of Quit:
        killed = true
      of ResizedWindow:
        input.windowWasResized = true
      of KeyPressed:
        input.keyWasPressed.incl event.key
        input.keyIsDown.incl event.key
      of KeyReleased:
        input.keyWasReleased.incl event.key
        input.keyIsDown.excl event.key
      of MousePressed:
        input.mouseWasPressed.incl event.button
        input.mouseIsDown.incl event.button
      of MouseReleased:
        input.mouseWasReleased.incl event.button
        input.mouseIsDown.excl event.button
      of MouseMoved:
        let newPos = NewVec2(float32(event.x), float32(event.y))
        input.mouseMove = newPos - input.mousePosition
        input.mousePosition = newPos
      of MouseWheel:
        input.mouseWheel = event.amount
      of MinimizedWindow:
        input.windowIsMinimized = true
      of RestoredWindow:
        input.windowIsMinimized = false
      of GotFocus:
        input.hasFocus = true
      of LostFocus:
        input.hasFocus = false

  return not killed

proc KeyIsDown*(key: Key): bool = key in input.keyIsDown
proc KeyWasPressed*(key: Key): bool = key in input.keyWasPressed
proc KeyWasPressed*(): bool = input.keyWasPressed.len > 0
proc KeyWasReleased*(key: Key): bool = key in input.keyWasReleased
proc MouseIsDown*(button: MouseButton): bool = button in input.mouseIsDown
proc MouseWasPressed*(): bool = input.mouseWasPressed.len > 0
proc MouseWasPressed*(button: MouseButton): bool = button in input.mouseWasPressed
proc MousePressedButtons*(): set[MouseButton] = input.mouseWasPressed
proc MouseWasReleased*(): bool = input.mouseWasReleased.len > 0
proc MouseWasReleased*(button: MouseButton): bool = button in input.mouseWasReleased
proc MouseReleasedButtons*(): set[MouseButton] = input.mouseWasReleased
proc MousePosition*(): Vec2f = input.mousePosition
proc MousePositionNormalized*(size: (int, int)): Vec2f =
  result.x = (input.mousePosition.x / float32(size[0])) * 2.0 - 1.0
  result.y = (input.mousePosition.y / float32(size[1])) * 2.0 - 1.0
proc MouseMove*(): Vec2f = input.mouseMove
proc MouseWheel*(): float32 = input.mouseWheel
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

type
  ActionMap = object
    keyActions: Table[string, set[Key]]
    mouseActions: Table[string, set[MouseButton]]

# warning, shit is not thread safe
var actionMap: ActionMap

proc MapAction*[T: enum](action: T, key: Key) =
  if not actionMap.keyActions.contains($action):
    actionMap.keyActions[$action] = {}
  actionMap.keyActions[$action].incl key

proc MapAction*[T: enum](action: T, button: MouseButton) =
  if not actionMap.mouseActions.contains($action):
    actionMap.mouseActions[$action] = {}
  actionMap.mouseActions[$action].incl button

proc MapAction*[T: enum](action: T, keys: openArray[Key|MouseButton]) =
  for key in keys:
    MapAction(action, key)

proc UnmapAction*[T: enum](action: T, key: Key) =
  if actionMap.keyActions.contains($action):
    actionMap.keyActions[$action].excl(key)

proc UnmapAction*[T: enum](action: T, button: MouseButton) =
  if actionMap.mouseActions.contains($action):
    actionMap.mouseActions[$action].excl(button)

proc UnmapAction*[T: enum](action: T) =
  if actionMap.keyActions.contains($action):
    actionMap.keyActions[$action] = {}
  if actionMap.mouseActions.contains($action):
    actionMap.mouseActions[$action] = {}

proc SaveCurrentActionMapping*() =
  for name, keys in actionMap.keyActions.pairs:
    SystemStorage.Store(name, keys, table = "input_mapping_key")
  for name, buttons in actionMap.mouseActions.pairs:
    SystemStorage.Store(name, buttons, table = "input_mapping_mouse")

proc LoadActionMapping*[T]() =
  reset(actionMap)
  for name in SystemStorage.List(table = "input_mapping_key"):
    let action = parseEnum[T](name)
    let keys = SystemStorage.Load(name, set[Key](), table = "input_mapping_key")
    for key in keys:
      MapAction(action, key)

proc ActionDown*[T](action: T): bool =
  if actionMap.keyActions.contains($action):
    for key in actionMap.keyActions[$action]:
      if key in input.keyIsDown:
        return true
    return false
  if actionMap.mouseActions.contains($action):
    for button in actionMap.mouseActions[$action]:
      if button in input.mouseIsDown:
        return true
    return false

proc ActionPressed*[T](action: T): bool =
  if actionMap.keyActions.contains($action):
    for key in actionMap.keyActions[$action]:
      if key in input.keyWasPressed:
        return true
  elif actionMap.mouseActions.contains($action):
    for button in actionMap.mouseActions[$action]:
      if button in input.mouseWasPressed:
        return true

proc ActionReleased*[T](action: T): bool =
  if actionMap.keyActions.contains($action):
    for key in actionMap.keyActions[$action]:
      if key in input.keyWasReleased:
        return true
  elif actionMap.mouseActions.contains($action):
    for button in actionMap.mouseActions[$action]:
      if button in input.mouseWasReleased:
        return true

proc ActionValue*[T](action: T): float32 =
  if actionMap.keyActions.contains($action):
    for key in actionMap.keyActions[$action]:
      if key in input.keyIsDown:
        return 1
  elif actionMap.mouseActions.contains($action):
    for button in actionMap.mouseActions[$action]:
      if button in input.mouseIsDown:
        return 1