From a5ade3fe81462dd16f973716030cd05bb5bf12f0 Mon Sep 17 00:00:00 2001
From: Nathan James <64075030+Nathanjms@users.noreply.github.com>
Date: Mon, 19 Jan 2026 11:50:34 +0000
Subject: [PATCH] feat: Change keyboard "caps" to "shift" & Wrap Keyboard
(#377)
## Summary
* This PR solves issue
https://github.com/crosspoint-reader/crosspoint-reader/issues/357 in the
first commit
* I then added an additional commit which means when you reach the end
of the keyboard, if you go 'beyond', you wrap back to the other side.
* This replaces existing behaviour, so if you would rather this be
removed, let me know and I'll just do the `caps` -> `shift` change
## Additional Context
### Screenshots for the new shift display
I thought it might not fit and need column size changes, but ended up
fitting fine, see screenshots showing this below:
### Gif showing the wrap-around of the text

---
### AI Usage
Did you use AI tools to help write this code? **PARTIALLY** - used to
double check the text wrapping had no edge-cases. (It did also suggest
rewriting the function, but I decided that was too big of a change for a
working part of the codebase, for now!)
---
src/activities/util/KeyboardEntryActivity.cpp | 40 ++++++++++++-------
1 file changed, 26 insertions(+), 14 deletions(-)
diff --git a/src/activities/util/KeyboardEntryActivity.cpp b/src/activities/util/KeyboardEntryActivity.cpp
index aa4ffc20..8c36ac33 100644
--- a/src/activities/util/KeyboardEntryActivity.cpp
+++ b/src/activities/util/KeyboardEntryActivity.cpp
@@ -73,7 +73,7 @@ int KeyboardEntryActivity::getRowLength(const int row) const {
case 3:
return 10; // zxcvbnm,./
case 4:
- return 10; // caps (2 wide), space (5 wide), backspace (2 wide), OK
+ return 10; // shift (2 wide), space (5 wide), backspace (2 wide), OK
default:
return 0;
}
@@ -145,6 +145,11 @@ void KeyboardEntryActivity::loop() {
// Clamp column to valid range for new row
const int maxCol = getRowLength(selectedRow) - 1;
if (selectedCol > maxCol) selectedCol = maxCol;
+ } else {
+ // Wrap to bottom row
+ selectedRow = NUM_ROWS - 1;
+ const int maxCol = getRowLength(selectedRow) - 1;
+ if (selectedCol > maxCol) selectedCol = maxCol;
}
updateRequired = true;
}
@@ -154,16 +159,24 @@ void KeyboardEntryActivity::loop() {
selectedRow++;
const int maxCol = getRowLength(selectedRow) - 1;
if (selectedCol > maxCol) selectedCol = maxCol;
+ } else {
+ // Wrap to top row
+ selectedRow = 0;
+ const int maxCol = getRowLength(selectedRow) - 1;
+ if (selectedCol > maxCol) selectedCol = maxCol;
}
updateRequired = true;
}
if (mappedInput.wasPressed(MappedInputManager::Button::Left)) {
+ const int maxCol = getRowLength(selectedRow) - 1;
+
// Special bottom row case
if (selectedRow == SPECIAL_ROW) {
// Bottom row has special key widths
if (selectedCol >= SHIFT_COL && selectedCol < SPACE_COL) {
- // In shift key, do nothing
+ // In shift key, wrap to end of row
+ selectedCol = maxCol;
} else if (selectedCol >= SPACE_COL && selectedCol < BACKSPACE_COL) {
// In space bar, move to shift
selectedCol = SHIFT_COL;
@@ -180,10 +193,9 @@ void KeyboardEntryActivity::loop() {
if (selectedCol > 0) {
selectedCol--;
- } else if (selectedRow > 0) {
- // Wrap to previous row
- selectedRow--;
- selectedCol = getRowLength(selectedRow) - 1;
+ } else {
+ // Wrap to end of current row
+ selectedCol = maxCol;
}
updateRequired = true;
}
@@ -204,7 +216,8 @@ void KeyboardEntryActivity::loop() {
// In backspace, move to done
selectedCol = DONE_COL;
} else if (selectedCol >= DONE_COL) {
- // At done button, do nothing
+ // At done button, wrap to beginning of row
+ selectedCol = SHIFT_COL;
}
updateRequired = true;
return;
@@ -212,9 +225,8 @@ void KeyboardEntryActivity::loop() {
if (selectedCol < maxCol) {
selectedCol++;
- } else if (selectedRow < NUM_ROWS - 1) {
- // Wrap to next row
- selectedRow++;
+ } else {
+ // Wrap to beginning of current row
selectedCol = 0;
}
updateRequired = true;
@@ -288,14 +300,14 @@ void KeyboardEntryActivity::render() const {
// Handle bottom row (row 4) specially with proper multi-column keys
if (row == 4) {
- // Bottom row layout: CAPS (2 cols) | SPACE (5 cols) | <- (2 cols) | OK (2 cols)
+ // Bottom row layout: SHIFT (2 cols) | SPACE (5 cols) | <- (2 cols) | OK (2 cols)
// Total: 11 visual columns, but we use logical positions for selection
int currentX = startX;
- // CAPS key (logical col 0, spans 2 key widths)
- const bool capsSelected = (selectedRow == 4 && selectedCol >= SHIFT_COL && selectedCol < SPACE_COL);
- renderItemWithSelector(currentX + 2, rowY, shiftActive ? "CAPS" : "caps", capsSelected);
+ // SHIFT key (logical col 0, spans 2 key widths)
+ const bool shiftSelected = (selectedRow == 4 && selectedCol >= SHIFT_COL && selectedCol < SPACE_COL);
+ renderItemWithSelector(currentX + 2, rowY, shiftActive ? "SHIFT" : "shift", shiftSelected);
currentX += 2 * (keyWidth + keySpacing);
// Space bar (logical cols 2-6, spans 5 key widths)