Author Topic: Check for multiple keypress, but just "once", how?  (Read 7585 times)

0 Members and 1 Guest are viewing this topic.

Offline Jerros

  • LV4 Regular (Next: 200)
  • ****
  • Posts: 137
  • Rating: +9/-0
    • View Profile
Check for multiple keypress, but just "once", how?
« on: July 25, 2010, 10:37:05 am »
Ok, so I know there are several ways to check the key(s) that is/are being hold down, but as far as I know there's only 1 way to check for multiple keys:
Code: [Select]
    LD  b, 4                         ; whatever many times the loop is executed
loop:
    LD     A, %11111111               ; group
    OUT    (1), A
    IN     A, (1)
    CP     %11101101                   ; whatever key(s) you wanna check for
    JR     Z, Label                          ; if the keys you were checking for were pressed, JP to label
   djnz    loop
Works like a charm, in fact, works a bit TOO well; if I keep the correct button(s) down it jumps to "Label" several times per loop. (or each loop, hard to see)
Now, If you'd use the standart:
Code: [Select]
    LD  b, 4                         ; whatever many times the loop is executed
loop:
    b_call _GetCSC
    CP     sk2nd                 ; whatever key you wanna check for
    JR     Z, Label                          ; if the keys you were checking for were pressed, JP to label
     djnz    loop
instead of the first, then there's just 1 jump to label if you hold the button down, BUT it cant check for multiple keys being pressed or not.

Is there a way to both check for multiple keypresses but only jump once untill you release the buttons and press them down again?
I hope I've made myself clear, its hard for me to explain :O
Thanks in advance!
« Last Edit: July 03, 2011, 04:46:49 pm by Jerros »


79% of all statistics are made up randomly.

Offline Quigibo

  • The Executioner
  • CoT Emeritus
  • LV11 Super Veteran (Next: 3000)
  • *
  • Posts: 2031
  • Rating: +1075/-24
  • I wish real life had a "Save" and "Load" button...
    • View Profile
Re: Check for multiple keypress, but just "once", how?
« Reply #1 on: July 25, 2010, 01:29:12 pm »
This code might help.  You use a variable that is zero when no keys are held down and non-zero when keys are being pressed.  That way you can choose to only jump once until the next time the key is down.  Also, you need at least a 7 clock cycle delay between setting the key groups and reading their values because the hardware is slow and otherwise it will read values of the previous key group and can cause weird things to happen.
Code: [Select]
KeyCheck:
ld a,(MyKeyVariable)
or a
jr nz,CheckForRelease
ld a, %11111111
out (1), a
ld b,%11101101 ;This is a delay before reading the key groups.  Does something useful.
in a, (1)
cp b
jp z, Label
jr KeysDone
CheckForRelease:
xor a
out ($01),a
ld a,(de) ;Another delay
in a,($01)
inc a
ld (MyKeyVariable),a
KeysDone:
...

Label:
(MyKeyVariable),a
...
___Axe_Parser___
Today the calculator, tomorrow the world!

Offline Jerros

  • LV4 Regular (Next: 200)
  • ****
  • Posts: 137
  • Rating: +9/-0
    • View Profile
Re: Check for multiple keypress, but just "once", how?
« Reply #2 on: July 26, 2010, 03:02:23 am »
Also, you need at least a 7 clock cycle delay between setting the key groups and reading their values because the hardware is slow and otherwise it will read values of the previous key group and can cause weird things to happen.

Ye, I've read all about that.
I'm not doing it now though, and everything still works fine, but if its better to add the delay I will.

Code: [Select]

ld b,%11101101 ;This is a delay before reading the key groups.  Does something useful.

ld a,(de) ;Another delay

The thing is, I need this routine to be as fast as possible, is anything noticable about the delays?
Or is it lightning speed, just as the rest : )

Thanks alot, I knew there had to be something like this, just didn't knew what. n_n
I'll try your routine later today.
« Last Edit: July 26, 2010, 03:05:06 am by Jerros »


79% of all statistics are made up randomly.

Offline Quigibo

  • The Executioner
  • CoT Emeritus
  • LV11 Super Veteran (Next: 3000)
  • *
  • Posts: 2031
  • Rating: +1075/-24
  • I wish real life had a "Save" and "Load" button...
    • View Profile
Re: Check for multiple keypress, but just "once", how?
« Reply #3 on: July 26, 2010, 03:37:06 am »
Yeah, 7 clock cycles at 6 MHz = 7/6,000,000 seconds = 1.1 micro seconds, no way that can be noticeable.  And in the section you quoted above, it only uses 3 extra cycles than before due to that optimization of mine.

Normally, you don't notice the lack of delay because the first time it passes that part in the program, it has the wrong key group when it tries to read the key, but its set correctly afterward once it finally goes through.  The time you will notice it is if you check a bunch of keys one after another from different key groups.  Then, each check you do is reading from the previous keygroup, which is wrong and you end up with mismatched keys.
___Axe_Parser___
Today the calculator, tomorrow the world!

Offline Jerros

  • LV4 Regular (Next: 200)
  • ****
  • Posts: 137
  • Rating: +9/-0
    • View Profile
