Author Topic: Keyboard jamming issue only happening in QB64  (Read 5030 times)

0 Members and 1 Guest are viewing this topic.

Offline johannhowitzer

  • Forum Regular
  • Posts: 118
    • View Profile
Keyboard jamming issue only happening in QB64
« on: July 11, 2020, 12:51:26 am »
Trying to read inputs, and when I press and release left shift, Z, and X together, sometimes Z or X or both will stick, but only in QB64 using the _keydown function.  The press() function below will return true after Z or X is released, until it is pressed and released again.  Notepad does not give the same result, I don't get a long row of Xs or Zs sometimes when I do this, so it doesn't seem like an issue with my laptop.  Is there a workaround for this?

Code: QB64: [Select]
  1.    _limit 60
  2.    cls
  3.    for n = 1 to 12
  4.       color 8
  5.       if press(n) = true then color 7
  6.       print key_name$(n)
  7.    next n
  8.  
  9.  
  10. function press(b)
  11. press = _keydown(keybind(b))
  12.  

Offline Ashish

  • Forum Resident
  • Posts: 630
  • Never Give Up!
    • View Profile
Re: Keyboard jamming issue only happening in QB64
« Reply #1 on: July 11, 2020, 01:21:29 am »
Hi! What is keybind? Is it an array? or a function? its undefined in your code.

Also, I think you are looking for _KEYHIT...

Code: QB64: [Select]
  1.     _LIMIT 60
  2.     k& = _KEYHIT
  3.     IF k& >= 65 AND k& < 150 THEN
  4.         PRINT CHR$(k&);
  5.     END IF
  6.     _DISPLAY
  7.  

https://qb64.org/wiki/KEYHIT
« Last Edit: July 11, 2020, 01:23:31 am by Ashish »
if (Me.success) {Me.improve()} else {Me.tryAgain()}


My Projects - https://github.com/AshishKingdom?tab=repositories
OpenGL tutorials - https://ashishkingdom.github.io/OpenGL-Tutorials

Offline johannhowitzer

  • Forum Regular
  • Posts: 118
    • View Profile
Re: Keyboard jamming issue only happening in QB64
« Reply #2 on: July 11, 2020, 02:17:34 am »
I will try _keyhit and see if it behaves differently from _keydown, but I'm under the impression that _keyhit can't handle modifier keys like shift and ctrl?  Also, I know it's just an example, but that code is almost functionally equivalent to a do-inkey$-loop, which only picks up one keystroke at a time, and won't work for my purposes.  The game I'm coding needs to track a dozen inputs that can happen simultaneously, and even some key combinations.


Here's what keybind looks like:

Code: QB64: [Select]
  1. function keybind(i)
  2. keybind = key_ref(keybind_ref(i))
  3.  

It's just a quick way to type a longer thing.  key_ref contains all the key codes for all bindable keys, and keybind_ref is an array that stores the player's chosen keybinds.

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Keyboard jamming issue only happening in QB64
« Reply #3 on: July 11, 2020, 02:58:53 am »
The game I'm coding needs to track a dozen inputs that can happen simultaneously, and even some key combinations.

If you’re using an USB keyboard, that’ll never happen.  Hardware limitations will cap you out before you get 12+ inputs.  USB specifications generally allow a maximum of 6-key rollover, plus modifier keys.  The only practical way to guarantee n-key input limits is to buy/require a quality PS/2 n-key keyboard for your end users.

You may want to rethink a simpler input scheme.
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline johannhowitzer

  • Forum Regular
  • Posts: 118
    • View Profile
Re: Keyboard jamming issue only happening in QB64
« Reply #4 on: July 11, 2020, 03:12:06 am »
Ah, I made it sound more demanding than it is.  There are 12 inputs, but you're not going to be pressing all 12 at once.  Two are enter / esc, which are only used for menus and pausing, and four are directional, of which generally no more than two will be happening at once.

That leaves six, if it was a gamepad, it would be four face buttons and two shoulder buttons - the shoulders are for weapon swapping (on A and S by default), and the four face buttons are attack (default Z), dash (left shift), block (X), and a special combo button (left ctrl).  In the most extreme example of pressing a bunch of stuff at once, you might be holding weapon and combo for a charge attack, while also dashing, holding a diagonal direction, and then make a weapon switch or tap block.  That's a reasonable upper limit of six.

