gintctl/src/gint/keyboard.c

248 lines
6.9 KiB
C

#include <gint/display.h>
#include <gint/keyboard.h>
#include <gint/drivers/keydev.h>
#include <gint/gint.h>
#include <gint/clock.h>
#include <gintctl/util.h>
#include <gintctl/assets.h>
static void position(int row, int col, int *x, int *y, int *w, int *h)
{
#ifdef FX9860G
*x = 1 + (5 + (row>=5)) * col;
*y = 1 + 4 * row + (row >= 1) + (row >= 3);
*w = 4;
*h = 3 + (row == 0 || row >= 5);
if(row >= 5) *y += 1 + (row - 5);
if((row == 1 || row == 2) && col >= 4)
{
*x += 3 * (row == 2) - 2 * (col == 5);
*y += 1 + (row == 1) - 3 * (col == 5);
*w = 3;
}
#endif
#ifdef FXCG50
if(row == 0) *y=2, *x=7+29*col, *w=16, *h=16;
if(row >= 5) *y=108+23*(row-5), *x=2+35*col, *w=30, *h=17;
if(row >= 1 && row <= 4)
{
*y=28+18*(row-1), *x=2+29*col, *w=25, *h=18;
if(row == 1 && col == 4) *x=127, *y=37, *w=12, *h=12;
if(row == 1 && col == 5) *x=140, *y=24, *w=12, *h=12;
if(row == 2 && col == 4) *x=140, *y=50, *w=12, *h=12;
if(row == 2 && col == 5) *x=153, *y=37, *w=12, *h=12;
}
#endif
}
static void render_keyboard(keydev_t *d, int x0, int y0)
{
int x=0, y=0, w=0, h=0;
dimage(x0, y0, &img_kbd_released);
for(int row = 0; row < 9; row++)
{
int major = (9-row);
int key_count = (major >= 5) ? 6 : 5;
for(int col = 0; col < key_count; col++)
{
int code = (major << 4) | (col + 1);
if(code == 0x45) code = 0x07;
if(!keydev_keydown(d, code)) continue;
position(row, col, &x, &y, &w, &h);
dsubimage(x0+x, y0+y, &img_kbd_pressed, x,y,w,h, 0);
}
}
}
static void render_option(int x, int y, char const *name, bool enabled)
{
int w, h;
dsize(name, NULL, &w, &h);
if(enabled) drect(x, y, x+w+_(1,2), y+h+_(1,2), C_BLACK);
dtext(x+_(1,2), y+_(1,2), (enabled ? C_WHITE : C_BLACK), name);
}
static void render_icon(int x, int y, int id)
{
int left = _(6,9) * id + _(1, 0);
int top = _(id != 3 && id != 4, 0);
int width = _(5, 9);
int height = _(7 - 2*top, 9);
dsubimage(x, y+top, &img_kbd_events, left,top,width,height, DIMAGE_NONE);
}
static char const *key_name(int key)
{
char const *key_names[] = {
"F1", "F2", "F3", "F4", "F5", "F6",
"SHIFT", "OPTN", "VARS", "MENU", "Left", "Up",
"ALPHA", "x^2", "^", "EXIT", "Down", "Right",
"X,O,T", "log", "ln", "sin", "cos", "tan",
"frac", "F<>D", "(", ")", ",", "->",
"7", "8", "9", "DEL", "AC.ON", "0x46",
"4", "5", "6", "*", "/", "0x47",
"1", "2", "3", "+", "-", "0x48",
"0", ".", "x10^", "(-)", "EXE", "0x49",
};
if(key == 0) return "N/A";
if(key == KEY_ACON) key = 0x45;
int row = 9 - (key >> 4);
int col = (key & 15) - 1;
return key_names[6*row + col];
}
static void render(keydev_t *d, key_event_t *last_events, int counter)
{
key_event_t ev;
dclear(C_WHITE);
#ifdef FXCG50
row_title("Keyboard state visualizer");
int y0=190, dy=14, maxev=12;
int x1=290, x2=350;
#endif
#ifdef FX9860G
row_print(1, 1, "Keyboard state");
dimage(0, 56, &img_opt_gint_keyboard);
int y0=47, dy=7, maxev=6;
int x1=87, x2=117;
font_t const *old_font = dfont(&font_mini);
#endif
for(int i=0, y=y0; i < maxev; i++, y-=dy)
{
ev = last_events[(counter+15 - i) % 16];
if(ev.type == KEYEV_NONE) continue;
int t = ev.type;
render_icon(x1, y+_(0,2), (t==KEYEV_DOWN ? 0 : (t==KEYEV_UP ? 1 : 2)));
dtext(x1 + _(7,11), y + 1, C_BLACK, key_name(ev.key));
if(ev.shift) render_icon(x2, y+_(0,1), 3);
if(ev.alpha) render_icon(x2 + _(5,9), y+_(0,1), 4);
}
render_keyboard(d, _(2,15), _(6,21));
int tr = d->tr.enabled;
#ifdef FX9860G
dtext(35, 10, C_BLACK, "Shift:");
render_option(35, 16, "Del", (tr & KEYDEV_TR_DELAYED_SHIFT) != 0);
render_option(47, 16, "Ins", (tr & KEYDEV_TR_INSTANT_SHIFT) != 0);
dtext(35, 24, C_BLACK, "Alpha:");
render_option(35, 30, "Del", (tr & KEYDEV_TR_DELAYED_ALPHA) != 0);
render_option(47, 30, "Ins", (tr & KEYDEV_TR_INSTANT_ALPHA) != 0);
render_option(35, 38, "-Mods", (tr & KEYDEV_TR_DELETE_MODIFIERS) != 0);
render_option(35, 46, "-Rels", (tr & KEYDEV_TR_DELETE_RELEASES) != 0);
render_option(64, 9, "Reps", (tr & KEYDEV_TR_REPEATS) != 0);
render_icon(54, 9, d->delayed_shift ? 7 : (d->pressed_shift ? 6 : 5));
render_icon(55, 23, d->delayed_alpha ? 7 : (d->pressed_alpha ? 6 : 5));
dtext(65, 17, C_BLACK, key_name(d->rep_key));
dprint(65, 29, C_BLACK, "L:%d", d->events_lost);
dfont(old_font);
#endif /* FX9860G */
#ifdef FXCG50
dtext(210, 30, C_BLACK, "Shift:");
render_option(210, 42, "Del", (tr & KEYDEV_TR_DELAYED_SHIFT) != 0);
render_option(245, 42, "Ins", (tr & KEYDEV_TR_INSTANT_SHIFT) != 0);
dtext(210, 56, C_BLACK, "Alpha:");
render_option(210, 68, "Del", (tr & KEYDEV_TR_DELAYED_ALPHA) != 0);
render_option(245, 68, "Ins", (tr & KEYDEV_TR_INSTANT_ALPHA) != 0);
render_option(210, 82, "-Mods", (tr & KEYDEV_TR_DELETE_MODIFIERS) != 0);
render_option(210, 96, "-Rels", (tr & KEYDEV_TR_DELETE_RELEASES) != 0);
render_option(210, 110, "Reps", (tr & KEYDEV_TR_REPEATS) != 0);
render_icon(252, 30, d->delayed_shift ? 7 : (d->pressed_shift ? 6 : 5));
render_icon(251, 56, d->delayed_alpha ? 7 : (d->pressed_alpha ? 6 : 5));
dtext(210, 124, C_BLACK, key_name(d->rep_key));
dprint(210, 136, C_BLACK, "L:%d", d->events_lost);
#endif /* FXCG50 */
}
static int handle_event(keydev_t *d, key_event_t *last_events, int counter)
{
key_event_t ev = last_events[(counter + 15) % 16];
if(ev.type != KEYEV_DOWN) return 0;
if(ev.key == KEY_EXIT) return 1;
if(ev.key == KEY_MENU)
{
render(d, last_events, counter);
dupdate();
gint_osmenu();
return 0;
}
keydev_transform_t tr = keydev_transform(d);
if(ev.key == KEY_F1) tr.enabled ^= KEYDEV_TR_DELAYED_SHIFT;
if(ev.key == KEY_F2) tr.enabled ^= KEYDEV_TR_INSTANT_SHIFT;
if(ev.key == KEY_F3) tr.enabled ^= KEYDEV_TR_DELAYED_ALPHA;
if(ev.key == KEY_F4) tr.enabled ^= KEYDEV_TR_INSTANT_ALPHA;
if(ev.key == KEY_F5) tr.enabled ^= KEYDEV_TR_REPEATS;
if(ev.key == KEY_F6) tr.enabled ^= KEYDEV_TR_DELETE_MODIFIERS;
keydev_set_transform(d, tr);
return 0;
}
static int repeater(GUNUSED int key, GUNUSED int duration, GUNUSED int count)
{
if(count == 4) return -1;
/* Wait 250 ms until the next repeat */
return 250000;
}
/* gintct_gint_keyboard: Real-time keyboard visualization */
void gintctl_gint_keyboard(void)
{
keydev_t *d = keydev_std();
keydev_transform_t tr = keydev_transform(d);
keydev_transform_t base = { .enabled = 0, .repeater = repeater };
keydev_set_transform(d, base);
/* All initialized with type=KEYEV_NONE */
key_event_t last_events[16] = { 0 };
key_event_t ev;
int counter = 0;
bool loop = true;
while(loop)
{
render(d, last_events, counter);
dupdate();
/* Redraw at each event if needed */
while((ev = keydev_read(d)).type == KEYEV_NONE) sleep();
last_events[counter] = ev;
counter = (counter+1) % 16;
if(handle_event(d, last_events, counter)) break;
while((ev = keydev_read(d)).type != KEYEV_NONE && loop)
{
last_events[counter] = ev;
counter = (counter+1) % 16;
if(handle_event(d, last_events, counter)) loop = false;
}
}
keydev_set_transform(d, tr);
}