Author Topic: Input method clarifications  (Read 4144 times)

0 Members and 1 Guest are viewing this topic.

Offline johannhowitzer

  • Forum Regular
  • Posts: 118
    • View Profile
Input method clarifications
« on: January 07, 2021, 10:44:48 pm »
I'm currently trying to settle various input challenges faced in my game development project.  Ideally, what I want is 1) perfectly consistent keyboard input, and 2) mostly consistent onboard plug and play gamepad input support.

For number 1, I've been using _KEYDOWN, which has a bug involving the SHIFT key sticking keys under certain circumstances.  I had been putting off switching to _KEYHIT, as it will require a pretty big code upheaval - I don't just have to change how the inputs during gameplay and in menus are read, I have to reorganize how the whole keybinding system is processed.

Then I stumbled on _DEVICES and its related functions, and this looks like a perfect solution to both number 1 and number 2, if I'm understanding it correctly, but the articles on the wiki raised a few questions I want to resolve first, to hopefully save myself a lot of work and headaches by way of others' experience.


1. Detecting devices using _DEVICES, _DEVICE$, and LEFT$ is pretty easy, and allows me to store the device index of keyboard and controller.  However, _BUTTON and similar functions only take one index - the index of the button itself.  How do I tell _BUTTON which device I'm trying to examine?

2. I'd like to avoid problems caused by controller disconnection mid-game.  If you've used these functions to handle gamepad support before, how did you ensure the user would be able to resume play once controller connection was restored?

3. Is there a way to allow the window to detect gamepad inputs even when the window loses focus?  I saw in the wiki that this is impossible for keyboard, so I thought it would be a good idea to check.


Thanks, and happy new year!
« Last Edit: January 07, 2021, 10:45:49 pm by johannhowitzer »

Offline johannhowitzer

  • Forum Regular
  • Posts: 118
    • View Profile
Re: Input method clarifications
« Reply #1 on: January 09, 2021, 09:54:19 am »
Completely failing to get off the ground with these systems, some help would be appreciated.  Here's my little test program:

Code: QB64: [Select]
  1. const true = -1
  2. const false = 0
  3.  
  4. dim shared d_keyboard as _byte ' Indexes of input devices in device list
  5. dim shared d_mouse    as _byte
  6. dim shared d_gamepad  as _byte
  7.  
  8. devices = _devices
  9. for i = devices to 1 step -1
  10.    d$ = _device$(i)
  11.    if left$(d$, 10) = "[KEYBOARD]"   then d_keyboard = i
  12.    if left$(d$, 7)  = "[MOUSE]"      then d_mouse    = i
  13.    if left$(d$, 12) = "[CONTROLLER]" then d_gamepad  = i
  14.  
  15.    print d$
  16.  
  17. print devices
  18. print d_keyboard, _lastbutton(d_keyboard)
  19. print d_mouse,    _lastbutton(d_mouse)
  20. 'print d_gamepad,  _lastbutton(d_gamepad)
  21.  
  22.    _limit 60
  23.    d = _deviceinput(d_keyboard)
  24.    l = _lastbutton(d_keyboard)
  25.    if d = true then
  26.       print "Activity"
  27.       if _button(182) = true then
  28.          print "Spacebar"
  29.          exit do
  30.       end if
  31.    end if
  32.  

_button(182) is never returning true, and the wiki has not provided a good reason why this should be happening.  _deviceinput is returning true for keypresses and releases, and _lastbutton is returning 512 for the keyboard.
« Last Edit: January 09, 2021, 09:56:12 am by johannhowitzer »

Offline johannhowitzer

  • Forum Regular
  • Posts: 118
    • View Profile
Re: Input method clarifications
« Reply #2 on: January 09, 2021, 11:48:22 am »
Hmm.  Either _BUTTON and _BUTTONCHANGE are broken, or the wiki is using them incorrectly, or the key codes on http://www.qb64.org/wiki/Controller_Devices are incorrect.  The example code block compiled on 1.4 returned a 0 from both functions on a keystroke.  I did have to make one simple change to the code to stop the example from generating unreadable screen spam, by putting a conditional in front of the print statement:

Code: QB64: [Select]
  1.     PRINT STR$(i) + ") " + _DEVICE$(i) + " Buttons:"; _LASTBUTTON(i); ",Axis:"; _LASTAXIS(i); ",Wheel:"; _LASTWHEEL(i)
  2.  
  3.     d& = _DEVICEINPUT
  4.     IF d& THEN '             the device number cannot be zero!
  5.         PRINT "Found"; d&;
  6.         FOR b = 1 TO _LASTBUTTON(d&)
  7.             IF b = 182 THEN PRINT _BUTTONCHANGE(b); _BUTTON(b);
  8.         NEXT
  9.         PRINT
  10.     END IF
  11. LOOP UNTIL INKEY$ = CHR$(27) 'escape key exit
  12.  
  13.  

On spacebar, I get the output "Found 1 0 0" - the first number is the device, and the second and third are the functions returning false.  So what's going on here?  During the screen spam, I did notice some -1s showing up in the sea of zeroes, so these functions definitely return true for something, leading me to believe the wiki is badly wrong on the chart of codes.  Going to do some testing now to see if I can brute force the real codes.
« Last Edit: January 09, 2021, 11:53:06 am by johannhowitzer »

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Input method clarifications
« Reply #3 on: January 09, 2021, 11:53:02 am »
ALL the key codes for _DEVICES are mapped incorrectly.  Don’t go by any of the values listed on the wiki.  You’ll need to hit each key individually and write down what the return values are for them, and record which ones have NO return value, and then see if you can hash together enough codes to make it usable for your needs.
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Input method clarifications
« Reply #4 on: January 09, 2021, 11:56:33 am »
Code: [Select]
'                            Extended Keyboard Press Scancodes
'
'  Esc  F1 F2 F3 F4 F5 F6 F7 F8 F9 F10  F11 F12   SysReq ScrL Pause                 
'   1   59 60 61 62 63 64 65 66 67 68   87  88     0     70    29
'  `~  1! 2@ 3# 4$ 5% 6^ 7& 8* 9( 0) -_ =+ BkSpc  Insert Home PgUp   NumL   /     *    -
'   41 2  3  4  5  6  7  8  9  10 11 12 13  14     82    71    73     69    53    55   74
'  Tab  Q  W  E  R  T  Y  U  I  O  P  [{ ]} \|    Delete End  PgDn   7/Home 8/▲  9/PU  +
'   15  16 17 18 19 20 21 22 23 24 25 26 27 43     83    79    81     71    72    73   78
'  CapL  A  S  D  F  G  H  J  K  L  ;: '"  Enter                     4/◄-   5    6/-►  E
'   58   30 31 32 33 34 35 36 37 38 39 40   28                        75    76    77   n
'  Shift  Z  X  C  V  B  N  M  ,< .> /?    Shift         ▲           1/End  2/▼  3/PD  t
'   42    44 45 46 47 48 49 50 51 52 53     54           72           79    80    81   e
'  Ctrl Win Alt    Spacebar    Alt Win Menu Ctrl     ◄-  ▼   -►      0/Insert    ./Del r
'   29  91  56        57       56  92   93  29       75  80  77       82          83   28
'
'   QB64 codes only! Release codes = Press code + 128. Pause/Break may lock code returns.

I’m thinking those are the codes which _DEVICES return, for the buttons which actually return a code.
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline johannhowitzer

  • Forum Regular
  • Posts: 118
    • View Profile
Re: Input method clarifications
« Reply #5 on: January 09, 2021, 11:58:16 am »
Nope, SMcNeill, 57 did not yield a true return value for spacebar, so at least that code is incorrect in your chart.


So essentially I'm going to have to brute force test every single number against every key on my keyboard and see if I get a positive?  I wonder if there's a way to expedite this process a little, but it's made difficult by the fact that these codes seem to be unique to these two functions.  I can see this taking days if I have to do it by hand one by one.

This does still seem to be my best solution for my game's input needs, over both _KEYDOWN and _KEYHIT, so I have a pretty big incentive for putting in the busywork.  We should get that wiki page fixed, I can either edit it myself or submit the codes when I'm done and someone else can edit it.

