git.y1.nz

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.