input_helpers.nim 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. import
  2. sfml, tables, hashes
  3. type
  4. TKeyEventKind* = enum down, up
  5. TInputFinishedProc* = proc()
  6. TKeyCallback = proc()
  7. PKeyClient* = ref object
  8. onKeyDown: Table[int32, TKeyCallback]
  9. onKeyUp: Table[int32, TKeyCallback]
  10. name: string
  11. PTextInput* = ref object
  12. text*: string
  13. cursor: int
  14. onEnter: TInputFinishedProc
  15. var
  16. keyState: array[-MouseButtonCount.int32 .. KeyCount.int32, bool]
  17. mousePos: TVector2f
  18. activeClient: PKeyClient = nil
  19. activeInput: PTextInput = nil
  20. proc setActive*(client: PKeyClient) =
  21. activeClient = client
  22. echo("** set active client ", client.name)
  23. proc newKeyClient*(name: string = "unnamed", setactive = false): PKeyClient =
  24. new(result)
  25. result.onKeyDown = initTable[int32, TKeyCallback](16)
  26. result.onKeyUp = initTable[int32, TKeyCallback](16)
  27. result.name = name
  28. if setActive:
  29. setActive(result)
  30. proc keyPressed*(key: TKeyCode): bool {.inline.} =
  31. return keyState[key.int32]
  32. proc buttonPressed*(btn: TMouseButton): bool {.inline.} =
  33. return keyState[-btn.int32]
  34. proc clearKey*(key: TKeyCode) {.inline.} =
  35. keyState[key.int32] = false
  36. proc clearButton*(btn: TMouseButton) {.inline.} =
  37. keyState[-btn.int32] = false
  38. proc addKeyEvent*(key: TKeyCode, ev: TKeyEventKind) {.inline.} =
  39. if activeClient.isNil: return
  40. let k = key.int32
  41. case ev
  42. of down:
  43. keyState[k] = true
  44. if activeClient.onKeyDown.hasKey(k):
  45. activeClient.onKeyDown[k]()
  46. else:
  47. keyState[k] = false
  48. if activeClient.onKeyUp.hasKey(k):
  49. activeClient.onKeyUp[k]()
  50. proc addButtonEvent*(btn: TMouseButton, ev: TKeyEventKind) {.inline.} =
  51. if activeClient.isNil: return
  52. let b = -btn.int32
  53. case ev
  54. of down:
  55. keyState[b] = true
  56. if activeClient.onKeyDown.hasKey(b):
  57. activeClient.onKeyDown[b]()
  58. else:
  59. keyState[b] = false
  60. if activeClient.onKeyUp.hasKey(b):
  61. activeClient.onKeyUp[b]()
  62. proc registerHandler*(client: PKeyClient; key: TKeyCode;
  63. ev: TKeyEventKind; fn: TKeyCallback) =
  64. case ev
  65. of down: client.onKeyDown[key.int32] = fn
  66. of up: client.onKeyUp[key.int32] = fn
  67. proc registerHandler*(client: PKeyClient; btn: TMouseButton;
  68. ev: TKeyEventKind; fn: TKeyCallback) =
  69. case ev
  70. of down: client.onKeyDown[-btn.int32] = fn
  71. of up: client.onKeyUp[-btn.int32] = fn
  72. proc newTextInput*(text = "", pos = 0, onEnter: TInputFinishedProc = nil): PTextInput =
  73. new(result)
  74. result.text = text
  75. result.cursor = pos
  76. result.onEnter = onEnter
  77. proc setActive*(i: PTextInput) =
  78. activeInput = i
  79. proc stopCapturingText*() =
  80. activeInput = nil
  81. proc clear*(i: PTextInput) =
  82. i.text.setLen 0
  83. i.cursor = 0
  84. proc recordText*(i: PTextInput; c: cint) =
  85. if c > 127 or i.isNil: return
  86. if c in 32..126: ##printable
  87. if i.cursor == i.text.len: i.text.add(c.int.chr)
  88. else:
  89. let rem = i.text.substr(i.cursor)
  90. i.text.setLen(i.cursor)
  91. i.text.add(chr(c.int))
  92. i.text.add(rem)
  93. inc(i.cursor)
  94. elif c == 8: ## \b backspace
  95. if i.text.len > 0 and i.cursor > 0:
  96. dec(i.cursor)
  97. let rem = i.text.substr(i.cursor + 1)
  98. i.text.setLen(i.cursor)
  99. i.text.add(rem)
  100. elif c == 10 or c == 13:## \n, \r enter
  101. if not i.onEnter.isNil: i.onEnter()
  102. proc recordText*(i: PTextInput; e: TTextEvent) {.inline.} =
  103. recordText(i, e.unicode)
  104. proc setMousePos*(x, y: cint) {.inline.} =
  105. mousePos.x = x.float
  106. mousePos.y = y.float
  107. proc getMousePos*(): TVector2f {.inline.} = result = mousePos
  108. var event: TEvent
  109. # Handle and filter input-related events
  110. iterator filterEvents*(window: PRenderWindow): PEvent =
  111. while window.pollEvent(addr event):
  112. case event.kind
  113. of EvtKeyPressed: addKeyEvent(event.key.code, down)
  114. of EvtKeyReleased: addKeyEvent(event.key.code, up)
  115. of EvtMouseButtonPressed: addButtonEvent(event.mouseButton.button, down)
  116. of EvtMouseButtonReleased: addButtonEvent(event.mouseButton.button, up)
  117. of EvtTextEntered: recordText(activeInput, event.text)
  118. of EvtMouseMoved: setMousePos(event.mouseMove.x, event.mouseMove.y)
  119. else: yield(addr event)
  120. # Handle and return input-related events
  121. iterator pollEvents*(window: PRenderWindow): PEvent =
  122. while window.pollEvent(addr event):
  123. case event.kind
  124. of EvtKeyPressed: addKeyEvent(event.key.code, down)
  125. of EvtKeyReleased: addKeyEvent(event.key.code, up)
  126. of EvtMouseButtonPressed: addButtonEvent(event.mouseButton.button, down)
  127. of EvtMouseButtonReleased: addButtonEvent(event.mouseButton.button, up)
  128. of EvtTextEntered: recordText(activeInput, event.text)
  129. of EvtMouseMoved: setMousePos(event.mouseMove.x, event.mouseMove.y)
  130. else: discard
  131. yield(addr event)