Read multiple keys from keyboard?

All aspects of programming on the Commander X16.
Dacobi
Posts: 292
Joined: Sun Dec 19, 2021 1:44 am
Location: Samsø, Denmark
Contact:

Question Read multiple keys from keyboard?

Post by Dacobi »

I've been working on a game where besides using joysticks I wanted keyboard controls, but I can't seem to figure out how to read more than one key?

At first I used cbm_k_getin, but in the emulator it only returns the last key that was being hold down.
I've been looking at kbdbuf_peek, but it seems I would need a function like kbdbuf_get? which doesn't seem to exist?
DragWx
Posts: 342
Joined: Tue Mar 07, 2023 9:07 pm

Re: Read multiple keys from keyboard?

Post by DragWx »

If you read joystick 0, that's the "keyboard joystick" that the kernal sets up for you, and it provides button-down/button-up state similar to how the joysticks work, but for a subset of keys on the keyboard instead (Z, X, A, S, D, C, Enter, Left Shift, Arrow keys).

If you want this but for an arbitrary set of keys instead, you will need to set up a custom routine for handling key-down/key-up events, where you watch for scancodes you're interested in, and update variables based on whether that scancode was getting pressed or getting released.
User avatar
Kevin Murphy Games
Posts: 15
Joined: Tue Feb 21, 2023 2:42 pm

Re: Read multiple keys from keyboard?

Post by Kevin Murphy Games »

Are you using Basic Or Assembler ?

Did you know that you can read certain keys, by reading the joystick ( if no joystick is plugged in )

The cursor keys are mapped to the joystick directions and the buttons too.

Matt Heffernan has a nice video tutorial on the subject, as well as lots of other excellent videos.

https://www.youtube.com/watch?v=Q5vw-wA ... eRetroDesk

This page also has documentation

https://github.com/commanderx16/x16-doc ... 0KERNAL.md



Here is an assembly example i use

read_joystick

; Joystick 0 Is Also Mapped To The Following Keys

; Ctrl Mapped To NES A Button
; Alt Mapped To NES B Button

; Ctrl Mapped To SNES B Button
; Alt Mapped To SNES Y Button

; Space Mapped To Select Button

; Enter Mapped To Start Button


lda #0
sta joystick_0_up
sta joystick_0_down
sta joystick_0_left
sta joystick_0_right

; Read Joystick 0
lda #0
jsr $ff56

sta joystick_0_status

and #8
beq read_joystick_loop_0
lda #1
sta joystick_0_down



read_joystick_loop_0

lda joystick_0_status
and #4
beq read_joystick_loop_1
lda #1
sta joystick_0_up



read_joystick_loop_1

lda joystick_0_status
and #2
beq read_joystick_loop_2
lda #1
sta joystick_0_right



read_joystick_loop_2

lda joystick_0_status
and #1
beq read_joystick_loop_3
lda #1
sta joystick_0_left


read_joystick_loop_3

rts


joystick_0_status
.byte 0

joystick_0_up
.byte 0

joystick_0_down
.byte 0

joystick_0_left
.byte 0

joystick_0_right
.byte 0



Calling the routine 'read_joystick' every frame allows you to check the following variables for a value of 1.

0 = No movement
1 = Movement

joystick_0_up
joystick_0_down
joystick_0_left
joystick_0_right

This reads the cursor keys if no joystick is plugged in and in any combination.


If on the other hand you want to read keys other than those mapped to the joystick then you could do what i did and write your own keyboard irq routine.

This will allow you to read any combination of key presses at the same time if you flag each keypress.

The end of this page shows an example

https://github.com/commanderx16/x16-doc ... 0Editor.md

Titled - Custom Keyboard Scancode Handler

I could also provide a list of scancodes for the irq keyboard handler if you dont already have it.
Dacobi
Posts: 292
Joined: Sun Dec 19, 2021 1:44 am
Location: Samsø, Denmark
Contact:

Re: Read multiple keys from keyboard?

Post by Dacobi »

Thanks for your replies.

I was aware of joystick 0 but didn't know about the custom keyhandler.

Since I want to create 2 virtual joysticks this seems to be the way to do it.
I could also provide a list of scancodes for the irq keyboard handler if you dont already have it.
That would be appreciated if they are different than the normal values returned by cbm_k_getin?
User avatar
Kevin Murphy Games
Posts: 15
Joined: Tue Feb 21, 2023 2:42 pm

