Skip to content

Working with the keyboard

This tutorial will guide you through handling keyboard input on your Classpad calculator using C++. Even if you’re new to C development, we’ll take it step by step.

Start with the “Application Template”.

Go to your codespace and open the main.cpp file. Ensure it have the needed imports :

#include <appdef.hpp>
#include <sdk/calc/calc.hpp>
#include <sdk/os/input.hpp>
#include <sdk/os/lcd.hpp>
#include <sdk/os/debug.hpp>

Here, we’ll need:

Add your app’s basic information:

APP_NAME("TouchRectangle")
APP_DESCRIPTION("Move a rectangle based on touch and key input.")
APP_AUTHOR("Your Name")
APP_VERSION("1.0.0")

Add constants for colors, rectangle size, and movement:

#define COLOR_BACKGROUND RGB_TO_RGB565(0, 0, 0)
#define COLOR_RECTANGLE RGB_TO_RGB565(0x1F, 0, 0)
#define RECT_SIZE 20
#define MOVE_STEP 5
extern uint16_t *vram;
int lcdWidth, lcdHeight;
int rectX, rectY;

These constants define:

  • COLOR_BACKGROUND: Black background color
  • COLOR_RECTANGLE: Red rectangle color
  • RECT_SIZE: Size of the rectangle in pixels
  • MOVE_STEP: How many pixels to move with each key press

Create functions to draw the rectangle and update the screen:

void drawRectangle(int x, int y, uint16_t color) {
for (int i = x; i < x + RECT_SIZE; ++i) {
for (int j = y; j < y + RECT_SIZE; ++j) {
if (i >= 0 && i < lcdWidth && j >= 0 && j < lcdHeight) {
vram[i + (j + 24) * lcdWidth] = color;
}
}
}
}
void draw() {
LCD_ClearScreen();
drawRectangle(rectX, rectY, COLOR_RECTANGLE);
LCD_Refresh();
}

The drawRectangle function draws a filled rectangle at position (x, y) with the specified color. The draw function clears the screen, draws the rectangle, and refreshes the display.

Set up the main function with initialization code:

extern "C"
void main() {
LCD_VRAMBackup();
vram = LCD_GetVRAMAddress();
LCD_GetSize(&lcdWidth, &lcdHeight);
rectX = lcdWidth / 2 - RECT_SIZE / 2;
rectY = lcdHeight / 2 - RECT_SIZE / 2;
/* TODO: Add input handling loop here */
LCD_VRAMRestore();
LCD_Refresh();
}

This code:

  • Backs up the current VRAM content
  • Gets the VRAM address and screen dimensions
  • Centers the rectangle on the screen

This loop will:

  • Draws the current state
  • Waits for input events
  • Handles touch events by moving the rectangle to the touch position
  • Handles key events by moving the rectangle with arrow keys
  • Exits when the CLEAR key is pressed
  • Keeps the rectangle within screen boundaries

The app uses GetInput() to wait for events:

  • EVENT_TOUCH: Touch screen events
  • EVENT_KEY: Keyboard events

When the user touches the screen:

  • TOUCH_DOWN: Initial touch
  • TOUCH_HOLD_DRAG: Continued touch with movement

The app responds to these keys:

  • KEYCODE_UP: Move rectangle up
  • KEYCODE_DOWN: Move rectangle down
  • KEYCODE_LEFT: Move rectangle left
  • KEYCODE_RIGHT: Move rectangle right
  • KEYCODE_POWER_CLEAR: Exit the app

Add the main input handling loop:

struct InputEvent event;
bool running = true;
while (running) {
draw();
GetInput(&event, 0xFFFFFFFF, 0x10);
switch (event.type) {
case EVENT_TOUCH:
if (event.data.touch_single.direction == TOUCH_DOWN ||
event.data.touch_single.direction == TOUCH_HOLD_DRAG) {
rectX = event.data.touch_single.p1_x;
rectY = event.data.touch_single.p1_y;
}
break;
case EVENT_KEY:
switch (event.data.key.keyCode) {
case KEYCODE_UP:
rectY -= MOVE_STEP;
break;
case KEYCODE_RIGHT:
rectX += MOVE_STEP;
break;
case KEYCODE_DOWN:
rectY += MOVE_STEP;
break;
case KEYCODE_LEFT:
rectX -= MOVE_STEP;
break;
case KEYCODE_POWER_CLEAR:
running = false;
break;
}
break;
}
// Ensure the rectangle stays within the screen boundaries
if (rectX < 0)
rectX = 0;
if (rectY < 0)
rectY = 0;
if (rectX + RECT_SIZE > lcdWidth)
rectX = lcdWidth - RECT_SIZE;
if (rectY + RECT_SIZE > lcdHeight)
rectY = lcdHeight - RECT_SIZE;
}

Here’s the complete code for your TouchRectangle app:

#include <appdef.hpp>
#include <sdk/calc/calc.hpp>
#include <sdk/os/debug.hpp>
#include <sdk/os/input.hpp>
#include <sdk/os/lcd.hpp>
APP_NAME("TouchRectangle")
APP_DESCRIPTION("Move a rectangle based on touch and key input.")
APP_AUTHOR("Your Name")
APP_VERSION("1.0.0")
#define COLOR_BACKGROUND RGB_TO_RGB565(0, 0, 0)
#define COLOR_RECTANGLE RGB_TO_RGB565(0x1F, 0, 0)
#define RECT_SIZE 20
#define MOVE_STEP 5
extern uint16_t *vram;
int lcdWidth, lcdHeight;
int rectX, rectY;
void drawRectangle(int x, int y, uint16_t color) {
for (int i = x; i < x + RECT_SIZE; ++i) {
for (int j = y; j < y + RECT_SIZE; ++j) {
if (i >= 0 && i < lcdWidth && j >= 0 && j < lcdHeight) {
vram[i + (j + 24) * lcdWidth] = color;
}
}
}
}
void draw() {
LCD_ClearScreen();
drawRectangle(rectX, rectY, COLOR_RECTANGLE);
LCD_Refresh();
}
extern "C"
void main() {
LCD_VRAMBackup();
vram = LCD_GetVRAMAddress();
LCD_GetSize(&lcdWidth, &lcdHeight);
rectX = lcdWidth / 2 - RECT_SIZE / 2;
rectY = lcdHeight / 2 - RECT_SIZE / 2;
struct InputEvent event;
bool running = true;
while (running) {
draw();
GetInput(&event, 0xFFFFFFFF, 0x10);
switch (event.type) {
case EVENT_TOUCH:
if (event.data.touch_single.direction == TOUCH_DOWN ||
event.data.touch_single.direction == TOUCH_HOLD_DRAG) {
rectX = event.data.touch_single.p1_x;
rectY = event.data.touch_single.p1_y;
}
break;
case EVENT_KEY:
switch (event.data.key.keyCode) {
case KEYCODE_UP:
rectY -= MOVE_STEP;
break;
case KEYCODE_RIGHT:
rectX += MOVE_STEP;
break;
case KEYCODE_DOWN:
rectY += MOVE_STEP;
break;
case KEYCODE_LEFT:
rectX -= MOVE_STEP;
break;
case KEYCODE_POWER_CLEAR:
running = false;
break;
}
break;
}
// Ensure the rectangle stays within the screen boundaries
if (rectX < 0)
rectX = 0;
if (rectY < 0)
rectY = 0;
if (rectX + RECT_SIZE > lcdWidth)
rectX = lcdWidth - RECT_SIZE;
if (rectY + RECT_SIZE > lcdHeight)
rectY = lcdHeight - RECT_SIZE;
}
LCD_VRAMRestore();
LCD_Refresh();
}
  1. Save your main.cpp file
  2. Open the terminal and run make bin
  3. Download the generated .bin file
  4. Transfer it to your calculator
  5. Launch it from the Hollyhock-2 Launcher

Congratulations! You’ve created an interactive app that responds to both touch and keyboard input.

Now try:

  • Adding more shapes that respond to different keys
  • Creating a simple game with multiple moving objects
  • Implementing more complex touch gestures
  • Adding visual feedback for different input types