gbdk-2020 | GameBoy Development Kit |
| download: https://git.y1.nz/archives/gbdk.tar.gz | |
| README | Files | Log | Refs | LICENSE |
gbdk-lib/examples/megaduck/laptop_keyboard/src/megaduck_keyboard.c
1 #include <gbdk/platform.h>
2 #include <stdint.h>
3 #include <stdbool.h>
4
5 #include <duck/laptop_io.h>
6 #include <duck/laptop_keycodes.h>
7
8 #include "megaduck_key2ascii.h"
9 #include "megaduck_keyboard.h"
10
11
12 #define REPEAT_OFF 0u
13 #define REPEAT_FIRST_THRESHOLD 8u
14 #define REPEAT_CONTINUE_THRESHOLD 4u
15
16 bool key_repeat_allowed = false;
17 uint8_t key_repeat_timeout = REPEAT_OFF;
18 uint8_t key_pressed = NO_KEY;
19 uint8_t key_repeat_previous = NO_KEY;
20 uint8_t key_previous = NO_KEY;
21
22
23 // RX Bytes for Keyboard Serial Reply Packet
24 // - 1st:
25 // - Always 0x04 (Length)
26 // - 2nd:
27 // - KEY REPEAT : |= 0x01 (so far looks like with no key value set in 3rd Byte)
28 // - CAPS_LOCK: |= 0x02
29 // - SHIFT: |= 0x04
30 // - LEFT_PRINTSCREEN: |= 0x08
31 // - 3rd:
32 // - Carries the keyboard key scan code
33 // - 0x00 when no key pressed
34 // - 4th:
35 // - Two's complement checksum byte
36 // - It should be: #4 == (((#1 + #2 + #3) XOR 0xFF) + 1) [two's complement]
37 // - I.E: (#4 + #1 + #2 + #3) == 0x100 -> unsigned overflow -> 0x00
38
39
40 // Request Keyboard data and handle the response
41 //
42 // Returns success or failure (Keyboard struct data not updated if polling failed)
43 bool duck_io_poll_keyboard(duck_keyboard_data_t * key_data) {
44
45 if (duck_io_send_cmd_and_receive_buffer(DUCK_IO_CMD_GET_KEYS)) {
46 if (duck_io_rx_buf_len == DUCK_IO_LEN_KBD_GET) {
47 key_data->flags = duck_io_rx_buf[DUCK_IO_KBD_FLAGS];
48 key_data->scancode = duck_io_rx_buf[DUCK_IO_KBD_KEYCODE];
49 return true;
50 }
51 }
52 return false;
53 }
54
55
56 // Translates key scancodes to ascii
57 // Handles Shift/Caps Lock and Repeat flags
58 //
59 // Returns translated key (if no key pressed, invalid, etc value will be NO_KEY)
60 char duck_io_process_key_data(duck_keyboard_data_t * key_data, uint8_t megaduck_model) {
61
62 key_previous = key_pressed;
63
64 // Optional program layer of key repeat on top of
65 // hardware key repeat (which is too fast, mostly)
66 //
67 // The hardware repeat works like this:
68 // - First packet after key press: Repeat Flag *NOT* set, Scan code matches key
69 // - N+1 packets after key press: Repeat Flag *IS* set, Scan code set to 0x00 (None) remains this way until key released
70 if ((key_data->flags & DUCK_IO_KEY_FLAG_KEY_REPEAT) && (key_repeat_allowed)) {
71
72 // Default to no key repeat
73 key_pressed = NO_KEY;
74
75 if (key_repeat_timeout) {
76 key_repeat_timeout--;
77 } else {
78 // If there is a repeat then send the previous pressed key
79 // and set a small delay until next repeat
80 key_pressed = key_repeat_previous;
81 key_repeat_timeout = REPEAT_CONTINUE_THRESHOLD;
82 }
83 }
84 else {
85 key_data->flags = key_data->flags;
86 uint8_t temp_key_scancode = key_data->scancode;
87
88 // If only shift is enabled, use keycode translation for shift alternate keys (-= 0x80u)
89 if ((key_data->flags & (DUCK_IO_KEY_FLAG_CAPSLOCK | DUCK_IO_KEY_FLAG_SHIFT)) == DUCK_IO_KEY_FLAG_SHIFT)
90 temp_key_scancode -= DUCK_IO_KEY_BASE;
91
92 key_pressed = duck_io_scancode_to_ascii(temp_key_scancode, megaduck_model);
93
94 // If only caps lock is enabled, just translate a-z -> A-Z with no other shift alternates
95 if ((key_data->flags & (DUCK_IO_KEY_FLAG_CAPSLOCK | DUCK_IO_KEY_FLAG_SHIFT)) == DUCK_IO_KEY_FLAG_CAPSLOCK)
96 if ((key_pressed >= 'a') && (key_pressed <= 'z'))
97 key_pressed -= ('a' - 'A');
98
99 // Allow PrintScreen flag to override any other key pressed
100 // (Left printscreen is a flag, Right one is an actual key)
101 if (key_data->flags & DUCK_IO_KEY_FLAG_PRINTSCREEN_LEFT)
102 key_pressed = KEY_PRINTSCREEN;
103
104 // Only allow repeat for the range from:
105 // - ASCII 32 (space) and higher
106 // - As well as arrow keys
107 if ((key_pressed >= ' ') ||
108 ((key_pressed >= KEY_ARROW_UP) && (key_pressed <= KEY_ARROW_LEFT))) {
109 key_repeat_allowed = true;
110 key_repeat_timeout = REPEAT_FIRST_THRESHOLD;
111 } else
112 key_repeat_allowed = false;
113
114 // Save key for repeat
115 key_repeat_previous = key_pressed;
116 }
117
118 return key_pressed;
119 }
This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.