DEV Community

Cover image for The Secret to Fast Typing on the Game Boy: Here’s How I Did It!
Liam Clegg
Liam Clegg

Posted on

The Secret to Fast Typing on the Game Boy: Here’s How I Did It!

Repository : https://github.com/cleggacus/gbos
See it working : https://www.youtube.com/shorts/qvXVCzCBPLs

The Quest for Speed: Why Fast Typing Matters!

In the fast-paced world of gaming and technology, efficiency is key. Imagine trying to navigate a complex menu or communicate in a game using a slow, cumbersome typing system. It can be frustrating, especially on a device like the Game Boy, which has a limited number of buttons and a small screen. This is where the quest for speed comes in!

When I set out to create a typing system for the Game Boy, I wanted to address these challenges head-on. Traditional input methods, like QWERTY or ABCD keyboards, are great in theory, but on a non touchscreen handheld console or TV keyboard, they can feel clunky and slow. Typing out messages or navigating menus should be quick and intuitive, allowing people to use the software without being bogged down by the mechanics of input.

Enter T9 predictive text — a system originally designed for nokia phones that allows users to type faster by predicting the words they intend to enter based on a few key presses. By adapting this concept for the Game Boy, I aimed to create a typing experience that was not only faster but also easy to learn. The T9 method offers a way to maximize the limited buttons available, letting users express themselves efficiently without breaking their flow.

From Concept to Code: The Birth of My Game Boy OS

The idea was simple yet revolutionary: instead of relying on a standard keyboard layout, I would create an on-screen keyboard that utilized T9 technology. This meant that each button on the Game Boy would correspond to multiple letters, allowing users to type efficiently with just a few presses. For example, tapping the number ‘5’ — located conveniently in the center of the D-pad—would be the main action button, letting users select words suggested by the predictive text system.

With this concept in mind, I set out to develop the foundation of my Game Boy OS. I decided to use C as my primary programming language, leveraging the Game Boy Development Kit (GBDK 2020) to tap into the console’s hardware capabilities. However, I knew that for certain performance-critical tasks, I would need to incorporate Assembly (ASM) to optimize speed.

To tackle the complexity of predictive text, I opted to generate a trie data structure in Python. This would allow me to efficiently store and retrieve the words in my dictionary while minimizing memory usage. With a target of 10,000 words, I aimed to create a compact yet comprehensive dictionary.

Embracing the Classics: Using a Real Game Boy

One of the most thrilling aspects of this project was the opportunity to work with authentic hardware: a real Game Boy. The tactile experience of typing on the original device, coupled with the nostalgia of classic gaming, added a layer of authenticity that simply can't be replicated with emulators. The Game Boy’s iconic design and sound, along with its limitations, presented unique challenges that enriched my development journey.

To facilitate this project, I utilized the EZ Flash Jr., a flash cartridge designed for the Game Boy and Game Boy Color. This cartridge not only allows for the convenient loading of custom ROMs but also supports save states, making it perfect for development and testing. With the EZ Flash Jr., I could quickly transfer my compiled programs to the Game Boy, experiencing firsthand how my changes affected performance and usability.

Crafting the Brain: Building the Trie in Python

In my quest to enhance typing speed on the Game Boy, I needed a robust structure to manage my dictionary efficiently. Enter the Trie, a tree-like data structure perfect for storing and retrieving keys in a dynamic set. I opted to use Python for its simplicity, enabling rapid prototyping.

The process began by defining a Node class that represents each character in the Trie. Each node contains pointers to its children, a completion flag to mark the end of a word, and a score to prioritize suggestions based on usage frequency.

Here’s a snippet of the key methods from my Node class:

class Node:
    def __init__(self):
        self.complete = False
        self.children = [None] * 26  # For each letter a-z
        self.child_counter = 0
        self.score = 0

    def push(self, val: str, score: int):
        # Logic to add a word to the Trie
Enter fullscreen mode Exit fullscreen mode

Using Google's 10k dictionary as my data source, I iterated through each word, adding it to the Trie while calculating a score based on its position. This scoring mechanism helps prioritize more commonly used words, making the typing experience even smoother.