Re: Read multiple keys from keyboard?

Post by Kevin Murphy Games »

Here is my updated irq keyboard routines.

Tested in the r42 emulator.

Feel free to use,modify or share it as you see fit.

This code scans the entire keyboard and allows detection of multiple keypresses.

Call 'set_keyboard_irq' just once and the table 'keyboard_scancodes_status' holds the status for each key.
0 = Key Released : Up
1 = Key Pressed : Down




; Example Code To Read Keys

; ldx #Array_Index : eg 0 = Key A : 36 = Key Up Cursor

; lda keyboard_scancodes_status , x

; beq Key_Not_Pressed

; Key Pressed Code Here





set_keyboard_irq

sei
lda #<keyhandler
sta $032e
lda #>keyhandler
sta $032f
cli
rts


keyhandler

php
pha
phx ; 65c02 Specific Instruction
phy ; 65c02 Specific Instruction


sta key_scancode ; // Save Scancode


; Save Carry Flag Status
bcs key_loop_0

lda #1
sta key_carry_flag_status

jmp key_loop_1

key_loop_0
lda #0
sta key_carry_flag_status



key_loop_1

ldx #0

key_loop_2
lda key_scancode
cmp keyboard_scancodes , x
bne key_loop_3

lda key_carry_flag_status
sta keyboard_scancodes_status , x

jmp key_loop_4

key_loop_3
inx
cpx #83
bne key_loop_2

key_loop_4
ply ; 65c02 Specific Instruction
plx ; 65c02 Specific Instruction
pla
plp

rts





keyboard_scancodes

.byte 28 ; Key ( A ) ( Array Index 0 )

.byte 50 ; Key ( B ) ( Array Index 1 )

.byte 33 ; Key ( C ) ( Array Index 2 )

.byte 35 ; Key ( D ) ( Array Index 3 )

.byte 36 ; Key ( E ) ( Array Index 4 )

.byte 43 ; Key ( F ) ( Array Index 5 )

.byte 52 ; Key ( G ) ( Array Index 6 )

.byte 51 ; Key ( H ) ( Array Index 7 )

.byte 67 ; Key ( I ) ( Array Index 8 )

.byte 59 ; Key ( J ) ( Array Index 9 )

.byte 66 ; Key ( K ) ( Array Index 10 )

.byte 75 ; Key ( L ) ( Array Index 11 )

.byte 58 ; Key ( M ) ( Array Index 12 )

.byte 49 ; Key ( N ) ( Array Index 13 )

.byte 68 ; Key ( O ) ( Array Index 14 )

.byte 77 ; Key ( P ) ( Array Index 15 )

.byte 21 ; Key ( Q ) ( Array Index 16 )

.byte 45 ; Key ( R ) ( Array Index 17 )

.byte 27 ; Key ( S ) ( Array Index 18 )

.byte 44 ; Key ( T ) ( Array Index 19 )

.byte 60 ; Key ( U ) ( Array Index 20 )

.byte 42 ; Key ( V ) ( Array Index 21 )

.byte 29 ; Key ( W ) ( Array Index 22 )

.byte 34 ; Key ( X ) ( Array Index 23 )

.byte 53 ; Key ( Y ) ( Array Index 24 )

.byte 26 ; Key ( Z ) ( Array Index 25 )




.byte 69 ; Key ( 0 ) ( Array Index 26 )

.byte 22 ; Key ( 1 ) ( Array Index 27 )

.byte 30 ; Key ( 2 ) ( Array Index 28 )

.byte 38 ; Key ( 3 ) ( Array Index 29 )

.byte 37 ; Key ( 4 ) ( Array Index 30 )

.byte 46 ; Key ( 5 ) ( Array Index 31 )

.byte 54 ; Key ( 6 ) ( Array Index 32 )

.byte 61 ; Key ( 7 ) ( Array Index 33 )

.byte 62 ; Key ( 8 ) ( Array Index 34 )

.byte 70 ; Key ( 9 ) ( Array Index 35 )




.byte 117 ; Keys ( UP CURSOR And NUMPAD 8 ) ( Array Index 36 )

.byte 114 ; Keys ( DOWN CURSOR And NUMPAD 2 ) ( Array Index 37 )

.byte 107 ; Keys ( LEFT CURSOR And NUMPAD 4 ) ( Array Index 38 )

