mirror of https://gitlab.com/camelot/kickc.git
174 lines
9.9 KiB
C
174 lines
9.9 KiB
C
// Simple Keyboard Input Library
|
||
// C64 Keyboard Matrix Reference - from http://codebase64.org/doku.php?id=base:reading_the_keyboard
|
||
// Keyboard Codes are %00rrrccc, where rrr is the row ID (0-7) and ccc is the column ID (0-7)
|
||
// +----+----------------------+-------------------------------------------------------------------------------------------------------+
|
||
// | | Write | Read $dc01 (C64 screen code in parenthesis): |
|
||
// |row:| $dc00: row bits +------------+------------+------------+------------+------------+------------+------------+------------+
|
||
// | | | BIT 7 | BIT 6 | BIT 5 | BIT 4 | BIT 3 | BIT 2 | BIT 1 | BIT 0 |
|
||
// +----+----------------------+------------+------------+------------+------------+------------+------------+------------+------------+
|
||
// |0. | #%11111110 (254/$fe) | DOWN ($ )| F5 ($ )| F3 ($ )| F1 ($ )| F7 ($ )| RIGHT ($ )| RETURN($ )|DELETE ($ )|
|
||
// |1. | #%11111101 (253/$fd) |LEFT-SH($ )| e ($05)| s ($13)| z ($1a)| 4 ($34)| a ($01)| w ($17)| 3 ($33)|
|
||
// |2. | #%11111011 (251/$fb) | x ($18)| t ($14)| f ($06)| c ($03)| 6 ($36)| d ($04)| r ($12)| 5 ($35)|
|
||
// |3. | #%11110111 (247/$f7) | v ($16)| u ($15)| h ($08)| b ($02)| 8 ($38)| g ($07)| y ($19)| 7 ($37)|
|
||
// |4. | #%11101111 (239/$ef) | n ($0e)| o ($0f)| k ($0b)| m ($0d)| 0 ($30)| j ($0a)| i ($09)| 9 ($39)|
|
||
// |5. | #%11011111 (223/$df) | , ($2c)| @ ($00)| : ($3a)| . ($2e)| - ($2d)| l ($0c)| p ($10)| + ($2b)|
|
||
// |6. | #%10111111 (191/$bf) | / ($2f)| ^ ($1e)| = ($3d)|RGHT-SH($ )| HOME ($ )| ; ($3b)| * ($2a)| £ ($1c)|
|
||
// |7. | #%01111111 (127/$7f) | STOP ($ )| q ($11)|COMMODR($ )| SPACE ($20)| 2 ($32)|CONTROL($ )| <- ($1f)| 1 ($31)|
|
||
// +----+----------------------+------------+------------+------------+------------+------------+------------+------------+------------+
|
||
|
||
#include <c64.h>
|
||
#include <c64-keyboard.h>
|
||
|
||
// Keycodes for each screen code character from $00-$3f.
|
||
// Chars that do not have an unmodified keycode return $3f (representing RUN/STOP).
|
||
const char keyboard_char_keycodes[] = {
|
||
/*@*/KEY_AT, /*a*/KEY_A, /*b*/KEY_B, /*c*/KEY_C, /*d*/KEY_D, /*e*/KEY_E, /*f*/KEY_F, /*g*/KEY_G,
|
||
/*h*/KEY_H, /*i*/KEY_I, /*j*/KEY_J, /*k*/KEY_K, /*l*/KEY_L, /*m*/KEY_M, /*n*/KEY_N, /*o*/KEY_O,
|
||
/*p*/KEY_P, /*q*/KEY_Q, /*r*/KEY_R, /*s*/KEY_S, /*t*/KEY_T, /*u*/KEY_U, /*v*/KEY_V, /*w*/KEY_W,
|
||
/*x*/KEY_X, /*y*/KEY_Y, /*z*/KEY_Z, /*[*/0x3f, /*£*/KEY_POUND, /*]*/0x3f, /*^*/KEY_ARROW_UP, /*<-*/KEY_ARROW_LEFT,
|
||
/* */KEY_SPACE, /*!*/0x3f, /*"*/0x3f, /*#*/0x3f, /*$*/0x3f, /*%*/0x3f, /*&*/0x3f, /*´*/0x3f,
|
||
/*(*/0x3f, /*)*/0x3f, /***/KEY_ASTERISK, /*+*/KEY_PLUS, /*,*/KEY_COMMA, /*-*/KEY_MINUS, /*.*/KEY_DOT, /*/*/KEY_SLASH,
|
||
/*0*/KEY_0, /*1*/KEY_1, /*2*/KEY_2, /*3*/KEY_3, /*4*/KEY_4, /*5*/KEY_5, /*6*/KEY_6, /*7*/KEY_7,
|
||
/*8*/KEY_8, /*9*/KEY_9, /*:*/KEY_COLON, /*;*/KEY_SEMICOLON, /*<*/0x3f, /*=*/KEY_EQUALS, /*>*/0x3f, /*?*/0x3f
|
||
};
|
||
|
||
// Keyboard row bitmask as expected by CIA#1 Port A when reading a specific keyboard matrix row (rows are numbered 0-7)
|
||
char keyboard_matrix_row_bitmask[8] = { 0b11111110, 0b11111101, 0b11111011, 0b11110111, 0b11101111, 0b11011111, 0b10111111, 0b01111111 };
|
||
|
||
// Keyboard matrix column bitmasks for a specific keybooard matrix column when reading the keyboard. (columns are numbered 0-7)
|
||
char keyboard_matrix_col_bitmask[8] = { 0b00000001, 0b00000010, 0b00000100, 0b00001000, 0b00010000, 0b00100000, 0b01000000, 0b10000000 };
|
||
|
||
// Initialize keyboard reading by setting CIA#1 Data Direction Registers
|
||
void keyboard_init() {
|
||
// Keyboard Matrix Columns Write Mode
|
||
CIA1->PORT_A_DDR = 0xff;
|
||
// Keyboard Matrix Columns Read Mode
|
||
CIA1->PORT_B_DDR = 0x00;
|
||
}
|
||
|
||
// Check if any key is currently pressed on the keyboard matrix
|
||
// Return 0 if no key is pressed and not 0 if any key is pressed
|
||
char keyboard_matrix_any(void) {
|
||
CIA1->PORT_A = 0;
|
||
return ~CIA1->PORT_B;
|
||
}
|
||
|
||
// Read a single row of the keyboard matrix
|
||
// The row ID (0-7) of the keyboard matrix row to read. See the C64 key matrix for row IDs.
|
||
// Returns the keys pressed on the row as bits according to the C64 key matrix.
|
||
// Notice: If the C64 normal interrupt is still running it will occasionally interrupt right between the read & write
|
||
// leading to erroneous readings. You must disable the normal interrupt or sei/cli around calls to the keyboard matrix reader.
|
||
char keyboard_matrix_read(char rowid) {
|
||
CIA1->PORT_A = keyboard_matrix_row_bitmask[rowid];
|
||
char row_pressed_bits = ~CIA1->PORT_B;
|
||
return row_pressed_bits;
|
||
}
|
||
|
||
// Determines whether a specific key is currently pressed by accessing the matrix directly
|
||
// The key is a keyboard code defined from the keyboard matrix by %00rrrccc, where rrr is the row ID (0-7) and ccc is the column ID (0-7)
|
||
// All keys exist as as KEY_XXX constants.
|
||
// Returns zero if the key is not pressed and a non-zero value if the key is currently pressed
|
||
char keyboard_key_pressed(char key) {
|
||
char colidx = key&7;
|
||
char rowidx = key>>3;
|
||
return keyboard_matrix_read(rowidx) & keyboard_matrix_col_bitmask[colidx];
|
||
}
|
||
|
||
// Get the keycode corresponding to a specific screen code character
|
||
// ch is the character to get the key code for ($00-$3f)
|
||
// Returns the key code corresponding to the passed character. Only characters with a non-shifted key are handled.
|
||
// If there is no non-shifted key representing the char $3f is returned (representing RUN/STOP) .
|
||
char keyboard_get_keycode(char ch) {
|
||
return keyboard_char_keycodes[ch];
|
||
}
|
||
|
||
// Keyboard event buffer. Contains keycodes for key presses/releases. Presses are represented by the keycode. Releases by keycode | $40. The buffer is filled by keyboard_scan()
|
||
char keyboard_events[8];
|
||
// Keyboard event buffer size. The number of events currently in the event buffer
|
||
char keyboard_events_size = 0;
|
||
// Current keyboard modifiers (left shift, right shift, ctrl, commodore)
|
||
char keyboard_modifiers = 0;
|
||
// Left shift is pressed
|
||
const char KEY_MODIFIER_LSHIFT = 1;
|
||
// Right shift is pressed
|
||
const char KEY_MODIFIER_RSHIFT = 2;
|
||
// CTRL is pressed
|
||
const char KEY_MODIFIER_CTRL = 4;
|
||
// Commodore is pressed
|
||
const char KEY_MODIFIER_COMMODORE = 8;
|
||
// Any shift is pressed
|
||
const char KEY_MODIFIER_SHIFT = KEY_MODIFIER_LSHIFT|KEY_MODIFIER_RSHIFT;
|
||
// The values scanned values for each row. Set by keyboard_scan() and used by keyboard_get_event()
|
||
char keyboard_scan_values[8];
|
||
|
||
// Scans the entire matrix to determine which keys have been pressed/depressed.
|
||
// Generates keyboard events into the event buffer. Events can be read using keyboard_event_get().
|
||
// Handles debounce and only generates events when the status of a key changes.
|
||
// Also stores current status of modifiers in keyboard_modifiers.
|
||
void keyboard_event_scan() {
|
||
char keycode = 0;
|
||
for(char row : 0..7) {
|
||
char row_scan = keyboard_matrix_read(row);
|
||
if(row_scan!=keyboard_scan_values[row]) {
|
||
// Something has changed on the keyboard row - check each column
|
||
for(char col : 0..7){
|
||
// XOR of row scan with the last seen row scan AND'ed with the col bitmask will be non-0 if the key status is changed
|
||
if(((row_scan^keyboard_scan_values[row])&keyboard_matrix_col_bitmask[col])!=0) {
|
||
// Key(row, col) status has changed. We have an event.
|
||
// Only process event if there is still room in the buffer
|
||
if(keyboard_events_size!=8) {
|
||
// AND of row scan and bit mask determines if key is pressed or released
|
||
char event_type = row_scan&keyboard_matrix_col_bitmask[col];
|
||
if(event_type==0) {
|
||
// Key released
|
||
keyboard_events[keyboard_events_size++] = keycode|0x40;
|
||
} else {
|
||
// Key pressed
|
||
keyboard_events[keyboard_events_size++] = keycode;
|
||
}
|
||
}
|
||
}
|
||
keycode++;
|
||
}
|
||
// Store the current keyboard status for the row to debounce
|
||
keyboard_scan_values[row] = row_scan;
|
||
} else {
|
||
// Update current keycode
|
||
keycode = keycode + 8;
|
||
}
|
||
}
|
||
// Update the keyboard modifiers
|
||
keyboard_modifiers = 0;
|
||
if(keyboard_event_pressed(KEY_LSHIFT)!= 0) {
|
||
keyboard_modifiers = keyboard_modifiers | KEY_MODIFIER_LSHIFT;
|
||
}
|
||
if(keyboard_event_pressed(KEY_RSHIFT)!= 0) {
|
||
keyboard_modifiers = keyboard_modifiers | KEY_MODIFIER_RSHIFT;
|
||
}
|
||
if(keyboard_event_pressed(KEY_CTRL)!= 0) {
|
||
keyboard_modifiers = keyboard_modifiers | KEY_MODIFIER_CTRL;
|
||
}
|
||
if(keyboard_event_pressed(KEY_COMMODORE)!= 0) {
|
||
keyboard_modifiers = keyboard_modifiers | KEY_MODIFIER_COMMODORE;
|
||
}
|
||
}
|
||
|
||
// Determine if a specific key is currently pressed based on the last keyboard_event_scan()
|
||
// Returns 0 is not pressed and non-0 if pressed
|
||
char keyboard_event_pressed(char keycode) {
|
||
char row_bits = keyboard_scan_values[keycode>>3];
|
||
return row_bits & keyboard_matrix_col_bitmask[keycode&7];
|
||
}
|
||
|
||
// Get the next event from the keyboard event buffer.
|
||
// Returns $ff if there is no event waiting. As all events are <$7f it is enough to examine bit 7 when determining if there is any event to process.
|
||
// The buffer is filled by keyboard_event_scan()
|
||
char keyboard_event_get() {
|
||
if(keyboard_events_size==0) {
|
||
return 0xff;
|
||
} else {
|
||
return keyboard_events[--keyboard_events_size];
|
||
}
|
||
}
|
||
|