Keyhit library update
#10
Okay, let's see how simple I can make this.  Here's what I put in the header:


Code: (Select All)
' References for press function and hold array
const up_key        =  1
const down_key      =  2
const left_key      =  3
const right_key     =  4
const weapon_key    =  5
const shield_key    =  6
const engine_key    =  7
const energy_key    =  8
const wpn_sel_right =  9
const wpn_sel_left  = 10
const ok_key        = 11
const cancel_key    = 12
const pause_key     = 13
const enter_key     = 14
const esc_key       = 15

' Input reference and binding data
const keybind_count = 15 ' Number of gameplay functions, including enter and esc

dim shared dev_keyboard as byte ' Store device index, to be re-checked whenever inputs are involved
dim shared dev_gamepad  as byte
dim shared dev_mouse    as byte
const keyboard = 1
const gamepad  = 2
const mouse    = 3


kc = keybind_count
dim shared key_name$(512, 2)                  ' Names of keyboard keys and gamepad buttons
dim shared keybind(kc, 2)          as integer ' Contains key code assigned by player
dim shared keybind_default(kc, 2)  as integer ' Defaults in case player wants to reset

dim shared axis_threshold as single ' Amount a stick needs to be tilted before input is registered
axis_threshold = 0.7
set_key_data


' Input tracking flags
dim shared press(kc)      as byte ' What was pressed this frame
dim shared hold(kc)        as byte ' What was pressed last frame

The constants at the top are user operations in your program.  For my game project, that's movement, face buttons, pause button, OK and cancel for menu navigation, etc.

The two arrays at the bottom are where inputs are stored and updated.  press() is what keys are pressed on this loop, hold() is what was pressed last loop.  So every loop, when update_inputs is called, press() gets copied over to hold().

Routines in my input handling library:

Code: (Select All)
function new_press(b)
new_press = false
if press(b) = true and hold(b) = false then new_press = true
end function


sub update_inputs

call detect_devices

for b = 1 to keybind_count
  hold(b) = press(b)
  press(b) = false

  d = keyboard
  if dev_keyboard <> false then
      z = deviceinput(dev_keyboard)
      if button(keybind(b, d)) = true then press(b) = true
  end if

  d = gamepad
  if dev_gamepad <> false and keybind(b, d) <> false then
      z = deviceinput(dev_gamepad)

      if keybind(b, d) < 100 then ' Button
        if button(keybind(b, d)) = true then press(b) = true

      ' Stick handling:
      ' keybind() set to 101, 102 etc. is an assignment of stick 1, 2 etc. in the negative direction
      ' keybind() set to 201, 202 etc. is an assignment of stick 1, 2 etc. in the positive direction
      elseif keybind(b, d) > 200 then ' Stick positive
        if axis(keybind(b, d) - 200) >  option_sensitivity * 0.1 then press(b) = true
      else                            ' Stick negative
        if axis(keybind(b, d) - 100) < -option_sensitivity * 0.1 then press(b) = true
      end if
  end if
next b

if dev_mouse = false then exit sub

dim mb(3)
for b = 1 to 3
  mb(b) = mouse_press(b)
next b

mouse_change = false
do while mouseinput <> false and mouse_change = false
  mouse_pos_x = mousex
  mouse_pos_y = mousey
  for b = 1 to 3
      mb(b) = mousebutton(b)
      if mb(b) <> mouse_press(b) then mouse_change = true
  next b
loop

for b = 1 to 3
  mouse_hold(b) = mouse_press(b)
  mouse_press(b) = mb(b)

  if mouse_press(b) = true and mouse_hold(b) = false then
      mouse_press_x(b) = mouse_pos_x ' Store position mouse button was pressed
      mouse_press_y(b) = mouse_pos_y
  elseif mouse_press(b) = false and mouse_hold(b) = true then
      mouse_release_x(b) = mouse_pos_x ' Store position mouse button was released
      mouse_release_y(b) = mouse_pos_y
  end if
next b

end sub


sub detect_devices

dev_keyboard = false
dev_gamepad  = false
dev_mouse    = false

d = devices
for n = d to 1 step -1
  if left$(device$(n), 10) = "[KEYBOARD]"  then dev_keyboard = n
  if left$(device$(n), 12) = "[CONTROLLER]" then dev_gamepad  = n
  if left$(device$(n),  7) = "[MOUSE]"      then dev_mouse    = n
next n

end sub


sub set_press(p)
for b = 1 to keybind_count
  press(b) = p
next b
end sub


sub set_hold(p)
for b = 1 to keybind_count
  hold(b) = p