.byte 116 ; Keys ( RIGHT CURSOR And NUMPAD 6 ) ( Array Index 39 )




.byte 112 ; Keys ( NUMPAD 0 And INSERT ) ( Array Index 40 )

.byte 105 ; Keys ( NUMPAD 1 And END ) ( Array Index 41 )

.byte 122 ; Keys ( NUMPAD 3 And PAGE DOWN ) ( Array Index 42 )

.byte 115 ; Key ( NUMPAD 5 ) ( Array Index 43 )

.byte 108 ; Keys ( NUMPAD 7 And HOME ) ( Array Index 44 )

.byte 125 ; Keys ( NUMPAD 9 And PAGE UP ) ( Array Index 45 )

.byte 124 ; Key ( NUMPAD *) ( Array Index 46 )

.byte 123 ; Key ( NUMPAD - ) ( Array Index 47 )

.byte 74 ; Keys ( NUMPAD / And / ) ( Array Index 48 )

.byte 121 ; Key ( NUMPAD + ) ( Array Index 49 )




.byte 90 ; Keys ( ENTER And NUMPAD ENTER ) ( Array Index 50 )

.byte 102 ; Key ( BACKSPACE ) ( Array Index 51 )

.byte 88 ; Key ( CAPS LOCK ) ( Array Index 52 )

.byte 41 ; Key ( SPACEBAR ) ( Array Index 53 )

.byte 13 ; Key ( TAB ) ( Array Index 54 )

.byte 18 ; Key ( LEFT SHIFT ) ( Array Index 55 )

.byte 89 ; Key ( RIGHT SHIFT ) ( Array Index 56 )

.byte 20 ; Keys ( LEFT CONTROL And RIGHT CONTROL ) ( Array Index 57 )

.byte 17 ; Keys ( LEFT ALT And RIGHT ALT ) ( Array Index 58 )

.byte 113 ; Key ( DELETE ) ( Array Index 59 )

.byte 119 ; Key ( ESCAPE ) ( Array Index 60 )




.byte 5 ; Key ( F1 ) ( Array Index 61 )

.byte 6 ; Key ( F2 ) ( Array Index 62 )

.byte 4 ; Key ( F3 ) ( Array Index 63 )

.byte 12 ; Key ( F4 ) ( Array Index 64 )

.byte 3 ; Key ( F5 ) ( Array Index 65 )

.byte 11 ; Key ( F6 ) ( Array Index 66 )

.byte 131 ; Key ( F7 ) ( Array Index 67 )

.byte 10 ; Key ( F8 ) ( Array Index 68 )

.byte 1 ; Key ( F9 ) ( Array Index 69 )

.byte 9 ; Key ( F10 ) ( Array Index 70 )

.byte 120 ; Key ( F11 ) ( Array Index 71 )

.byte 7 ; Key ( F12 ) ( Array Index 72 )




.byte 78 ; Key ( MINUS ) ( Array Index 73 )

.byte 85 ; Key ( EQUALS ) ( Array Index 74 )

.byte 73 ; Key ( PERIOD ) ( Array Index 75 )

.byte 65 ; Key ( COMMA ) ( Array Index 76 )

.byte 76 ; Key ( SEMI COLON ) ( Array Index 77 )

.byte 82 ; Key ( @ ) ( Array Index 78 )

