Home
JAQForum Ver 24.01
Log In or Join  
Active Topics
Local Time 09:01 01 Aug 2025 Privacy Policy
Jump to

Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.

Forum Index : Microcontroller and PC projects : MM: Help with INKEY$

     Page 1 of 2    
Author Message
WhiteWizzard
Guru

Joined: 05/04/2013
Location: United Kingdom
Posts: 2944
Posted: 04:45am 24 Sep 2015
Copy link to clipboard 
Print this post

This is not the first time that this topic has been brought up on TBS - but searching through the history unfortunately has not revealed an answer for me. The issue I have is with trying to accurately detect a single key press (on a PS2 keyboard) at very specific times; and NOT to read a buffered key press from an earlier point in time.

The setup I have is a MMBasic program (B31 on a 64-pin MM+) that is effectively a big repeating loop; continuously doing various hardware and software things depending on the state of certain I/O pin inputs.

Part of the big loop also 'interegates' a PS2 keyboard to see if any (single) keys are pressed - if so then the program branches off to do whatever is required (i.e. turn a pin on or off). I am only needing to capture single key presses so I naturally used INKEY$ to try achieve this.

NOTE: I am NOT entering data and hence am not using (or wanting to use) INPUT as this requires 'Enter' to be pressed.

Also, I can not wait for a key to be pressed as the loop needs to be continually cycled through - hence if a key is pressed when interrogated then do 'something', else move on . . .

The issue is that the INKEY$ function returns a character from the keyboard buffer which potentially means that it is NOT necessarily being pressed at the time INKEY$ is invoked.

I thought it would be a simple matter of clearing the 'keyboard buffer prior to using INKEY$ but using INKEY$ (to clear) and then another INKEY$ to read a key does not return anything. I assume this is not a bug as it often appears to be the situation if you refer to Google!

So does anyone have any ideas as to how to approach this? I do not want to use switches on I/O pins - it MUST be keys on a PS2 keyboard.

Timers, SetTick ? ? ?

Appreciate any responses, guidance, or ideas . . . . . . but please, no 'C' solutions (sorry Peter!)


WW

 
Chris Roper
Senior Member

Joined: 19/05/2015
Location: South Africa
Posts: 280
Posted: 05:11am 24 Sep 2015
Copy link to clipboard 
Print this post

You could possibly do it with the PEEK function to read the U1RXREG (or U2RXREG - I am not sure which one is the console) directly. However, if the serial buffer is interrupt driven which it most likely is, the buffer may well catch the character before you do and the hardware has its own 8 level deep Rx Buffer too.

Would it be possible to hook into the Receive Interrupt?

In the long run a CFunction probably would be easier, but if you have your reasons not to use one, then Delving into the Source code and looking for a back door past the INKEY$ function is probably your best bet.

Probably not too help full but I throw the ideas out there for comment.

Cheers
Chris

Edited by Chris Roper 2015-09-25
http://caroper.blogspot.com/
 
Grogster

Admin Group

Joined: 31/12/2012
Location: New Zealand
Posts: 9610
Posted: 05:13am 24 Sep 2015
Copy link to clipboard 
Print this post

First thought that springs to mind, and bear in mind it is 3:10AM here, is to use a diode on the clock or data line from the PS/2 keyboard, to any interrupt capable I/O pin.

As the PS/2 DTA and CLK lines are pulled high, then a pin set low with the PULLDOWN option or an external pulldown resistor on the INT I/O pin, cathod of diode to this I/O pin, anode of the diode to either CLK or DTA - probably CLK.

Any time the CLK line goes low, it SHOULD cause an interrupt jump on the INT pin, at which point you KNOW there was a keypress right then and there, and can use INKEY$ right at the moment it is pressed.

Totally untested, and at this time of the morning, I could be dreaming, but that is my first thought....
Smoke makes things work. When the smoke gets out, it stops!
 
Chris Roper
Senior Member

Joined: 19/05/2015
Location: South Africa
Posts: 280
Posted: 05:18am 24 Sep 2015
Copy link to clipboard 
Print this post

