445 lines
7.9 KiB
C
445 lines
7.9 KiB
C
|
#include <keyboard.h>
|
||
|
#include <mpu.h>
|
||
|
|
||
|
//---
|
||
|
// Keyboard variables.
|
||
|
//---
|
||
|
|
||
|
volatile unsigned char keyboard_state[10] = { 0 };
|
||
|
static int repeat_first = 10, repeat_next = 2;
|
||
|
static int last_key = KEY_NONE, last_repeats = 0, last_events = 0;
|
||
|
static volatile int interrupt_flag = 0;
|
||
|
|
||
|
|
||
|
|
||
|
//---
|
||
|
// Auxiliary functions.
|
||
|
//---
|
||
|
|
||
|
/*
|
||
|
sleep()
|
||
|
Puts the CPU in sleep mode and waits for an interrupt to return.
|
||
|
*/
|
||
|
void sleep(void)
|
||
|
{
|
||
|
__asm__
|
||
|
(
|
||
|
"sleep\n\t"
|
||
|
);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
getPressedKey()
|
||
|
Finds a pressed key in the keyboard state and returns it.
|
||
|
|
||
|
@return A pressed key.
|
||
|
*/
|
||
|
int getPressedKey(void)
|
||
|
{
|
||
|
int row = 1, column = 0;
|
||
|
int state;
|
||
|
if(keyboard_state[0] & 1) return KEY_AC_ON;
|
||
|
|
||
|
while(row <= 9 && !keyboard_state[row]) row++;
|
||
|
if(row > 9) return KEY_NONE;
|
||
|
|
||
|
state = keyboard_state[row];
|
||
|
while(!(state & 1))
|
||
|
{
|
||
|
state >>= 1;
|
||
|
column++;
|
||
|
}
|
||
|
|
||
|
return (column << 4) | row;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
getPressedKeys()
|
||
|
Find 'count' pressed keys in the keyboard state.
|
||
|
|
||
|
@arg keys Will be filled.
|
||
|
@arg count Size of array.
|
||
|
|
||
|
@return Number of actual pressed keys found.
|
||
|
*/
|
||
|
int getPressedKeys(int *keys, int count)
|
||
|
{
|
||
|
int row = 1, column;
|
||
|
int found = 0, actually_pressed;
|
||
|
int state;
|
||
|
if(count <= 0) return 0;
|
||
|
|
||
|
if(keyboard_state[0] & 1)
|
||
|
{
|
||
|
keys[found++] = KEY_AC_ON;
|
||
|
count--;
|
||
|
}
|
||
|
|
||
|
while(count && row <= 9)
|
||
|
{
|
||
|
while(row <= 9 && !keyboard_state[row]) row++;
|
||
|
if(row > 9) break;
|
||
|
|
||
|
state = keyboard_state[row];
|
||
|
column = 0;
|
||
|
|
||
|
while(count && column < 8)
|
||
|
{
|
||
|
if(state & 1)
|
||
|
{
|
||
|
keys[found++] = (column << 4) | row;
|
||
|
count--;
|
||
|
}
|
||
|
|
||
|
state >>= 1;
|
||
|
column++;
|
||
|
}
|
||
|
|
||
|
row++;
|
||
|
}
|
||
|
|
||
|
actually_pressed = found;
|
||
|
|
||
|
while(count)
|
||
|
{
|
||
|
keys[found++] = KEY_NONE;
|
||
|
count--;
|
||
|
}
|
||
|
|
||
|
return actually_pressed;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
keyboard_interrupt()
|
||
|
Callback for keyboard update. Allows keyboard analysis functions to
|
||
|
wake only when RTC interrupts happen.
|
||
|
*/
|
||
|
void keyboard_interrupt(void)
|
||
|
{
|
||
|
interrupt_flag = 1;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//---
|
||
|
// Keyboard configuration.
|
||
|
//---
|
||
|
|
||
|
/*
|
||
|
keyboard_setFrequency()
|
||
|
Sets the keyboard frequency. Does nothing when the argument is not a
|
||
|
valid KeyboardFrequency value.
|
||
|
|
||
|
@arg frequency
|
||
|
*/
|
||
|
void keyboard_setFrequency(enum KeyboardFrequency frequency)
|
||
|
{
|
||
|
volatile unsigned char *rcr2;
|
||
|
|
||
|
if(frequency < 1 || frequency > 7) return;
|
||
|
rcr2 = (unsigned char *)(isSH3() ? 0xfffffede : 0xa413fede);
|
||
|
|
||
|
frequency <<= 4;
|
||
|
*rcr2 = (*rcr2 & 0x8f) | frequency;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
keyboard_setRepeatRate()
|
||
|
Sets the default repeat rate for key events. The unit for the argument
|
||
|
is the keyboard period.
|
||
|
For example at 16 Hz, values of (10, 2) will imitate the system
|
||
|
default.
|
||
|
|
||
|
@arg first Delay before first repeat, in keyboard period units.
|
||
|
@arg next Delay before following repeats, in keyboard period
|
||
|
units.
|
||
|
*/
|
||
|
void keyboard_setRepeatRate(int first, int next)
|
||
|
{
|
||
|
if(first < 0) first = 0;
|
||
|
if(next < 0) next = 0;
|
||
|
|
||
|
repeat_first = first;
|
||
|
repeat_next = next;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//---
|
||
|
// Keyboard access.
|
||
|
//---
|
||
|
|
||
|
/*
|
||
|
keylast()
|
||
|
Returns the matrix code of the last pressed key. If repeat_count is
|
||
|
non-NULL, it is set to the number of repetitions.
|
||
|
|
||
|
@arg repeat_count
|
||
|
@return Key matrix code.
|
||
|
*/
|
||
|
int keylast(int *repeat_count)
|
||
|
{
|
||
|
if(repeat_count) *repeat_count = last_repeats;
|
||
|
return last_key;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
getkey()
|
||
|
Blocking function with auto-repeat and SHIFT modifying functionalities.
|
||
|
Roughly reproduces the behavior of the system's GetKey().
|
||
|
|
||
|
@return Pressed key matrix code.
|
||
|
*/
|
||
|
int getkey(void)
|
||
|
{
|
||
|
return getkey_opt(
|
||
|
Getkey_ShiftModifier |
|
||
|
Getkey_AlphaModifier |
|
||
|
|
||
|
Getkey_RepeatArrowKeys,
|
||
|
|
||
|
0
|
||
|
);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
getkey_opt()
|
||
|
Enhances getkey() with most general functionalities.
|
||
|
If max_cycles is non-zero and positive, getkey_opt() will return
|
||
|
KEY_NOEVENT if no event occurs during max_cycle analysis.
|
||
|
|
||
|
@arg options OR-combination of GetkeyOpt values.
|
||
|
@arg max_cycles
|
||
|
|
||
|
@return Pressed key matrix code.
|
||
|
*/
|
||
|
int getkey_opt(enum GetkeyOpt options, int max_cycles)
|
||
|
{
|
||
|
int key;
|
||
|
enum KeyType type;
|
||
|
int modifier = 0, last_modifier = KEY_NONE;
|
||
|
int r;
|
||
|
|
||
|
if(!max_cycles) max_cycles = -1;
|
||
|
|
||
|
while(max_cycles != 0)
|
||
|
{
|
||
|
while(!interrupt_flag) sleep();
|
||
|
interrupt_flag = 0;
|
||
|
if(max_cycles > 0) max_cycles--;
|
||
|
|
||
|
// Getting key and adding modifiers.
|
||
|
key = getPressedKey();
|
||
|
|
||
|
// Handling "no_key" event;
|
||
|
if(key == KEY_NONE)
|
||
|
{
|
||
|
// Condition for returning.
|
||
|
r = (last_key != KEY_NONE &&
|
||
|
options & Getkey_ReleaseEvent);
|
||
|
|
||
|
last_key = KEY_NONE;
|
||
|
last_modifier = KEY_NONE;
|
||
|
last_repeats = 0;
|
||
|
last_events = 0;
|
||
|
|
||
|
if(r) return KEY_NONE;
|
||
|
}
|
||
|
|
||
|
// Handling "new key" events.
|
||
|
else if(key != last_key)
|
||
|
{
|
||
|
if(options & Getkey_ShiftModifier && key == KEY_SHIFT)
|
||
|
{
|
||
|
if(last_modifier != KEY_SHIFT)
|
||
|
modifier ^= MOD_SHIFT;
|
||
|
last_modifier = KEY_SHIFT;
|
||
|
|
||
|
continue;
|
||
|
}
|
||
|
if(options & Getkey_AlphaModifier && key == KEY_ALPHA)
|
||
|
{
|
||
|
if(last_modifier != KEY_ALPHA)
|
||
|
modifier ^= MOD_ALPHA;
|
||
|
last_modifier = KEY_ALPHA;
|
||
|
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
last_key = key;
|
||
|
last_repeats = 0;
|
||
|
last_events = 0;
|
||
|
|
||
|
return key | modifier;
|
||
|
}
|
||
|
|
||
|
// Handling key repetitions.
|
||
|
else
|
||
|
{
|
||
|
type = keytype(key);
|
||
|
|
||
|
// Checking whether this key type is repeated.
|
||
|
if(options & (type << 4))
|
||
|
{
|
||
|
last_events++;
|
||
|
r = last_repeats ? repeat_next : repeat_first;
|
||
|
|
||
|
if(last_events >= r)
|
||
|
{
|
||
|
last_repeats++;
|
||
|
last_events = 0;
|
||
|
|
||
|
return key;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// When no key was pressed during the given delay...
|
||
|
return KEY_NOEVENT;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
multigetkey()
|
||
|
Listens the keyboard for simultaneous key hits. Uses the same options
|
||
|
as getkey_opt().
|
||
|
multigetkey() fills the 'keys' array with 'count' key codes, adding
|
||
|
KEY_NOKEY if less than 'count' keys are pressed.
|
||
|
Be aware that rectangle and column effects can make multigetkey() read
|
||
|
unpressed keys as pressed (see documentation for more information).
|
||
|
Setting count = 3 is generally safe.
|
||
|
|
||
|
@arg keys Key code array.
|
||
|
@arg count Maximum number of keys that will be read.
|
||
|
@arg max_cycles
|
||
|
*/
|
||
|
void multigetkey(int *keys, int count, int max_cycles)
|
||
|
{
|
||
|
int number;
|
||
|
|
||
|
if(!max_cycles) max_cycles = -1;
|
||
|
|
||
|
while(max_cycles != 0)
|
||
|
{
|
||
|
while(!interrupt_flag) sleep();
|
||
|
interrupt_flag = 0;
|
||
|
if(max_cycles > 0) max_cycles--;
|
||
|
|
||
|
number = getPressedKeys(keys, count);
|
||
|
if(number) return;
|
||
|
|
||
|
// Handle key repetitions.
|
||
|
/*
|
||
|
else
|
||
|
{
|
||
|
type = keytype(key);
|
||
|
|
||
|
// Checking whether this key type is repeated.
|
||
|
if(options & (type << 4))
|
||
|
{
|
||
|
last_events++;
|
||
|
r = last_repeats ? repeat_next : repeat_first;
|
||
|
|
||
|
if(last_events >= r)
|
||
|
{
|
||
|
last_repeats++;
|
||
|
last_events = 0;
|
||
|
|
||
|
return key;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
*/
|
||
|
}
|
||
|
|
||
|
// When no key was pressed during the given delay... (no need to fill
|
||
|
// the array, it has already been done by getPressedKeys()).
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//---
|
||
|
// Key analysis.
|
||
|
//---
|
||
|
|
||
|
/*
|
||
|
keyid()
|
||
|
Returns a non-matrix key code that can be used for array subscript.
|
||
|
Ignores modifiers.
|
||
|
|
||
|
@arg key
|
||
|
@return Modified keycode.
|
||
|
*/
|
||
|
int keyid(int key)
|
||
|
{
|
||
|
if(key < 0) return -1;
|
||
|
key &= MOD_CLEAR;
|
||
|
|
||
|
int row = 9 - (key & 0x0f);
|
||
|
int column = 6 - ((key & 0xf0) >> 4);
|
||
|
|
||
|
return 6 * row + column;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
keychar()
|
||
|
Returns the ASCII character associated with a key, or 0 for control
|
||
|
keys.
|
||
|
|
||
|
@arg key
|
||
|
*/
|
||
|
int keychar(int key)
|
||
|
{
|
||
|
char flat[] = {
|
||
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||
|
0x0, '2', '^', 0x0, 0x0, 0x0,
|
||
|
'X', 'l', 'l', 's', 'c', 't',
|
||
|
0x0, 0x0, '(', ')', ',', '>',
|
||
|
'7', '8', '9', 0x0, 0x0, 0x0,
|
||
|
'4', '5', '6', '*', '/', 0x0,
|
||
|
'1', '2', '3', '+', '-', 0x0,
|
||
|
'0', '.', 'e', '-', 0x0, 0x0
|
||
|
};
|
||
|
char alpha[] = {
|
||
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||
|
0x0, 'r', 'o', 0x0, 0x0, 0x0,
|
||
|
'A', 'B', 'C', 'D', 'E', 'F',
|
||
|
'G', 'H', 'I', 'J', 'K', 'L',
|
||
|
'M', 'N', 'O', 0x0, 0x0, 0x0,
|
||
|
'P', 'Q', 'R', 'S', 'T', 0x0,
|
||
|
'U', 'V', 'W', 'X', 'Y', 0x0,
|
||
|
'Z', ' ', '"', 0x0, 0x0, 0x0
|
||
|
};
|
||
|
|
||
|
int id = keyid(key);
|
||
|
|
||
|
if(key & MOD_ALPHA) return alpha[id];
|
||
|
return flat[id];
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
keytype()
|
||
|
Returns a key's type. Ignores modifiers.
|
||
|
|
||
|
@arg key
|
||
|
@return Key type.
|
||
|
*/
|
||
|
enum KeyType keytype(int key)
|
||
|
{
|
||
|
key &= MOD_CLEAR;
|
||
|
|
||
|
if(key == KEY_UP || key == KEY_RIGHT || key == KEY_DOWN ||
|
||
|
key == KEY_LEFT) return KeyType_Arrow;
|
||
|
|
||
|
if((key & 0x0f) == 0x09) return KeyType_Function;
|
||
|
|
||
|
return keychar(key) ? KeyType_Character : KeyType_Control;
|
||
|
}
|