The issue I'm having is that with just three buttons pressed and released at the same time (in this case, it's attack, dash, and block), sometimes one or two of the buttons gets stuck returning true from _keydown - which would stick the weapon in autofire state, for example, and waste the player's ammo.

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Keyboard jamming issue only happening in QB64
« Reply #5 on: July 11, 2020, 03:44:30 am »
See how something like this performs for you, and how many keys your keyboard will display with it:

Code: QB64: [Select]
  1. DIM Keys(10)
  2.  
  3.  
  4.     CLS
  5.     FOR i = 0 TO 10
  6.         IF Keys(i) THEN 'make certain the key is still down
  7.             IF _KEYDOWN(Keys(i)) THEN
  8.                 PRINT Keys(i)
  9.             ELSE
  10.                 PRINT 0
  11.                 Keys(i) = 0
  12.                 FOR j = i TO 9
  13.                     Keys(j) = Keys(j + 1)
  14.                 NEXT
  15.                 Keys(10) = 0
  16.                 keysdown = keysdown - 1
  17.                 i = i - 1
  18.             END IF
  19.         END IF
  20.     NEXT
  21.     k = _KEYHIT
  22.     IF k > 0 THEN
  23.         '        PRINT k
  24.         FOR i = 0 TO keysdown
  25.             IF Keys(i) = k THEN EXIT FOR 'key is already down and reported as such
  26.             IF Keys(i) = 0 THEN keysdown = keysdown + 1: Keys(i) = k: EXIT FOR
  27.         NEXT
  28.     ELSEIF k < 0 THEN
  29.         FOR i = 0 TO keysdown
  30.             IF Keys(i) = -k THEN 'clear the up key
  31.                 FOR j = i TO 9
  32.                     Keys(j) = Keys(j + 1)
  33.                 NEXT
  34.                 Keys(10) = 0
  35.                 keysdown = keysdown - 1
  36.                 EXIT FOR
  37.             END IF
  38.         NEXT
  39.     END IF
  40.     _DISPLAY
  41.     _LIMIT 60
  42.  
  43.  

What I'm doing here is building an array of keys which are pressed down, as they're pressed down.   When we detect up or down presses, I alter my array to reflect those changes.

On the off-chance that keys sometime "ghost" and keep reading false positives, (as you reported was happening to you with your own program), I then compare that array with the current _KEYHIT states, and double check that they're truly down for us, before I process them.  (Simply by printing them in this instance.)

This is the input array handler:

Code: [Select]
    k = _KEYHIT
    IF k > 0 THEN
        '        PRINT k
        FOR i = 0 TO keysdown
            IF Keys(i) = k THEN EXIT FOR 'key is already down and reported as such
            IF Keys(i) = 0 THEN keysdown = keysdown + 1: Keys(i) = k: EXIT FOR
        NEXT
    ELSEIF k < 0 THEN
        FOR i = 0 TO keysdown
            IF Keys(i) = -k THEN 'clear the up key
                FOR j = i TO 9
                    Keys(j) = Keys(j + 1)
                NEXT
                Keys(10) = 0
                keysdown = keysdown - 1
                EXIT FOR
            END IF
        NEXT
    END IF

And this segment is the process handler:
Code: [Select]
    FOR i = 0 TO 10
        IF Keys(i) THEN 'make certain the key is still down
            IF _KEYDOWN(Keys(i)) THEN
                PRINT Keys(i)
            ELSE
                PRINT 0
                Keys(i) = 0
                FOR j = i TO 9
                    Keys(j) = Keys(j + 1)
                NEXT
                Keys(10) = 0
                keysdown = keysdown - 1
                i = i - 1
            END IF
        END IF
    NEXT

I'm thinking something simple like the above should work for your needs.
« Last Edit: July 11, 2020, 03:51:17 am by SMcNeill »
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline johannhowitzer

  • Forum Regular
  • Posts: 118
    • View Profile
