ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_keyboard.c
Go to the documentation of this file.
1
10
11#include "ra8_keyboard.h"
12
13#include <stdint.h>
14
15#include "ra8_attributes.h"
16#include "ra8_check.h"
17#include "ra8_err.h"
18#include "ra8_ui.h"
19
24static const char* s_tag = "KBD";
25
48
49/* Letters layer rows. */
50static const char s_l_r0_lo[] = "qwertyuiop";
51static const char s_l_r0_hi[] = "QWERTYUIOP";
52static const char s_l_r1_lo[] = "asdfghjkl";
53static const char s_l_r1_hi[] = "ASDFGHJKL";
54static const char s_l_r2_lo[] = "zxcvbnm";
55static const char s_l_r2_hi[] = "ZXCVBNM";
56/* Numbers layer rows (no shift effect: upper == lower). */
57static const char s_n_r0[] = "1234567890";
58static const char s_n_r1[] = "-/:;()$&@\"";
59/* Symbols layer rows. Goal: every printable 7-bit ASCII symbol is reachable.
60 * The 32 ASCII symbols are split across the numbers row 1 (10), the shared
61 * punctuation row (5), and these two symbols rows (10 + 7) = 32, no repeats. */
62static const char s_s_r0[] = "[]{}#%^*+=";
63static const char s_s_r1[] = "<>\\_`|~";
64/* Shared third-row punctuation for the numbers + symbols layers. */
65static const char s_punct[] = ".,?!'";
66
101 int32_t x,
102 int32_t w,
103 int32_t y,
104 int32_t h,
105 char lo,
106 char hi,
108 uint8_t aux)
109{
110 if (kb->count >= (uint8_t)k_ra8_kbd_max_keys) {
111 return;
112 }
113 ra8_kbd_key_t* k = &kb->keys[kb->count];
114 k->rect.x = x;
115 k->rect.y = y;
116 k->rect.w = w;
117 k->rect.h = h;
118 k->ch_lower = lo;
119 k->ch_upper = hi;
120 k->kind = kind;
121 k->aux = aux;
122 kb->count++;
123}
124
150RA8_INTERNAL static int32_t internal_hx(const ra8_ui_rect_t* f, int32_t hu)
151{
152 return f->x + ((f->w * hu) / (int32_t)k_kbd_hu_div);
153}
154
190 const char* lo,
191 const char* hi,
192 int32_t n,
193 int32_t hu0,
194 const ra8_ui_rect_t* f,
195 int32_t y,
196 int32_t rh)
197{
198 for (int32_t i = 0; i < n; i++) {
199 const int32_t x0 = internal_hx(f, hu0 + (i * (int32_t)k_kbd_key_hu));
200 const int32_t x1 = internal_hx(f, hu0 + ((i + 1) * (int32_t)k_kbd_key_hu));
201 internal_add(kb,
202 x0,
203 x1 - x0,
204 y,
205 rh,
206 (char)lo[i],
207 (char)((hi != nullptr) ? hi[i] : lo[i]),
209 0U);
210 }
211}
212
245 int32_t a,
246 int32_t b,
247 const ra8_ui_rect_t* f,
248 int32_t y,
249 int32_t rh,
251 uint8_t aux)
252{
253 const int32_t x0 = internal_hx(f, a);
254 internal_add(kb, x0, internal_hx(f, b) - x0, y, rh, 0, 0, kind, aux);
255}
256
293 const ra8_ui_rect_t* f,
294 int32_t y,
295 int32_t rh,
296 uint8_t tog_aux)
297{
298 internal_span(kb, 0, (int32_t)k_kbd_act_hu, f, y, rh, k_ra8_kbd_key_layer, tog_aux);
299 internal_place(kb, s_punct, nullptr, (int32_t)k_kbd_punct_n, (int32_t)k_kbd_punct_hu0, f, y, rh);
300 internal_span(kb,
301 (int32_t)k_kbd_hu_div - (int32_t)k_kbd_act_hu,
302 (int32_t)k_kbd_hu_div,
303 f,
304 y,
305 rh,
307 0U);
308}
309
344 const ra8_ui_rect_t* f,
345 int32_t y,
346 int32_t rh,
347 uint8_t left_aux)
348{
349 internal_span(kb, 0, (int32_t)k_kbd_act_hu, f, y, rh, k_ra8_kbd_key_layer, left_aux);
350 internal_span(kb,
351 (int32_t)k_kbd_act_hu,
352 (int32_t)k_kbd_act_hu + (int32_t)k_kbd_space_hu,
353 f,
354 y,
355 rh,
357 0U);
358 internal_span(kb,
359 (int32_t)k_kbd_hu_div - (int32_t)k_kbd_act_hu,
360 (int32_t)k_kbd_hu_div,
361 f,
362 y,
363 rh,
365 0U);
366}
367
396RA8_INTERNAL static void
398{
399 const int32_t fy = f->y;
400 internal_place(kb, s_l_r0_lo, s_l_r0_hi, (int32_t)k_kbd_top_keys, 0, f, fy, rh);
402 s_l_r1_lo,
403 s_l_r1_hi,
404 (int32_t)k_kbd_mid_keys,
405 (int32_t)k_kbd_inset_hu,
406 f,
407 fy + rh,
408 rh);
409 const int32_t y2 = fy + ((int32_t)k_kbd_row2 * rh);
410 internal_span(kb, 0, (int32_t)k_kbd_wide_hu, f, y2, rh, k_ra8_kbd_key_shift, 0U);
412 s_l_r2_lo,
413 s_l_r2_hi,
414 (int32_t)k_kbd_r2_lett,
415 (int32_t)k_kbd_wide_hu,
416 f,
417 y2,
418 rh);
419 internal_span(kb,
420 (int32_t)k_kbd_hu_div - (int32_t)k_kbd_wide_hu,
421 (int32_t)k_kbd_hu_div,
422 f,
423 y2,
424 rh,
426 0U);
427 internal_row_bottom(kb, f, fy + ((int32_t)k_kbd_row3 * rh), rh, (uint8_t)k_ra8_kbd_layer_numbers);
428}
429
458RA8_INTERNAL static void
460{
461 const int32_t fy = f->y;
462 internal_place(kb, s_n_r0, nullptr, (int32_t)k_kbd_top_keys, 0, f, fy, rh);
463 internal_place(kb, s_n_r1, nullptr, (int32_t)k_kbd_top_keys, 0, f, fy + rh, rh);
464 internal_row_punct(kb, f, fy + ((int32_t)k_kbd_row2 * rh), rh, (uint8_t)k_ra8_kbd_layer_symbols);
465 internal_row_bottom(kb, f, fy + ((int32_t)k_kbd_row3 * rh), rh, (uint8_t)k_ra8_kbd_layer_letters);
466}
467
497RA8_INTERNAL static void
499{
500 const int32_t fy = f->y;
501 internal_place(kb, s_s_r0, nullptr, (int32_t)k_kbd_top_keys, 0, f, fy, rh);
503 s_s_r1,
504 nullptr,
505 (int32_t)k_kbd_sym1_n,
506 (int32_t)k_kbd_sym1_hu0,
507 f,
508 fy + rh,
509 rh);
510 internal_row_punct(kb, f, fy + ((int32_t)k_kbd_row2 * rh), rh, (uint8_t)k_ra8_kbd_layer_numbers);
511 internal_row_bottom(kb, f, fy + ((int32_t)k_kbd_row3 * rh), rh, (uint8_t)k_ra8_kbd_layer_letters);
512}
513
544{
545 kb->count = 0U;
546 const int32_t rh = kb->frame.h / (int32_t)k_ra8_kbd_rows;
547 if (kb->layer == (uint8_t)k_ra8_kbd_layer_numbers) {
548 internal_build_numbers(kb, &kb->frame, rh);
549 } else if (kb->layer == (uint8_t)k_ra8_kbd_layer_symbols) {
550 internal_build_symbols(kb, &kb->frame, rh);
551 } else {
552 internal_build_letters(kb, &kb->frame, rh);
553 }
554}
555
557{
558 RA8_CHECK_NULL_PTR(kb, s_tag, "kb must not be nullptr");
559 RA8_CHECK_NULL_PTR(frame, s_tag, "frame must not be nullptr");
560 /* Decision (MC/DC): reject a frame with no area. */
561 if ((frame->w <= 0) || (frame->h <= 0)) {
563 }
564 kb->frame = *frame;
565 kb->shift = false;
566 kb->layer = (uint8_t)k_ra8_kbd_layer_letters;
568 return k_ra8_ok;
569}
570
571[[nodiscard]] uint8_t ra8_kbd_hit(const ra8_kbd_layout_t* kb, int32_t px, int32_t py)
572{
573 if (kb == nullptr) {
574 return (uint8_t)k_ra8_kbd_no_hit;
575 }
576 for (uint8_t i = 0U; i < kb->count; i++) {
577 if (ra8_ui_rect_contains(&kb->keys[i].rect, px, py)) {
578 return i;
579 }
580 }
581 return (uint8_t)k_ra8_kbd_no_hit;
582}
583
584[[nodiscard]] char ra8_kbd_key_glyph(const ra8_kbd_layout_t* kb, uint8_t key_idx)
585{
586 if ((kb == nullptr) || (key_idx >= kb->count)) {
587 return (char)0;
588 }
589 const ra8_kbd_key_t* k = &kb->keys[key_idx];
590 if (k->kind != k_ra8_kbd_key_char) {
591 return (char)0;
592 }
593 return (char)(kb->shift ? k->ch_upper : k->ch_lower);
594}
595
597{
598 RA8_CHECK_NULL_PTR(t, s_tag, "t must not be nullptr");
599 t->len = 0U;
600 t->buf[0] = '\0';
601 t->committed = false;
602 return k_ra8_ok;
603}
604
633{
634 if (t->len < (uint8_t)((uint8_t)k_ra8_kbd_text_max - 1U)) {
635 t->buf[t->len] = ch;
636 t->len++;
637 t->buf[t->len] = '\0';
638 }
639}
640
641[[nodiscard]] ra8_err_t ra8_kbd_apply(ra8_kbd_text_t* t, ra8_kbd_layout_t* kb, uint8_t key_idx)
642{
643 RA8_CHECK_NULL_PTR(t, s_tag, "t must not be nullptr");
644 RA8_CHECK_NULL_PTR(kb, s_tag, "kb must not be nullptr");
645 if (key_idx >= kb->count) {
646 return k_ra8_ok; /* no-hit sentinel or out of range -> no-op */
647 }
648 const ra8_kbd_key_t* k = &kb->keys[key_idx];
649 switch (k->kind) {
651 internal_append(t, (char)(kb->shift ? k->ch_upper : k->ch_lower));
652 kb->shift = false; /* one-shot SHIFT clears after a character */
653 break;
655 internal_append(t, ' ');
656 kb->shift = false;
657 break;
659 if (t->len > 0U) {
660 t->len--;
661 t->buf[t->len] = '\0';
662 }
663 break;
665 t->committed = true;
666 break;
668 kb->shift = !kb->shift;
669 break;
671 kb->layer = k->aux;
672 kb->shift = false;
673 internal_build_layer(kb); /* re-lay the grid for the new layer */
674 break;
675 default:
676 break;
677 }
678 return k_ra8_ok;
679}
static const char * s_tag
Logging / check tag.
Definition ra8_app.c:17
Annotation-attribute framework macros for ra8-firmware.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
Validation and Error-Checking Macros for ra8-firmware.
#define RA8_CHECK_NULL_PTR(ptr, tag, message)
Reject nullptr pointer, returning k_ra8_err_null_ptr.
Definition ra8_check.h:243
Error Code Definitions for ra8-firmware.
@ k_ra8_err_invalid_arg
Invalid function argument.
Definition ra8_err.h:152
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
uint8_t ra8_kbd_hit(const ra8_kbd_layout_t *kb, int32_t px, int32_t py)
Map a tap to a key index.
static void internal_add(ra8_kbd_layout_t *kb, int32_t x, int32_t w, int32_t y, int32_t h, char lo, char hi, ra8_kbd_key_kind_t kind, uint8_t aux)
Append one key descriptor to the layout, bounded by k_ra8_kbd_max_keys.
ra8_err_t ra8_kbd_text_init(ra8_kbd_text_t *t)
Reset a text buffer to empty / uncommitted.
static void internal_build_numbers(ra8_kbd_layout_t *kb, const ra8_ui_rect_t *f, int32_t rh)
Build the numbers layer (digits, common symbols; #+= toggles to symbols).
static const char s_n_r0[]
static void internal_build_symbols(ra8_kbd_layout_t *kb, const ra8_ui_rect_t *f, int32_t rh)
Build the symbols layer (brackets, math operators; 123 toggles to numbers).
ra8_err_t ra8_kbd_apply(ra8_kbd_text_t *t, ra8_kbd_layout_t *kb, uint8_t key_idx)
Apply key key_idx to the text buffer, SHIFT, and active layer.
static const char s_l_r2_lo[]
static const char s_l_r2_hi[]
static void internal_build_letters(ra8_kbd_layout_t *kb, const ra8_ui_rect_t *f, int32_t rh)
Build the letters layer (QWERTY / SHIFT / 123 bottom-row toggle).
static void internal_place(ra8_kbd_layout_t *kb, const char *lo, const char *hi, int32_t n, int32_t hu0, const ra8_ui_rect_t *f, int32_t y, int32_t rh)
Place n character keys, each k_kbd_key_hu (2) half-units wide, starting from half-unit offset hu0.
static const char s_s_r0[]
static void internal_row_bottom(ra8_kbd_layout_t *kb, const ra8_ui_rect_t *f, int32_t y, int32_t rh, uint8_t left_aux)
Build the bottom row: a layer-toggle key, SPACE, and RETURN.
static const char s_l_r0_hi[]
static const char s_l_r1_lo[]
kbd_geom_t
Row geometry in 20ths of the width ("half-units"), iOS proportions.
@ k_kbd_top_keys
Keys in rows 0 and 1.
@ k_kbd_wide_hu
SHIFT / BACKSPACE width.
@ k_kbd_hu_div
Half-units per row (a normal key = 2 hu).
@ k_kbd_row2
Row index 2.
@ k_kbd_row1
Row index 1.
@ k_kbd_inset_hu
Home-row inset each side.
@ k_kbd_sym1_n
Symbols row 1 keys (_ \ | ~ < > `).
@ k_kbd_punct_hu0
Centred start for the 5 punctuation keys.
@ k_kbd_space_hu
SPACE width.
@ k_kbd_punct_n
Punctuation keys (.
@ k_kbd_act_hu
123 / ABC / RETURN width.
@ k_kbd_key_hu
Normal key width (half-units).
@ k_kbd_mid_keys
Keys in the inset home row.
@ k_kbd_sym1_hu0
Centred start for symbols row 1.
@ k_kbd_r2_lett
Letters in letters row 2.
@ k_kbd_row3
Row index 3.
static void internal_row_punct(ra8_kbd_layout_t *kb, const ra8_ui_rect_t *f, int32_t y, int32_t rh, uint8_t tog_aux)
Build row 2 for the numbers or symbols layer: layer-toggle, punctuation, backspace.
static void internal_append(ra8_kbd_text_t *t, char ch)
Append character ch to the text buffer if capacity allows.
ra8_err_t ra8_kbd_layout_init(ra8_kbd_layout_t *kb, const ra8_ui_rect_t *frame)
Lay the letters layer into frame; clear SHIFT.
static void internal_build_layer(ra8_kbd_layout_t *kb)
Rebuild the key grid for the active layer stored in kb->layer.
static int32_t internal_hx(const ra8_ui_rect_t *f, int32_t hu)
Compute the pixel X coordinate for a given half-unit offset within a frame.
static const char s_punct[]
char ra8_kbd_key_glyph(const ra8_kbd_layout_t *kb, uint8_t key_idx)
Effective character a char key emits given the live SHIFT state.
static const char s_l_r1_hi[]
static const char s_l_r0_lo[]
static const char s_s_r1[]
static const char s_n_r1[]
static void internal_span(ra8_kbd_layout_t *kb, int32_t a, int32_t b, const ra8_ui_rect_t *f, int32_t y, int32_t rh, ra8_kbd_key_kind_t kind, uint8_t aux)
Append one special key that spans half-units [a, b).
On-screen keyboard widget – iOS-style layers, shift, hit-test.
ra8_kbd_key_kind_t
What a key does when tapped.
@ k_ra8_kbd_key_space
Append a space.
@ k_ra8_kbd_key_layer
Switch to the layer in aux.
@ k_ra8_kbd_key_enter
Commit the query (RETURN).
@ k_ra8_kbd_key_char
Append the shift-correct char.
@ k_ra8_kbd_key_shift
Toggle the one-shot SHIFT.
@ k_ra8_kbd_key_backspace
Delete the last char.
@ k_ra8_kbd_layer_symbols
Brackets / math symbols (#+=).
@ k_ra8_kbd_layer_letters
QWERTY letters (with one-shot SHIFT).
@ k_ra8_kbd_layer_numbers
Digits + common symbols (123).
@ k_ra8_kbd_rows
Key rows per layer.
@ k_ra8_kbd_max_keys
Key-rect slots (<= 31 used per layer).
@ k_ra8_kbd_no_hit
ra8_kbd_hit "no key" sentinel.
@ k_ra8_kbd_text_max
Text buffer capacity incl.
Bounded UI interaction core: hit-testing, screen stack, paging.
bool ra8_ui_rect_contains(const ra8_ui_rect_t *r, int32_t px, int32_t py)
Test whether a point lies inside a rectangle.
Definition ra8_ui.c:34
One key: a hit rectangle, its unshifted + shifted chars, a kind, and (for layer keys) the target laye...
uint8_t aux
Target ra8_kbd_layer_t for a layer key.
char ch_lower
Unshifted char (char keys); 0 else.
ra8_kbd_key_kind_t kind
Key behaviour.
ra8_ui_rect_t rect
Hit / draw rectangle.
char ch_upper
Shifted char (char keys); 0 else.
The key grid for the active layer, plus SHIFT / layer / frame state.
ra8_kbd_key_t keys[k_ra8_kbd_max_keys]
Keys for the active layer.
uint8_t count
Keys in use.
uint8_t layer
Active ra8_kbd_layer_t.
bool shift
One-shot SHIFT armed.
ra8_ui_rect_t frame
Saved frame (re-lay on swap).
The typed query buffer + commit state.
char buf[k_ra8_kbd_text_max]
NUL-terminated query.
uint8_t len
Chars before the NUL.
bool committed
RETURN was applied.
Axis-aligned rectangle in framebuffer pixel coordinates.
Definition ra8_ui.h:72
int32_t w
Width (pixels, >= 0).
Definition ra8_ui.h:75
int32_t h
Height (pixels, >= 0).
Definition ra8_ui.h:76
int32_t x
Left edge (pixels).
Definition ra8_ui.h:73
int32_t y
Top edge (pixels).
Definition ra8_ui.h:74