Re: Check for multiple keypress, but just "once", how?
« Reply #4 on: July 26, 2010, 03:49:15 am »
Normally, you don't notice the lack of delay because the first time it passes that part in the program, it has the wrong key group when it tries to read the key, but its set correctly afterward once it finally goes through.  The time you will notice it is if you check a bunch of keys one after another from different key groups.  Then, each check you do is reading from the previous keygroup, which is wrong and you end up with mismatched keys.

Aha, well I'm only checking one group, so it won't be a problem to skip the delays, will it?


79% of all statistics are made up randomly.

Offline Quigibo

  • The Executioner
  • CoT Emeritus
  • LV11 Super Veteran (Next: 3000)
  • *
  • Posts: 2031
  • Rating: +1075/-24
  • I wish real life had a "Save" and "Load" button...
    • View Profile
Re: Check for multiple keypress, but just "once", how?
« Reply #5 on: July 26, 2010, 04:03:33 am »
Its possible, but its only a byte more with negligible speed difference, I would go for the extra safety because the downside is so small and if it spares you from a gruesome hour long debugging session in the future it will have all been worth it.
___Axe_Parser___
Today the calculator, tomorrow the world!

Offline Jerros

  • LV4 Regular (Next: 200)
  • ****
  • Posts: 137
  • Rating: +9/-0
    • View Profile
Re: Check for multiple keypress, but just "once", how?
« Reply #6 on: July 27, 2010, 08:11:22 am »
Its possible, but its only a byte more with negligible speed difference, I would go for the extra safety because the downside is so small and if it spares you from a gruesome hour long debugging session in the future it will have all been worth it.

Ok, went for the extra safety...
Another thing, your provided script works like a charm, as long as I only use it to regiser a single button press.
When I press multiple buttons, the script get performed the whole time again, and not just once 'till I've released the buttons again:
Code: [Select]
ld a,(MyKeyVariable)
or a
jr nz,CheckForRelease
    LD     A, %10111111
    OUT    (1), A
ld b,%11101101
    IN     A, (1)
    CP     %11101111
    JP     Z, presyequ
    CP     %11110111
    JP     Z, preswindow
    CP     %11111011
    JP     Z, preszoom
    CP     %11111101
    JP     Z, prestrace
    CP     %11111110
    JP     Z, presgraph

; The above all works perfect with your routine, but the below doesn't:

    CP     %11100111
    JP     Z, presyequ_window
    CP     %11101011
    JP     Z, presyequ_zoom
    CP     %11101101
    JP     Z, presyequ_trace
    CP     %11101110
    JP     Z, presyequ_graph
    CP     %11110011
    JP     Z, preswindow_zoom
    CP     %11110101
    JP     Z, preswindow_trace
    CP     %11110110
    JP     Z, preswindow_graph
    CP     %11111001
    JP     Z, preszoom_trace
    CP     %11111010
    JP     Z, preszoom_graph
    CP     %11111100
    JP     Z, prestrace_graph
jr LabelRestoftheScript
CheckForRelease:
xor a
out ($01),a
ld a,(de)
in a,($01)
inc a
ld (MyKeyVariable),a
LabelRestoftheScript:
     stuf.....


Is the problem in the "presXXX" labels, or is there a different reason it just keeps performing the labels combining multiple keys?
Also, I should've probably mentioned that it sometimes does seem to work, but when you press multiple keys for a while, or just keep 1 button pressed down and change the other the lot gets messed up :c
« Last Edit: July 03, 2011, 04:49:07 pm by Jerros »


79% of all statistics are made up randomly.

Offline thepenguin77

  • z80 Assembly Master
  • LV10 31337 u53r (Next: 2000)
  • **********
  • Posts: 1594
  • Rating: +823/-5
  • The game in my avatar is bit.ly/p0zPWu
    • View Profile
Re: Check for multiple keypress, but just "once", how?
« Reply #7 on: July 27, 2010, 09:00:32 am »
I don't know how big your loop is, but I would say that the problem is that you aren't pressing both keys at exactly the same time. Remember, the calculator runs at 6 MHz. That means that a relatively big loop, say 5,000 clock cycles runs 1,200 times per second. Which also means that you have to press the keys within 1/1,200 of a second because if one is pressed first, just that one is counted and your code says don't look for another.

Here is what I would suggest to fix the problem. When a key is pressed, a count down is started, when that countdown reaches 0, it really does the key scan and then jumps.
Code: [Select]

;pressed is my counter and my pressed flag
;saves space that way


ld a, $BF
out (01), a
ld a, (de) ;this is 7 t-states, but 1 byte
in a, (01)
ld b, a
ld a, (pressed)
or a
jr z, initialScan
jp m, countDown

inc b ;if no keys are pressed, b = $FF
jr nz, buttonDone
xor a
ld (pressed), a
jr buttonDone
initialScan:
inc b
jr z, buttonDone
ld a, -15 ;adjust this delay for responsiveness / window for two presses
ld (pressed), a
jr buttonDone
countDown:
inc a
ld (pressed), a
jr nz, buttonDone

inc a
ld (pressed), a ;putting a one to show its pressed