The culmination of this stage was a serialized version of the Trie, ready to be converted into C code for the Game Boy.

Translating Ideas: Encoding the Trie for Game Boy in C

Once I had my Trie structured and populated with data, the next challenge was translating it into C to fit the memory constraints of the Game Boy. To achieve this, I devised a method to serialize the Trie into a compact binary format that conserves space.

The serialization process transformed each Node into a 32-bit representation, splitting the data into distinct segments: 5 bits for the character, 15 bits for child pointers, 5 bits for child counts, 6 bits for scores, and a single bit for the completion flag. This efficient layout ensured that I could store a wealth of information in a limited space.

Here’s a glimpse of how I structured the serialization:

        val = ((char & 0b11111) << 27) | \
            ((child_ptr & 0b111111111111111) << 12) | \
            ((child_count & 0b11111) << 7) | \
            ((score & 0b111111) << 1) | \
            (complete & 1)

Enter fullscreen mode Exit fullscreen mode

Since this will still require about 24k nodes it cant be stored in a single rom bank. A great way to embrase larger memory requirements on the gameboy is to use memory bank controllers in gbdk. More info here: https://gbdk-2020.github.io/gbdk-2020/docs/api/docs_rombanking_mbcs.html

After successfully generating the C header and source files, I split the data across multiple ROM banks to accommodate the entire 10k dictionary, effectively sidestepping the memory limits of the Game Boy.

Navigating the Path: Traversing the Trie in C

With the Trie encoded in C, the next step was to implement traversal logic that enables real-time predictive text functionality. The traversal involves navigating the Trie based on user input, translating keypresses into the corresponding characters.

The core function utilizes a stack to keep track of the current node and its depth, ensuring efficient exploration of the Trie. By converting user inputs from letters to corresponding number keys (as seen in traditional T9 input), the system can quickly find matching words.

void t9_algorithm(char* val, uint8_t size, T9Results* results) {
    // Logic to find words in the Trie based on input
}
Enter fullscreen mode Exit fullscreen mode

This function not only identifies valid words based on the input sequence but also scores them for relevance, ensuring that the most appropriate suggestions appear first.

Seamless Input: Designing the Keyboard UI and Input System

Now that the backend was functional, it was time to focus on the user interface. Designing the input system for the Game Boy required a balance between accessibility and efficiency. I utilized the built-in background tiles to represent characters visually, allowing users to see their options clearly.

To capture user input, I implemented a system that debounces the buttons, ensuring that multiple buttons are registered at once for diagonals. Here’s a quick overview of the input handling:

// public
uint8_t input_press;
uint8_t input_down;
uint8_t input_up;

// private
uint8_t input_down_buffer;
uint8_t input_prev;
uint8_t input_down_timer = 0;

void update_input(void) {
    input_prev = input_press;
    input_press = joypad();
    input_up = input_prev & ~input_press;

    input_down = 0; // reset down

    // input down without delay
    uint8_t input_down_now = input_press & ~input_prev;

    // handle input down with delay for combos 
    input_down_timer--;

    // add current down to buffer
    if(input_down_now) {
        input_down_timer = INPUT_DOWN_DELAY;
        input_down_buffer |= input_down_now;
    }

    // Commit buffer
    if(input_down_timer == 0) {
        input_down = input_down_buffer;
        input_down_buffer = 0;
    }
}
Enter fullscreen mode Exit fullscreen mode

The Final Word: Conclusions and Future Horizons

Reflecting on this project, I’m proud of the progress made in optimizing typing speed on the Game Boy. The integration of a T9 predictive text system not only enhances user interaction but also opens doors to more complex functionalities. My journey doesn’t end here; I’m currently exploring ways to incorporate internet connectivity into this Game Boy OS, allowing for app integration and dynamic updates.

The knowledge gained through this project is invaluable, and I look forward to sharing more about the ongoing developments. Stay tuned for updates as I push the boundaries of what’s possible on this retro platform!

Repository : https://github.com/cleggacus/gbos
See it working : https://www.youtube.com/shorts/qvXVCzCBPLs

Top comments (0)