.byte 14 ; Key ( ` ) ( Array Index 79 )

.byte 84 ; Key ( [ ) ( Array Index 80 )

.byte 91 ; Key ( ] ) ( Array Index 81 )

.byte 93 ; Key ( # ) ( Array Index 82 )




key_scancode
.byte 0

key_carry_flag_status
.byte 0


keyboard_scancodes_status

; 100 Byte Table ( Only 83 Currently Used )
.byte 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0
.byte 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0
.byte 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0
.byte 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0
.byte 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0
.byte 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0
.byte 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0
.byte 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0
.byte 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0
.byte 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0
Last edited by Kevin Murphy Games on Mon Mar 20, 2023 8:49 am, edited 7 times in total.
Dacobi
Posts: 292
Joined: Sun Dec 19, 2021 1:44 am
Location: Samsø, Denmark
Contact:

Re: Read multiple keys from keyboard?

Post by Dacobi »

Which is posted below for anyone to use/modify ect.

I went through the entire keyboard testing these.
This is very helpful. Just by a glance the values look different from what I was getting from cbm_k_getin, so I'll probably just copy/paste the entire code into my irq setup asm file : )
Dacobi
Posts: 292
Joined: Sun Dec 19, 2021 1:44 am
Location: Samsø, Denmark
Contact:

Re: Read multiple keys from keyboard?

Post by Dacobi »

I'm having problems installing the keyhandler or do I have to do something extra in the VBLANK irq handler?

I'm using both ASM and C.

I have the handler setup:

Code: Select all

.proc _set_keyboard_irq: near
sei
lda #<keyhandler
sta $032e
lda #>keyhandler
sta $032f
cli
rts
.endproc
and then

Code: Select all

unsigned char getkey(unsigned char ckeynum){
    unsigned char retval;
    keynum = ckeynum;

    __asm__("ldx _keynum");
   getkeystat();

   retval = curkey;  
   return retval;
}

Code: Select all

.proc _getkeystat: near
   lda keyboard_scancodes_status , x
   sta _curkey
  rts
.endproc
but getkeystat always returns 0.
However if I manually set one byte in keyboard_scancodes_status to 1 it does return the correct value.
User avatar
Kevin Murphy Games
Posts: 15
Joined: Tue Feb 21, 2023 2:42 pm

Re: Read multiple keys from keyboard?

Post by Kevin Murphy Games »

Ahh i didnt realise you were using C.

I was using the VBCC compiler recently and had to drop it because it was just using up far too much memory.
Out of curiosity which C Compiler are you using ?

I would suggest putting the array and variables into specific memory locations, 1024 - 2023 is 1k of free low ram.

Then in C use a pointer to access that specific ram (array).

And just inline all the assembler code i posted within a C function.

You should only have to call the assembly code once and the irq's automatically set the array with values when a key is pressed or released.


So, Create A Pointer
unsigned char *key_pointer ;

// Point Pointer At Memory Address 1024 ( or pre calculated address )
key_pointer = (unsigned char*) 1024 ; // Start Of Array

// Read Memory Location 1024 ( which is the key status )
key_status = *key_pointer ;

I used 1024 as an example memory address, but you'll have to supply an address that is calculated from the index into the array for the key status you want to read.


I remember having similar problems using C and had to resort to using memory locations and pointers.
Dacobi
Posts: 292
Joined: Sun Dec 19, 2021 1:44 am
Location: Samsø, Denmark
Contact:

Re: Read multiple keys from keyboard?

Post by Dacobi »

I'm using cc65, but the problem is this code in the keyhandler:

Code: Select all

lda $9f27
and #1
bne key_loop_4
If I comment it out everything works fine.
Not sure if it has something to do with my custom VBLANK irq handler?

I have a C file and an ASM file which both import/export symbols from each other.
the ASM file has a function to setup a custom VBLANK irq handler that calls a function in C.
User avatar
Kevin Murphy Games
Posts: 15
Joined: Tue Feb 21, 2023 2:42 pm

Re: Read multiple keys from keyboard?

Post by Kevin Murphy Games »

Here is my normal IRQ handler vector.
vector $0314 - $0315

Here is the keyboard irq vector
$032e - $032f

Both different.

I have both irq's triggering.
i'm not sure if

lda $9f27 ; ( Only Working In Windowed Mode )
and #1
beq

is actually needed in the keyboard handler.

Incidentally, i can only read a raster irq in windowed mode. how about you ?

So i'm assuming a hardware irq triggers, goes to the hardware vector kernal routines and then jumps to the relevent software vector. I don't fully understand the process.
So if thats the case the $9f27 test shouldn't be needed in the keyboard handler.
I havnt tested it though.


Here is my normal IRQ Handler.

set_normal_irqs

; Normal Irq Vector
; $0314 = 252 Low Byte
; $0315 = 230 Hi Byte

; Normal Irq Vector Address = ( 230 * 256 ) + 252 = = 59132 = $e6fc

sei
lda #< custom_irq
sta $0314
lda #> custom_irq
sta $0315
cli
rts

custom_irq

; Check Raster IRQ Has Triggered
lda $9f27 ; ( Only Working In Windowed Mode )
and #1
beq custom_irq_exit

; my code

custom_irq_exit

lda #3
sta $9f27

jmp 59132 ; Jump To Normal Kernal IRQ Routines


I don't know if thats useful to you or not.
Post Reply