QB64.org Forum

Active Forums => QB64 Discussion => Topic started by: Qwerkey on June 11, 2019, 10:35:44 am

Title: This Week's Dumb Question About Multiple Simultaneous INKEY$ Handling
Post by: Qwerkey on June 11, 2019, 10:35:44 am
I feel rather ashamed to ask this question (but that hasn't stopped me asking it!).  I am constructing a program where I'd like to allow 2 keys to be pressed at the same time, and for the program to recognise that with two different responses.

I don't suppose that that would be possible (either by INKEY$ or _KEYHIT).  How would the hardware be behaving?  How would the software recognise such?  If, by some remote possibility, this could be done in some way I shan't feel quite so dumb!  But pardon me for cluttering up the site with ridiculous questions (I'm trying to get the keyboard to have the property of a game controller left&right hand).  If I were Odin, I'd create a Special Section for Qwerkey's Stupid Questions with an automatic flushing facility.
Title: Re: This Week's Dumb Question About Multiple Simultaneous INKEY$ Handling
Post by: bplus on June 11, 2019, 10:46:32 am
Checkout _KEYDOWN, it reports when a key is down (or not) and is good for discerning key combinations.
Title: Re: This Week's Dumb Question About Multiple Simultaneous INKEY$ Handling
Post by: Petr on June 11, 2019, 11:08:26 am
Hi Qwerkey,
None of us is perfect and none of us knows everything. Which particular combinations would you like to try?
Title: Re: This Week's Dumb Question About Multiple Simultaneous INKEY$ Handling
Post by: Pete on June 11, 2019, 11:18:05 am
I handle stuff like that with PEEK and POKE. That way, I can highlight text if the shift key is held down and an arrow key is pressed, etc. If the _KEYDOWN doesn't work out, take a look at something I wrote many years ago. It still works in '64...

https://www.tapatalk.com/groups/qbasic/viewtopic.php?f=13959&t=30059&p=177576&hilit=def+seg#p177576

Pete
Title: Re: This Week's Dumb Question About Multiple Simultaneous INKEY$ Handling
Post by: FellippeHeitor on June 11, 2019, 11:22:11 am
I feel rather ashamed to ask this question (but that hasn't stopped me asking it!).  I am constructing a program where I'd like to allow 2 keys to be pressed at the same time, and for the program to recognise that with two different responses.

I don't suppose that that would be possible (either by INKEY$ or _KEYHIT).  How would the hardware be behaving?  How would the software recognise such?  If, by some remote possibility, this could be done in some way I shan't feel quite so dumb!  But pardon me for cluttering up the site with ridiculous questions (I'm trying to get the keyboard to have the property of a game controller left&right hand).  If I were Odin, I'd create a Special Section for Qwerkey's Stupid Questions with an automatic flushing facility.

Code: QB64: [Select]
  1. This:
Title: Re: This Week's Dumb Question About Multiple Simultaneous INKEY$ Handling
Post by: Qwerkey on June 11, 2019, 12:37:23 pm
Thanks guys, it seems that I was so stupid that I hadn't realised that the Question wasn't actually that dumb!  Naturally, before posing the question here I had looked at the _KEYHIT, _KEYDOWN & _KEYCLEAR wiki pages, and assumed that the key combinations only worked for the Sys, ScL, Pause, CapL, Shift, Ctrl, Win, Alt & Menu keys in combination with other keys (they're the one in the wiki which have a "+" next to them, indicating their special combinatory abilities).

But I've now had a go with the example given on the _KEYDOWN wiki page, and indeed you DO seem to be able to have two keys down at once, and both the hardware and software can sort it out.  Quite amazing!

Petr, no need to worry about the mocking self-deprecation.  That's more-or-less the default British trait.  It's all done in the greatest of humour!

Pete, whenever I've seen other members' efforts with PEEK/POKE, I've never understood a thing.

Title: Re: This Week's Dumb Question About Multiple Simultaneous INKEY$ Handling
Post by: SMcNeill on June 11, 2019, 12:48:41 pm
You can also use _KEYHIT to track multiple key presses.  Remember, _KEYHIT gives us TWO values for each keypress — one when the key is pressed down, and a negative value for when the key is released.

Instead of storing the KEYHIT in a single variable (such as just K = _KEYHIT), instead you save it into an array of keys down, and then remove it from the array when keys are let up.

I can give an example, if you’re curious, once I get back home and at my PC later.  (Currently, I’m in town, on my iPad, which is impossible for me to code much from.)
Title: Re: This Week's Dumb Question About Multiple Simultaneous INKEY$ Handling
Post by: Qwerkey on June 11, 2019, 01:10:38 pm
Steve, thanks.  I'll work with _KEYDOWN for the present, using the wiki page example as my guide.  You'll hear from me, no doubt, if I'm struggling.

None of us is perfect and none of us knows everything.

Petr, there you are quite wrong.  Steve McNeill not only knows everything, but he understands everything!
Title: Re: This Week's Dumb Question About Multiple Simultaneous INKEY$ Handling
Post by: SMcNeill on June 11, 2019, 02:10:14 pm
A quick demo of how one could use _KEYHIT to track multiple key presses at the same time, for those who might be curious about the process:

Code: QB64: [Select]
  1. DIM KeysDown(10)
  2.     k = _KEYHIT
  3.     SELECT CASE k
  4.         CASE IS > 0 'key is pressed down
  5.             AlreadyDown = 0 'Assume it's not recorded as down, by default
  6.             FOR i = 1 TO KeysDown(0) 'check to see if the key is already recorded as "down"
  7.                 IF k = KeysDown(i) THEN
  8.                     AlreadyDown = -1 'It's already down
  9.                     EXIT FOR
  10.                 END IF
  11.             NEXT
  12.             IF NOT AlreadyDown THEN
  13.                 KeysDown(0) = KeysDown(0) + 1 '0th element is to track how many keys are down
  14.                 KeysDown(KeysDown(0)) = k 'elements 1 to 10 represent the keys which are actually down
  15.             END IF
  16.         CASE IS < 0 'key is released
  17.             FOR i = 1 TO 10
  18.                 IF KeysDown(i) = -k THEN 'remove the key from the array as it's lifted up
  19.                     FOR j = i TO 9
  20.                         KeysDown(j) = KeysDown(j + 1)
  21.                     NEXT
  22.                     KeysDown(0) = KeysDown(0) - 1 'subtract the total numbers of keys held down from our counter
  23.                     EXIT FOR
  24.                 END IF
  25.             NEXT
  26.         CASE 0 ' we don't do anything if there's no keys being held/released
  27.     END SELECT
  28.  
  29.     'Display some results
  30.     CLS
  31.     PRINT "There are currently"; KeysDown(0); " keys being held down."
  32.     FOR i = 1 TO KeysDown(0)
  33.         PRINT KeysDown(i)
  34.     NEXT
  35.  
  36.     _DISPLAY 'reduce flicker
  37.     _LIMIT 30 'reduce CPU usage
  38. LOOP UNTIL ESCAPE
Title: Re: This Week's Dumb Question About Multiple Simultaneous INKEY$ Handling
Post by: Pete on June 11, 2019, 02:55:15 pm
So getting this into something useful like my highlighting example, this is what came to my mind, first...

Find out if either shift key is held down while a right or left arrow key is pressed

Code: QB64: [Select]
  1. DIM KeysDown(10)
  2. GOSUB dsp
  3.     k = _KEYHIT
  4.     SELECT CASE k
  5.         CASE IS > 0 'key is pressed down
  6.             AlreadyDown = 0 'Assume it's not recorded as down, by default
  7.             FOR i = 1 TO KeysDown(0) 'check to see if the key is already recorded as "down"
  8.                 IF k = KeysDown(i) THEN
  9.                     AlreadyDown = -1 'It's already down
  10.                     EXIT FOR
  11.                 END IF
  12.             NEXT
  13.             IF NOT AlreadyDown THEN
  14.                 KeysDown(0) = KeysDown(0) + 1 '0th element is to track how many keys are down
  15.                 KeysDown(KeysDown(0)) = k 'elements 1 to 10 represent the keys which are actually down
  16.             END IF
  17.             GOSUB dsp
  18.         CASE IS < 0 'key is released
  19.             FOR i = 1 TO 10
  20.                 IF KeysDown(i) = -k THEN 'remove the key from the array as it's lifted up
  21.                     FOR j = i TO 9
  22.                         KeysDown(j) = KeysDown(j + 1)
  23.                     NEXT
  24.                     KeysDown(0) = KeysDown(0) - 1 'subtract the total numbers of keys held down from our counter
  25.                     EXIT FOR
  26.                 END IF
  27.             NEXT
  28.             GOSUB dsp
  29.         CASE 0 ' we don't do anything if there's no keys being held/released
  30.     END SELECT
  31.     _LIMIT 30 'reduce CPU usage
  32. LOOP UNTIL ESCAPE
  33.  
  34. dsp:
  35. 'Display results
  36. PRINT "There are currently"; KeysDown(0); "keys being held down."
  37. FOR i = 1 TO KeysDown(0)
  38.     PRINT KeysDown(i)
  39.  
  40. _DISPLAY 'reduce flicker
  41.  
  42. ' See if shift and left arrow are down
  43. IF KeysDown(0) = 2 THEN
  44.     IF KeysDown(1) + KeysDown(2) >= 100303 + 19200 AND KeysDown(1) + KeysDown(2) <= 100304 + 19200 THEN
  45.         PRINT "Highlighting left initiated!"
  46.         _DISPLAY
  47.         _DELAY 1
  48.     ELSEIF KeysDown(1) + KeysDown(2) >= 100303 + 19712 AND KeysDown(1) + KeysDown(2) <= 100304 + 19712 THEN
  49.         PRINT "Highlighting right initiated!"
  50.         _DISPLAY
  51.         _DELAY 1
  52.     END IF
  53.  

Now maybe there is some "bitwise" way of calculating combined values, which is better than what I presented here. Like I stated, I still use PEEK/POKE routines for these activities. In an actual WP, you have to add highlighting up and down methods, too. Anyway, it's what I love about BASIC, there's more than one way to peel a banana.

800lb gorilla out,

Pete
Title: Re: This Week's Dumb Question About Multiple Simultaneous INKEY$ Handling
Post by: bplus on June 11, 2019, 04:58:14 pm
Steve's code looks like handy way to get key code numbers.
Title: Re: This Week's Dumb Question About Multiple Simultaneous INKEY$ Handling
Post by: Qwerkey on June 12, 2019, 03:31:32 am
Just to confirm, I have included a sequence of _KEYDOWN statements in my code and indeed more than 1 key pressed at the same time has multiple consequences which QB64 handles perfectly.  Wow!
Title: Re: This Week's Dumb Question About Multiple Simultaneous INKEY$ Handling
Post by: Raven_Singularity on June 12, 2019, 12:06:53 pm
Just to add to this:

The number of simultaneous key-downs that a system can handle is determined by the actual keyboard hardware.  The most advanced USB keyboards allow detection of key up/down states for EVERY key simultaneously.  With cheap keyboards, sometimes even 3 simultaneous keypresses can fail!  All keyboards can handle Ctrl, Alt, Shift combinations because OSes so commonly use them as modifiers, but once you get into uncommon combinations like A+B+C, it's much less likely to register the keypresses.

Also to note, PS/2 and the original keyboard connectors physically limit how many keypresses can be sent simultaneously.  USB keyboards, in theory, have no such limits, but in practise most cheap USB keyboards emulate PS/2 under-the-hood, along with their crappy limitations.  Gaming keyboards often advertise how many keys can be held down simultaneously, though some lie about this!  My current piece-of-shit Amazon Basics keyboard is terrible for this, it often fails with three-key combos, despite saying it can handle 128 simultaneous keys or some rubbish.

Back in the day I can remember trying tons of key combos to figure out which could be handled for multiplayer gaming on the same keyboard.  It was tricky to find keys that wouldn't block each other.
Title: Re: This Week's Dumb Question About Multiple Simultaneous INKEY$ Handling
Post by: Jack002 on June 12, 2019, 12:11:28 pm
Years ago I was looking at this topic for the commodore 64. Even two keypresses were not always detectable. There were row and column wires and when you pressed one key the pressing of others was hidden. Not a think on a c64, I am surprised you can do it on any keyboard.
Title: Re: This Week's Dumb Question About Multiple Simultaneous INKEY$ Handling
Post by: SMcNeill on June 12, 2019, 02:24:47 pm
Just to add to this:

The number of simultaneous key-downs that a system can handle is determined by the actual keyboard hardware.  The most advanced USB keyboards allow detection of key up/down states for EVERY key simultaneously.  With cheap keyboards, sometimes even 3 simultaneous keypresses can fail!  All keyboards can handle Ctrl, Alt, Shift combinations because OSes so commonly use them as modifiers, but once you get into uncommon combinations like A+B+C, it's much less likely to register the keypresses.

Also to note, PS/2 and the original keyboard connectors physically limit how many keypresses can be sent simultaneously.  USB keyboards, in theory, have no such limits, but in practise most cheap USB keyboards emulate PS/2 under-the-hood, along with their crappy limitations.  Gaming keyboards often advertise how many keys can be held down simultaneously, though some lie about this!  My current piece-of-shit Amazon Basics keyboard is terrible for this, it often fails with three-key combos, despite saying it can handle 128 simultaneous keys or some rubbish.

Back in the day I can remember trying tons of key combos to figure out which could be handled for multiplayer gaming on the same keyboard.  It was tricky to find keys that wouldn't block each other.

The term of importance here is, “key rollover”.  https://en.m.wikipedia.org/wiki/Rollover_(key)

Most keyboards are listed with a “#-key rollover” rating.  (Or #KRO.)  A very cheep keyboard is called a 2KRO and allows simultaneous pressing of 2 keys.  A standard keyboard is often a 4KRO (4 key presses allowed), and many gaming keyboards are 6KRO.  The truly expensive keyboards which allow EVERY key to be pressed and handled at once are called NKRO.  (n-key rollover)

From my personal experience, most USB keyboards top out at 6KRO, while you need a PS/2 keyboard for NKRO usage.
Title: Re: This Week's Dumb Question About Multiple Simultaneous INKEY$ Handling
Post by: SMcNeill on June 12, 2019, 02:31:28 pm
A nice link on the subject: http://blog.controlspace.org/2010/08/n-key-rollover-what-it-is-and-how-to.html

And to explain the USB and PS/2 difference: 
Quote
PS/2 vs USB Technical Limitations

Keep the following in mind if you have an n-key rollover keyboard that can be hooked up to your computer through either USB or a PS/2 port:
USB protocol limitation - A max of 10 simultaneous key presses are recognized, 6 non-modifier keys ('w', 'a', 's', 'd', etc) + 4 modifier keys (Shift, Caps, Ctrl, etc).  Although you are limited to 6 regular keys you are still guaranteed that any combination of keys will be recognized properly if you have an n-key rollover keyboard. I would guess that most people would not need support for more keys than this. I would also guess that the 6 key limit may have had something to do with braille input requirements rather than someone choosing an arbitrary limit (although that doesn't explain why the limit exists in the first place).
PS/2 - There are no limitations when using a PS/2 connection with your keyboard. You will truly get full n-key rollover support.
When given the choice between using PS/2 or USB, it is generally recommended to choose PS/2 since it doesn't have the rollover limitations.  However, if you enjoy hotplug support which PS/2 doesn't have, USB may very well be the better choice for you.
Title: Re: This Week's Dumb Question About Multiple Simultaneous INKEY$ Handling
Post by: Raven_Singularity on June 12, 2019, 08:02:23 pm
From my personal experience, most USB keyboards top out at 6KRO, while you need a PS/2 keyboard for NKRO usage.

Really?

I've never encountered a PS/2 keyboard that could handle even 4 simultaneous keys down, unless the keys included the standard modifiers (Ctrl, Alt, Shift).  Haven't seen a PS/2 keyboard that could handle A+B+C+D.


Edit:
Thanks for the link.