Reading Grogster's reply I realise I was chasing the wrong horse I read PC keyboard not PS/2 keyboard sorry.

http://caroper.blogspot.com/
 
WhiteWizzard
Guru

Joined: 05/04/2013
Location: United Kingdom
Posts: 2944
Posted: 05:28am 24 Sep 2015
Copy link to clipboard 
Print this post

Thanks guys for your ideas.

@Chris - I don't mind using a CFunction - just haven't got my head round them yet (even with the brilliant tuorials from the two Peters). So I would be relying on someone else's code (prefer not to do this if I can avoid it). Time doesn't allow me learning CFunctions; I have tried on numerous occasions but must have some 'phobia; against them!

@Grogs
One thing I should have made clearer is that I do not need to 'guarantee' that I see a key press; I just want to know whether or not it is being pressed at the time I 'interrogate' it.

So in my big loop I want to achieve something like:

.
.
.
IF KEY$ = "C" THEN goto . .
IF KEY$ = "Q" THEN goto . . .
IF KEY$ = "P" THEN goto . . . .
.
.
.


The loop takes a varying number of milliseconds (from about 50 to over 800). If every time it was around 50mS then I can seem to capture the depresses reasonably accurately, but with 250mS or more then there is considerable 'delay' resulting in mis-interpretation of the key being pressed.

Will keep pondering this one . . .

Edited by WhiteWizzard 2015-09-25
 
WhiteWizzard
Guru

Joined: 05/04/2013
Location: United Kingdom
Posts: 2944
Posted: 05:40am 24 Sep 2015
Copy link to clipboard 
Print this post

Here is a piece of code to kind of demonstrate the issue:

Do
a$=INKEY$
IF a$="w" THEN PRINT "W ";
Pause 200
Loop


Run this code; and repeatedly press random keys (but not 'W' or Ctrl-C!). This will put some 'keypresses' into the keyboard buffer which is what INKEY$ 'refers' to when invoked. Then immediately press the W key and see how long it takes to be displayed.

Now shorten the PAUSE to 25 and do the same thing. W is now captured everytime. This would imply using another a$=INKEY to flush the buffer out, but when you do this it doesn't see the 'W' key most of the time

Variations on the above short program infer that INKEY$ is not the way forward.



 
Chris Roper
Senior Member

Joined: 19/05/2015
Location: South Africa
Posts: 280
Posted: 06:19am 24 Sep 2015
Copy link to clipboard 
Print this post

Total untested but what about something like this?

[code]
MyKey$ = "wcqp" ' Keys you wish to catch

Do
a$ = lcase$(INKEY$)
IF instr$(MyKey$, a$) then ' if it is a key we want to trap
rem Process a$
else
do
a$ = INKEY$
loop until a$ = "" ' Clear the buffer
end if

Pause 200
Loop
[/code]

or this:
[code]
do
do
a$ = lcase$(INKEY$)
IF instr$(MyKey$, a$) then Process(a$)
loop untill a$ = ""
loop
[/code]

the above would process all valid keys but if you only want the first valid key then flush the buffer in process(a$).

Not sure if my syntax matches MMBasic as I am currently working in GCBasic and keep mixing the two up but I think you can see what I intend it to do.

Cheers
Chris

Edited by Chris Roper 2015-09-25
http://caroper.blogspot.com/
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 10310
Posted: 09:03am 24 Sep 2015
Copy link to clipboard 
Print this post

  Quote  The issue I have is with trying to accurately detect a single key press (on a PS2 keyboard) at very specific times


I'm probably misunderstanding but I don't think it can work the way you describe. A PS2 keyboard sends a data packet as a key is pressed and another when the key is released. That way the host software can do things like interpret multiple key presses (CTRL/ALT/DELETE). The keyboard may also have an auto-repeat set so that it sends the "pressed" code repeatedly at a pre-defined rate but not the "release" code until there is an actual release.

It would not be normal for the host software to expose a status that says the key had been pressed but not yet released which seems to be what you want. The host software will know this as it determines the position in the state machine but doesn't expose it.