;do all your two button cp's here
;always use jr instead of jp, jr is 3 t-states faster on fail and 1 byte smaller

;for your singles, I have some optimization

rrca
jr nc, presGraph
rrca
jr nc, presTrace
rrca
jr nc, presZoom
rrca
jr nc, presWindow
rrca
jr nc, presYEqu

;cp is two bytes and 7 t-states
;rrca is 1 bytes and 4 t-states

buttonDone:
This one puts a set delay in between press and go which allows for the second to be pressed.

There is also another option where you wait for the keys to be released and then check what was pressed.
Code: [Select]

;this time pressed holds the last pressed keyscan


ld a, $BF
out (01), a
ld a, (de)
in a, (01)

ld b, a
ld a, (pressed)
or a
jr nz, checkForRelease

ld a, b
inc b
jr z, buttonDone

ld (pressed), a
jr buttonDone

checkForRelease:
inc b
jr nz, buttonDone

ld b, a
xor a
ld (pressed), a
ld a, b



;do your checks here
;don't forget what I said in the first one



buttonDone:

I like writing little optimized routines. After writing both, I kind of like the second one better. But it's up to you, release or delay.
zStart v1.3.013 9-20-2013 
All of my utilities
TI-Connect Help
You can build a statue out of either 1'x1' blocks or 12'x12' blocks. The 1'x1' blocks will take a lot longer, but the final product is worth it.
       -Runer112

Offline Jerros

  • LV4 Regular (Next: 200)
  • ****
  • Posts: 137
  • Rating: +9/-0
    • View Profile
Re: Check for multiple keypress, but just "once", how?
« Reply #8 on: July 27, 2010, 09:55:06 am »
Wow, thank you alot!
I don't think I can use the second routine though, it's a timing-game where you have to press button(s) according to when a sprite is in a certain area, so it needs to respond as soon as you press the button.
But that "timing window" in the first routine sounds perfect, allows me to try and see what's enough time to react to multiple buttons pressed, but not waiting too long for it to feel inresponsive.
Oh, and I know its always better to use "JR", but my jumps are out of range, so...  ;)

EDIT:
Ok this sucks... somehow there's something wrong in the rest of my script, since what you've both posted works...
It wasn't even necasery to perform a diferenct scrip when multiple buttons are pressed, just do the routine of 1 button, and then the other.
But somehow my routine fails, I've re-wrote it several times already, but this just doesnt seem to happen for me ><
It has probably something to do with the massive routines it performs when a button is pressed, I don't know.
Let the long hours of going over every line begin. :'(
« Last Edit: July 28, 2010, 04:16:09 am by Jerros »


79% of all statistics are made up randomly.

Offline DJ Omnimaga

  • Clacualters are teh gr33t
  • CoT Emeritus
  • LV15 Omnimagician (Next: --)
  • *
  • Posts: 55942
  • Rating: +3154/-232
  • CodeWalrus founder & retired Omnimaga founder
    • View Profile
    • Dream of Omnimaga Music
Re: Check for multiple keypress, but just "once", how?
« Reply #9 on: July 29, 2010, 05:15:45 pm »
Bump, in case people missed Jerros EDIT.
Now active at https://discord.gg/cuZcfcF (CodeWalrus server)

Offline AssemblyBandit

  • LV6 Super Member (Next: 500)
  • ******
  • Posts: 374
  • Rating: +60/-1
  • ~AssemblyBandit~
    • View Profile
    • briandm82.com
Re: Check for multiple keypress, but just "once", how?
« Reply #10 on: September 06, 2010, 12:27:37 am »
The best way to handle key presses is in an interrupt, having it in the program kinda wastes processing time, unless your able to press the keys faster than about 300 times a second. Youll find that its at the perfect speed too. To check for multiple key presses just once, they would have to be in the same mask group, or use multiple keymasks and just 'and' the bits together.

 :o Whoa, I had a major error in the simple version heres a better version:
Code: [Select]
keyloop:
 ld a,(OldKey)  ;get the stored previous keypress ($ff means none)
 xor 255  ;set up a mask
 ld c,a  ;store the mask of the keypress that happened earlier
 ld a,$fe  ;get the arrow keys
 out ($01),a
 nop  ;usually i dont wait, or debounce
 in a,($01)
 or $f0  ;mask to only check the arrow keys
 ld (OldKey),a  ;store the new keypress
 or c  ;dont allow the old keypress to get through
 cp %11110101
 jp z,up_left
 cp %11110011
 jp z,up_right
 cp %11111100  
 jp z,down_left
 cp %11111010  
 jp z,down_right
 cp %11111110  
 jp z,down
 cp %11111101  
 jp z,left
 cp %11111011  
 jp z,right
 cp %11110111  
 jp z,up
 ...                 ;do stuff or use a timer here
 ...                 ;if you read the port too fast
 ld bc,$ffff
Delay:
 push bc
 pop bc
 dec bc
 ld a,b
 or c
 jp nz,Delay
 ...                 ;button presses will be too
 ...                 ;sensitive.
 jp keyloop

OldKey:
.db $ff
« Last Edit: September 06, 2010, 02:51:27 am by AssemblyBandit »