next b
end sub


sub press_any_key
do
  limit 60
  display
  for b = 1 to keybind_count
      if new_press(b) = true then exit sub
  next b
  call update_inputs
loop
end sub


sub set_default_keybinds

call detect_devices

for b = 1 to keybind_count
  keybind(b, keyboard) = keybind_default(b, keyboard)
  keybind(b, gamepad)  = keybind_default(b, gamepad)
next b

if dev_gamepad = false then exit sub

' Eliminate any defaults that go beyond a gamepad's features
d = gamepad

for b = 1 to keybind_count
  if keybind(b, d) < 100 and keybind(b, d) > lastbutton(dev_gamepad) then keybind(b, d) = false
next b

if lastaxis(dev_gamepad) < 2 then
  keybind(up_key,    d) = false
  keybind(down_key,  d) = false
  keybind(left_key,  d) = false
  keybind(right_key, d) = false
end if

end sub


sub set_key_data

key_name$(false, keyboard) = "NOT SET"
key_name$(false, gamepad)  = "NOT SET"

d = keyboard
for n = 1 to 512
  key_name$(n, d) = "UNKNOWN"
next n
key_name$(2,  d) = "ESC"
key_name$(60,  d) = "F1"
key_name$(61,  d) = "F2"
key_name$(62,  d) = "F3"
key_name$(63,  d) = "F4"
key_name$(64,  d) = "F5"
key_name$(65,  d) = "F6"
key_name$(66,  d) = "F7"
key_name$(67,  d) = "F8"
key_name$(68,  d) = "F9"
key_name$(88,  d) = "F11"
key_name$(89,  d) = "F12"
key_name$(42,  d) = "~"
key_name$(3,  d) = "1"
key_name$(4,  d) = "2"
key_name$(5,  d) = "3"
key_name$(6,  d) = "4"
key_name$(7,  d) = "5"
key_name$(8,  d) = "6"
key_name$(9,  d) = "7"
key_name$(10,  d) = "8"
key_name$(11,  d) = "9"
key_name$(12,  d) = "0"
key_name$(13,  d) = "-"
key_name$(14,  d) = "="
key_name$(15,  d) = "BKSP"
key_name$(16,  d) = "TAB"
key_name$(17,  d) = "Q"
key_name$(18,  d) = "W"
key_name$(19,  d) = "E"
key_name$(20,  d) = "R"
key_name$(21,  d) = "T"
key_name$(22,  d) = "Y"
key_name$(23,  d) = "U"
key_name$(24,  d) = "I"
key_name$(25,  d) = "O"
key_name$(26,  d) = "P"
key_name$(27,  d) = "["
key_name$(28,  d) = "]"
key_name$(44,  d) = "\"
key_name$(31,  d) = "A"
key_name$(32,  d) = "S"
key_name$(33,  d) = "D"
key_name$(34,  d) = "F"
key_name$(35,  d) = "G"
key_name$(36,  d) = "H"
key_name$(37,  d) = "J"
key_name$(38,  d) = "K"
key_name$(39,  d) = "L"
key_name$(40,  d) = ";"
key_name$(41,  d) = "'"
key_name$(29,  d) = "ENTER"
key_name$(43,  d) = "L SHIFT"
key_name$(45,  d) = "Z"
key_name$(46,  d) = "X"
key_name$(47,  d) = "C"
key_name$(48,  d) = "V"
key_name$(49,  d) = "B"
key_name$(50,  d) = "N"
key_name$(51,  d) = "M"
key_name$(52,  d) = ","
key_name$(53,  d) = "."
key_name$(54,  d) = "/"
key_name$(55,  d) = "R SHIFT"
key_name$(30,  d) = "L CTRL"
key_name$(58,  d) = "SPACE"
key_name$(286, d) = "R CTRL"
key_name$(339, d) = "INS"
key_name$(340, d) = "DEL"
key_name$(328, d) = "HOME"
key_name$(336, d) = "END"
key_name$(330, d) = "PG UP"
key_name$(338, d) = "PG DN"
key_name$(329, d) = "UP"
key_name$(337, d) = "DOWN"
key_name$(332, d) = "LEFT"
key_name$(334, d) = "RIGHT"
key_name$(310, d) = "NUM /"
key_name$(56,  d) = "NUM *"
key_name$(75,  d) = "NUM -"
key_name$(79,  d) = "NUM +"
key_name$(285, d) = "NUM ENTER"
key_name$(72,  d) = "NUM 7"
key_name$(73,  d) = "NUM 8"
key_name$(74,  d) = "NUM 9"
key_name$(76,  d) = "NUM 4"
key_name$(77,  d) = "NUM 5"
key_name$(78,  d) = "NUM 6"
key_name$(80,  d) = "NUM 1"
key_name$(81,  d) = "NUM 2"
key_name$(82,  d) = "NUM 3"
key_name$(83,  d) = "NUM 0"
key_name$(84,  d) = "NUM ."