You can run a loop to empty the keyboard buffer and note the last key pressed before you get the buffer empty code ("") but this does not tell you when it was pressed or if it is still pressed. The only way to see if it is still pressed is to empty the buffer and then poll continuously for the auto-repeat timeout (typically 500msec) before deciding.

 
WhiteWizzard
Guru

Joined: 05/04/2013
Location: United Kingdom
Posts: 2944
Posted: 09:25am 24 Sep 2015
Copy link to clipboard 
Print this post

  matherp said  I'm probably misunderstanding but I don't think it can work the way you describe.


Thanks for your comments.

Let me try a very simple analogy with a digital I/O pin:


SETPIN(22),din
.
MLoop:
.
.
.

IF PIN(22) THEN GOTO xyz:
.
.
.
.
xyz:
' do something. . . .
.
.
goto MLoop


The above has a one-line check to see if PIN 22 is high, and if so, the code branches off to label xyz. Now the line that reads the state of PIN 22 returns the 'current' state of PIN22; it does not return the state of the pin at some previous time in the past (which 'could' then clearly have been a different value to the current state).

I simply want to do the same but reading the state of a key on a PS2 keyboard. There use to be a 'KEYDOWN' command in various BASICs which would resolve this issue. Most people seem to incorrectly use INKEY$ (and it works perfectly if your code can 'hang around' such as waiting for a 'Y' or 'N' keypress in response to a 'Yes'/ 'No' question).

Fully aware about code sets, and their make & break codes (and extended codes) which strengthens my doubts that it can actually be done at all.

Please tell me that I am missing something really stupid and that this seemingly simple task can somehow be achieved?
 
vegipete

Guru

Joined: 29/01/2013
Location: Canada
Posts: 1132
Posted: 11:11am 24 Sep 2015
Copy link to clipboard 
Print this post

Does MMBasic still have the KeyDown function?

ky = KeyDown

should put the ascii code of what was (last?) pressed into the variable ky.

Probably up to you to test if it's a new press or one you already saw.
Visit Vegipete's *Mite Library for cool programs.
 
cosmic frog
Guru

Joined: 09/02/2012
Location: United Kingdom
Posts: 302
Posted: 11:48am 24 Sep 2015
Copy link to clipboard 
Print this post

KEYDOWN was available on the MaxiMite but unfortunately not on the MicroMite.
 
WhiteWizzard
Guru

Joined: 05/04/2013
Location: United Kingdom
Posts: 2944
Posted: 11:48am 24 Sep 2015
Copy link to clipboard 
Print this post

  vegipete said   Does MMBasic still have the KeyDown function?

Hi Pete,

Unfortunately the KeyDown feature is not included in MicroMite+ MMBasic (please can someone prove me wrong i.e. Geoff ) I am using v4.7 B31.

However, I do seem to recall that it was included within the MaxiMite MMBasic.

WW
 
TassyJim

Guru

Joined: 07/08/2011
Location: Australia
Posts: 6283
Posted: 12:17pm 24 Sep 2015
Copy link to clipboard 
Print this post

Would this work

' TassyJim
'
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' keep reading the keyboard buffer until it is empty.
' use the last key pressed only
DO
x$=""
DO
a$=INKEY$
IF a$="" THEN EXIT DO
x$=a$
LOOP

PRINT x$

PAUSE 500
LOOP


I don't have a keyboard connected to any device to test here.

JimEdited by TassyJim 2015-09-25
VK7JH
MMedit
 
TassyJim

Guru

Joined: 07/08/2011
Location: Australia
Posts: 6283
Posted: 12:29pm 24 Sep 2015
Copy link to clipboard 
Print this post

Had you tried
ON KEY target

You can enable it as required and disable when you don't want the interruption.
If you do disable, I think that you would need to clear the buffer before you re-enable it.

Jim
VK7JH
MMedit
 
robert.rozee
Guru

Joined: 31/12/2012
Location: New Zealand
Posts: 2442
Posted: 02:04pm 24 Sep 2015
Copy link to clipboard 
Print this post