FellippeHeitor

  • Guest
Re: Input method clarifications
« Reply #6 on: January 09, 2021, 12:16:40 pm »

Offline johannhowitzer

  • Forum Regular
  • Posts: 118
    • View Profile
Re: Input method clarifications
« Reply #7 on: January 09, 2021, 12:18:14 pm »
Code: [Select]
'              Extended Keyboard Press Scancodes - _BUTTON and _BUTTONCHANGE
'
'  Esc  F1 F2 F3 F4 F5 F6 F7 F8 F9 F10  F11 F12   SysReq ScrL Pause                 
'   2   60 61 62 63 64 65 66 67 68 --   88  89     0     71    70
'  `~  1! 2@ 3# 4$ 5% 6^ 7& 8* 9( 0) -_ =+ BkSpc  Insert Home PgUp   NumL   /     *    -
'   42 3  4  5  6  7  8  9  10 11 12 13 14  15     339   328   330    326   310   56   75
'  Tab  Q  W  E  R  T  Y  U  I  O  P  [{ ]} \|    Delete End  PgDn   7/Home 8/▲  9/PU  +
'   16  17 18 19 20 21 22 23 24 25 26 27 28 44     340   336   338    72    73    74   79
'  CapL  A  S  D  F  G  H  J  K  L  ;: '"  Enter                     4/◄-   5    6/-►  E
'   59   31 32 33 34 35 36 37 38 39 40 41   29                        76    77    78   n
'  Shift  Z  X  C  V  B  N  M  ,< .> /?    Shift         ▲           1/End  2/▼  3/PD  t
'   43    45 46 47 48 49 50 51 52 53 54     55           329          80    81    82   e
'  Ctrl Win Alt    Spacebar    Alt Win Menu Ctrl     ◄-  ▼   -►      0/Insert    ./Del r
'   30  348 --        58       --  ??   350 286      332 337 334      83          84   285

Found a way to test it all very quickly, so here you go.  Most codes were 1 higher than your chart says, while some were actually three-digit.  Neither Alt key, nor the F10 key, caused the test code to do anything at all, so I guess _BUTTON and _BUTTONCHANGE don't have a way to detect those three keys.  My keyboard doesn't have a right side Windows key either, so you'll have to fill that in yourself.  If I had to guess, it's probably 349.
« Last Edit: January 09, 2021, 12:21:39 pm by johannhowitzer »

Offline johannhowitzer

  • Forum Regular
  • Posts: 118
    • View Profile
Re: Input method clarifications
« Reply #8 on: January 09, 2021, 12:32:30 pm »
So it seems the basic process of detecting input goes something like...

- At start of program, invoke _DEVICES and _DEVICE$ to process what devices are present.

- At time of input handling, use _DEVICEINPUT to pick an input device to check, then _BUTTON and similar functions to check inputs from that device.



Seems _DEVICEINPUT is the method to point _BUTTON and similar functions at a specific device.  It's a little bizarre to me that they're joined at the hip like that, more intuitive in my mind to pass _BUTTON a device index parameter, but it works.  This linked behavior is noted on the wiki for _DEVICES and _DEVICE$, but not _DEVICEINPUT and _BUTTON/_BUTTONCHANGE.  I'll add a note to that part of the wiki too when I'm able.
« Last Edit: January 09, 2021, 12:36:07 pm by johannhowitzer »

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Input method clarifications
« Reply #9 on: January 09, 2021, 12:49:36 pm »
Quick question: Are you on Linux, or Windows?  You might want to check to make certain the codes are the same cross-platforms.
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline johannhowitzer

  • Forum Regular
  • Posts: 118
    • View Profile
Re: Input method clarifications
« Reply #10 on: January 09, 2021, 01:08:58 pm »
Windows 10, on a laptop if that matters.  I don't have an easy way to test other platforms currently.

While it might matter for the wiki chart, it won't matter very much for my game.  The way I'm coding the keybinding/controller settings, the user will just be able to set things however they want, regardless of how their platform organizes the codes or which type of USB gamepad they're using.  It might just mean the labels in the input settings menu will look wrong.
« Last Edit: January 09, 2021, 01:27:27 pm by johannhowitzer »