' Troublesome keyboard codes:
'  71 - Scroll Lock
'  70 - Pause
'  59 - Caps Lock
'  348 - Windows Left
'  349 - Windows Right?
'  350 - Menu
'  326 - Num Lock

d = gamepad
for n = 1 to 20
  key_name$(n, d) = "BUTTON" + str$(n)
next n
for n = 1 to 8
  key_name$(n + 100, d) = "AXIS" + str$(n) + "-" ' *** Check that first axis is horizontal
  key_name$(n + 200, d) = "AXIS" + str$(n) + "+"
next n

end sub

new_press is the function you would check if you want to see if something is being freshly pressed (not held down) on this loop.  For example, if new_press(ok_key) = true then [accept menu option].  Any loop where you're taking user input needs to have an update_inputs call.  If you want to clear user input completely, you can call set_hold true.  The bulk of the data is carried in set_key_data, as well as a block of code such as this:

Code: (Select All)
d = keyboard
keybind_default(up_key,        d) = 329
keybind_default(down_key,      d) = 337
keybind_default(left_key,      d) = 332
keybind_default(right_key,    d) = 334
keybind_default(weapon_key,    d) = 46 ' x
keybind_default(shield_key,    d) = 47 ' c
keybind_default(engine_key,    d) = 45 ' z
keybind_default(energy_key,    d) = 30 ' LCTRL
keybind_default(wpn_sel_right, d) = 34 ' f
keybind_default(wpn_sel_left,  d) = 33 ' d
keybind_default(ok_key,        d) = 46 ' x
keybind_default(cancel_key,    d) = 47 ' c
keybind_default(pause_key,    d) = 31 ' a
keybind_default(enter_key,    d) = 29
keybind_default(esc_key,      d) = 2

Once you have this data set, you can call set_default_keybinds and all the assignments above are made.  You would have to code your own front-end keybinding menu, I can share what I've done for my game with that, but it may be very project-specific.


So to sum up, you just use these routines, set the defaults as you see fit, call update_inputs in your loops, and check new_press() using the input constants at the top, to detect if that key was freshly pressed.  You could also check press() and hold() together to see if it's being held down or released during a given loop.

Here's a sample loop, a stripped-down version of my game's title screen routine, I've omitted most of the stuff that you don't need to wade through, like text draws:

Code: (Select All)
  do
      limit 60

      display_screen
      update_inputs

      if new_press(up_key)  = true and new_press(down_key)  = false then cursor = wrap(cursor - 1, 0, 2)
      if new_press(down_key) = true and new_press(up_key)    = false then cursor = wrap(cursor + 1, 0, 2)

      if new_press(enter_key) = false and new_press(ok_key) = false then continue
      if cursor = 1 then option_menu: c = 0: continue ' Options
      if cursor = 2 then exit sub ' Quit

      ' Start game, etc etc
  loop

Let me know if you need me to clarify anything, hopefully this was a little clearer than mud!
Reply


Messages In This Thread
Keyhit library update - by SMcNeill - 11-23-2022, 01:16 PM
RE: Keyhit library update - by TempodiBasic - 02-08-2023, 10:07 AM
RE: Keyhit library update - by PhilOfPerth - 02-08-2023, 11:30 PM
RE: Keyhit library update - by SMcNeill - 02-08-2023, 11:51 PM
RE: Keyhit library update - by PhilOfPerth - 02-09-2023, 12:35 AM
RE: Keyhit library update - by johannhowitzer - 02-10-2023, 04:17 AM
RE: Keyhit library update - by PhilOfPerth - 02-10-2023, 05:56 AM
RE: Keyhit library update - by johannhowitzer - 02-10-2023, 06:28 AM
RE: Keyhit library update - by PhilOfPerth - 02-10-2023, 06:51 AM
RE: Keyhit library update - by johannhowitzer - 02-10-2023, 01:39 PM
RE: Keyhit library update - by SMcNeill - 02-10-2023, 02:16 PM
RE: Keyhit library update - by SpriggsySpriggs - 02-10-2023, 03:21 PM
RE: Keyhit library update - by johannhowitzer - 02-10-2023, 08:31 PM



Users browsing this thread: 1 Guest(s)