do you wish multiple keys to be allowed to be down at any one time? and what timeframe would be acceptable for responsiveness? would 1/2 a second be ok?


cheers,
rob :-)
 
WhiteWizzard
Guru

Joined: 05/04/2013
Location: United Kingdom
Posts: 2944
Posted: 02:11pm 24 Sep 2015
Copy link to clipboard 
Print this post

@TassyJim - You maybe onto something with ON KEY

Just tried a simple test program and signs look good. At first I was doubtful as the User Manual implies this reads the 'serial console buffer' i.e. not the keyboard buffer. Anyway, will play more with this . . .

Thanks Jim
 
WhiteWizzard
Guru

Joined: 05/04/2013
Location: United Kingdom
Posts: 2944
Posted: 02:26pm 24 Sep 2015
Copy link to clipboard 
Print this post

@rob - sorry your comments came in while replying to TassyJim.

Multiple keys not required (but are ok). It is a first-come, first-served in terms of checking keys. So for example, if "1" then goto label1, if "2" then goto label2, if "3" then goto label3.

Responsiveness needs to be instant at the line of code enquiring if a key is pressed.

I am going to different parts of the program depending on which key is detected first. I do not need to 'go back' to see if the 'next' key is pressed. I will simply pick up any pressed keys at the next time I go through the loop. If none are pressed then this is fine - as long as my loop is continually executed.

Using the analogy of checking digital input pins should help i.e. at the time I check a pin, if it is high then branch off. If low then check the next pin. If this pin is high then branch off somewhere else, otherwise check the next pin. If a pin is high then the program will deal with that pin, and then eventually the loop will go around again and reach the 'pin check' section again. So I will only check all pins IF all are low; otherwise the first one being high will 'deviate' the program flow.

Now all I need is keys rather than pins . . .

I need to make it clear that potentially lots of keys may be continually 'bashed' throughout my program loop which means an INKEY$ approach will not work as the keyboard buffer would rapidly get filled. Only at the time of checking for a key press do I want to see if a certain key is pressed i.e. NOT read from a buffer that contains 'old' information

Edited by WhiteWizzard 2015-09-26
 
WhiteWizzard
Guru

Joined: 05/04/2013
Location: United Kingdom
Posts: 2944
Posted: 02:37pm 24 Sep 2015
Copy link to clipboard 
Print this post

  Chris Roper said   You could possibly do it with the PEEK function . . .


Could there be a PEEK to somewhere maybe that could simplify things
This is way over my level of understanding so need an 'expert' to comment here . . .
 
robert.rozee
Guru

Joined: 31/12/2012
Location: New Zealand
Posts: 2442
Posted: 02:15am 25 Sep 2015
Copy link to clipboard 
Print this post

you have a couple of options if using a PS/2 keyboard is essential:

1. ask geoff to expose the scancodes returned from a PS/2 keyboard via an interrupt. these have the top bit cleared on a key going down, and the top bit set on the same key going up. you then set up an array of 128 booleans, one element for each key/scancode. upon seeing the down code for a given key, the interrupt service routine sets the appropriate boolean true. upon seeing the up code, it sets is false.

in your main program, scan through the array for true values - these correspond to the keys currently 'down'.

2. write your own PS/2 input routine. this could be done with a custom function, or in basic code. once you have done this, do the same as in 1. above to the scan codes read.


if you just want a keyboard that uses a single pin, have a limited number of keys to detect (less than a coupe of dozen), and are happy that the user is only allowed to press a single key at any time:

3. implement an analog keyboard, where each key causes a different resistance to be present at the output. there were some threads about doing this quite some time ago - i shall dig back through the archives if this is an suitable solution.


cheers,
rob :-)
 
robert.rozee
Guru

Joined: 31/12/2012
Location: New Zealand
Posts: 2442
Posted: 02:18am 25 Sep 2015
Copy link to clipboard 
Print this post

found it. see: http://www.thebackshed.com/forum/forum_posts.asp?TID=6418
 
     Page 1 of 2    
Print this page
The Back Shed's forum code is written, and hosted, in Australia.
© JAQ Software 2025