gint_strcat/src/keyboard.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;
}