Re: Keyboard jamming issue only happening in QB64
« Reply #6 on: July 11, 2020, 04:07:40 am »
Ah, thanks.  I tried the same thing with your code, and it still resulted in sticking the Z or S key, but I was able to see more of what's going on.  The Shift key is the culprit, because of how it's interacting with shift-modifiable keys.  Two examples:

1. Start holding Z > [122]
2. Start holding shift > [122, 100304]
3. Let go of Z > [122, 100304]
4. Let go of shift > [122]

1. Start holding shift > [100304]
2. Start holding Z > [100304, 90]
3. Let go of shift > [90, 122]
4. Let go of Z > [90]

And in the second example, you can't unstick the 90 code by tapping Z by itself - you have to hold shift and tap Z.

My best idea for how to solve this issue would be to manually clear all keyboard codes every frame.  My game engine has the press() function to return current keypress states, but it also has a hold() array, and every frame the current states are dumped into that array, so I can see what was pressed last frame.  Then there's a new_press() function, that returns true only if the button is pressed this frame, and wasn't last frame.

So at the end of each frame, I would clear the keyboard codes right after storing what's pressed in hold().  Not knowing much about hardware, or how _keydown actually interacts with the keyboard in detail, I'm gonna need some more help at this point.  But at least now we know what the problem is!  Thanks a bunch.

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Keyboard jamming issue only happening in QB64
« Reply #7 on: July 11, 2020, 04:13:41 am »
Then make certain to process all keys as either uppercase or lowercase.

k = _KEYHIT
IF k > 64 and k < 91 then k = k + 32
IF k < -64 and k > -91 then k = k - 32

The first line would turn your A-Z keydown into an a-z keydown, and the second would work with the keyup codes.  :)
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline johannhowitzer

  • Forum Regular
  • Posts: 118
    • View Profile
Re: Keyboard jamming issue only happening in QB64
« Reply #8 on: July 11, 2020, 05:25:28 am »
A couple questions still... I've never used _keyhit and this is a little confusing to me.

1. _keyhit appears to return only one value, so is it (a) the last key that was pressed, (b) a key that is currently pressed when the program reaches the _keyhit, (c) all keys currently pressed, processed into one complex value, like how _rgba works?

2. If (b), does it pick out one key among several pressed in a priority order or something?

3. It seems like there's some mixing of terms, as I read that last line as still involving _keydown.  It took me several minutes to realize by "keydown" you might be meaning lowercase, and "keyup" you mean uppercase, I think?

4. Looking at your code, I can't make heads or tails of what half the stuff is doing.  Marked it up with my own comments about what I think might be going on:

Code: QB64: [Select]
  1. DIM Keys(10)
  2.  
  3.  
  4.     CLS
  5.     FOR i = 0 TO 10
  6.         IF Keys(i) THEN ' If this Keys() index contains a non-false value?
  7.             IF _KEYDOWN(Keys(i)) THEN ' Using _keydown on the stored code in Keys()
  8.                 PRINT Keys(i) ' Print the code, as we already saw
  9.             ELSE
  10.                 PRINT 0 ' Prints a zero on the screen?  Never saw this happen
  11.                 Keys(i) = 0 ' Sees the key is no longer down, clear the value
  12.                 FOR j = i TO 9 ' Collapse the array, eliminating the cleared value
  13.                     Keys(j) = Keys(j + 1)
  14.                 NEXT
  15.                 Keys(10) = 0 ' After collapsing, the last index should always be clear
  16.                 keysdown = keysdown - 1 ' Decrement a counter of how many keys are pressed
  17.                 i = i - 1 ' Decrement the for loop's counter, so next loop will continue at the same counter
  18.             END IF
  19.         END IF
  20.     NEXT
  21.     k = _KEYHIT ' Detect a keystroke?  How are multiple keystrokes on the same frame detected by this?
  22.     IF k > 0 THEN ' A keystroke was detected
  23.         '        PRINT k
  24.         FOR i = 0 TO keysdown
  25.             IF Keys(i) = k THEN EXIT FOR ' Don't add a duplicate keystroke to Keys()
  26.             IF Keys(i) = 0 THEN keysdown = keysdown + 1: Keys(i) = k: EXIT FOR ' Found an empty index, add here and increment number of keys pressed
  27.         NEXT
  28.     ELSEIF k < 0 THEN ' OK, I'm maybe gathering that "keyup" might have meant a key was released?
  29.         FOR i = 0 TO keysdown ' As before, collapse the array since a key was detected released?
  30.             IF Keys(i) = -k THEN 'clear the up key
  31.                 FOR j = i TO 9
  32.                     Keys(j) = Keys(j + 1)
  33.                 NEXT
  34.                 Keys(10) = 0
  35.                 keysdown = keysdown - 1
  36.                 EXIT FOR
  37.             END IF
  38.         NEXT
  39.     END IF
  40.     _DISPLAY
  41.     _LIMIT 60
  42.  
  43.  