Offline TempodiBasic

  • Forum Resident
  • Posts: 1792
    • View Profile
Re: Input method clarifications
« Reply #11 on: January 09, 2021, 03:07:50 pm »
Hi
your code to test deviceinput seems to work well!
Here my little mode to avoid the scrolling effect of output on the screen..
as you can see you can detect many buttons on the same time from a single device, but you cannot detect in the same time different input from different devices... because the code does it sequentially...
Code: QB64: [Select]
  1. nDev = _DEVICES
  2. FOR i = 1 TO nDev
  3.     PRINT STR$(i) + ") " + _DEVICE$(i) + " Buttons:"; _LASTBUTTON(i); ",Axis:"; _LASTAXIS(i); ",Wheel:"; _LASTWHEEL(i)
  4. done = 0
  5.     d& = _DEVICEINPUT
  6.  
  7.  
  8.     IF d& THEN '             the device number cannot be zero!
  9.         CLS
  10.         IF d& = 1 THEN LOCATE 6, 1: PRINT "Input from device "; d&
  11.         IF d& = 2 THEN LOCATE 7, 1: PRINT "Input from device"; d&
  12.         IF d& = 3 THEN LOCATE 8, 1: PRINT "Input from device"; d&
  13.         IF d& = 1 THEN LOCATE 6, 23
  14.         IF d& = 2 THEN LOCATE 7, 23
  15.         IF d& = 3 THEN LOCATE 8, 23
  16.         FOR b = 1 TO _LASTBUTTON(d&)
  17.             '    IF b = 182 THEN PRINT _BUTTONCHANGE(b); _BUTTON(b);
  18.             IF _BUTTONCHANGE(b) OR _BUTTON(b) THEN
  19.                 PRINT "button "; b; " ";
  20.             END IF
  21.         NEXT
  22.         PRINT
  23.         IF d& = 1 AND _BUTTON(2) THEN done = -1
  24.     END IF
  25.  
  26.     _LIMIT 10
  27. LOOP UNTIL done ' INKEY$ = CHR$(27) 'escape key exit
  28.  
  29.  
  30.  

Observations:
1. spacebar key return me 58 and ESC 2...
2. pressing the right ALT key on my keyboard of notebook that is labelled as AltGr it activates a permanent key 30 active
3. pressing the left Alt I got no code, while Menu Key (on the right side) is 350 and Windows key on the left side of keyboard is 348
4. Left mousepad button is 1 right mousepad button is 3
5 generic usb joystick works well with multiple keypressing

It may  be that the _DEVICES is dependent from hardware structure of keyboard and so it must be configured for each kind of keyboard.
Programming isn't difficult, only it's  consuming time and coffee

Offline johannhowitzer

  • Forum Regular
  • Posts: 118
    • View Profile
Re: Input method clarifications
« Reply #12 on: January 09, 2021, 08:42:28 pm »
Yep, that lines up with my chart.

All I ended up doing to test each key quickly was change the FOR loop:

Code: [Select]
FOR i = 1 TO _DEVICES
  PRINT STR$(i) + ") " + _DEVICE$(i) + " Buttons:"; _LASTBUTTON(i); ",Axis:"; _LASTAXIS(i); ",Wheel:"; _LASTWHEEL(i)
NEXT

DO
  d& = _DEVICEINPUT
  IF d& = 1 THEN '             the device number cannot be zero!
    FOR b = 1 TO _LASTBUTTON(d&)
      IF _BUTTON(b) = -1 THEN PRINT b
    NEXT
  END IF
LOOP UNTIL INKEY$ = CHR$(27) 'escape key exit

END 

This way, each time you type a key, it spits out the code.

Offline johannhowitzer

  • Forum Regular
  • Posts: 118
    • View Profile
Re: Input method clarifications
« Reply #13 on: January 10, 2021, 01:56:29 am »
Also, some very good news, gamepad does indeed register inputs with _BUTTON even when the program doesn't have focus.