This reply has been more or less a brain dump of my reactions to everything, because I'm confused enough to be unsure what questions I should be asking, just trying to wrap my head around how this works.  Hopefully unloading this much about my thoughts will tell you where I might be wrong or unclear.  This looks like a potential solution, but I don't understand it nearly enough to use it, and I've been referring to the wiki a lot during writing this post, it wasn't especially helpful in this case.

My greatest concern here, once I understand how to use this, is detection of multiple new keystrokes on the same frame.  When I ran the program in the first place, it seemed to be detecting them just fine, but _keydown was still involved here, and I wasn't playing the window back frame by frame to see if there was a delay.

Thanks for taking the time to help me with this!

Offline Cobalt

  • QB64 Developer
  • Forum Resident
  • Posts: 878
  • At 60 I become highly radioactive!
    • View Profile
Re: Keyboard jamming issue only happening in QB64
« Reply #9 on: July 11, 2020, 10:58:31 am »
I did not see anyone else mention this on my brief skim so,

Do not forget to add _KEYCLEAR to then end of your loop to remove unwanted buffer data.

Depending on how fast your computer is and how big your keyboard buffer is you can get large amounts of  extra  characters printed and or read.
Granted after becoming radioactive I only have a half-life!

Offline johannhowitzer

  • Forum Regular
  • Posts: 118
    • View Profile
Re: Keyboard jamming issue only happening in QB64
« Reply #10 on: July 11, 2020, 08:28:57 pm »
Hmm.  That seemed hopeful, but adding _keyclear to the end of my loop changed nothing, and adding it to the end of SMcNeill's loop completely eliminated all keypresses, as far as I could tell.

Offline johannhowitzer

  • Forum Regular
  • Posts: 118
    • View Profile
Re: Keyboard jamming issue only happening in QB64
« Reply #11 on: July 12, 2020, 02:50:05 am »
As a last resort, if it comes to it, I can just disallow shift in keybinds, not a big deal.  It's part of the default controls, and I think it's kind of natural to use, but I'm not married to it.  Modifier keys in general have always made me a little bit concerned, being able to bind alt for example would generate a game input if the player uses alt+tab, and ctrl would generate an input if the player uses ctrl+printscreen.  The most generally reliable solution may just be to lock out all modifier keys.  I'm already disallowing binding to F1-F12 and num/caps/scroll lock.

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Keyboard jamming issue only happening in QB64
« Reply #12 on: July 12, 2020, 03:16:19 am »
Wouldn’t the easiest solution just be _KEYDOWN, without any loops or all, since you only have a total of 12 interaction keys?

IF  _KEYDOWN(90) OR _KEYDOWN(122) THEN ‘it’s a “Z” or “z” key down.
    ‘Do Z stuff
END IF

....and so on...
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline johannhowitzer

  • Forum Regular
  • Posts: 118
    • View Profile
Re: Keyboard jamming issue only happening in QB64
« Reply #13 on: July 12, 2020, 03:42:57 am »
That's what I'm already doing, and that's the problem.  _keydown is returning true for keys that aren't being pressed.  When I run my press() function on, say, the Z key, it's checking both _keydown(90) and _keydown(122) via the key_ref() array of codes - but either the uppercase or lowercase is returning true from _keydown when the key isn't pressed.

FellippeHeitor

  • Guest
Re: Keyboard jamming issue only happening in QB64
« Reply #14 on: July 12, 2020, 05:33:50 am »
Try Steve's simpler solution above, without jumping though the hoops of functions and arrays. See if that works please.