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:

<img width="573" height="366" alt="image"
src="https://github.com/user-attachments/assets/b8f6a4ec-94f5-4f5e-b9a6-06cc5f250ddb"
/>

<img width="570" height="308" alt="image"
src="https://github.com/user-attachments/assets/7d775518-4784-4120-a20a-a9dc67af8565"
/>


### Gif showing the wrap-around of the text



![IMG_7648](https://github.com/user-attachments/assets/7eec9066-e1cc-49a1-8b6b-a61556038d31)

---

### 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!)
This commit is contained in:
Nathan James
2026-01-19 11:50:34 +00:00
committed by GitHub
parent 12940cc546
commit 7185e5d287

View File

@@ -73,7 +73,7 @@ int KeyboardEntryActivity::getRowLength(const int row) const {
case 3: case 3:
return 10; // zxcvbnm,./ return 10; // zxcvbnm,./
case 4: 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: default:
return 0; return 0;
} }
@@ -145,6 +145,11 @@ void KeyboardEntryActivity::loop() {
// Clamp column to valid range for new row // Clamp column to valid range for new row
const int maxCol = getRowLength(selectedRow) - 1; const int maxCol = getRowLength(selectedRow) - 1;
if (selectedCol > maxCol) selectedCol = maxCol; 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; updateRequired = true;
} }
@@ -154,16 +159,24 @@ void KeyboardEntryActivity::loop() {
selectedRow++; selectedRow++;
const int maxCol = getRowLength(selectedRow) - 1; const int maxCol = getRowLength(selectedRow) - 1;
if (selectedCol > maxCol) selectedCol = maxCol; 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; updateRequired = true;
} }
if (mappedInput.wasPressed(MappedInputManager::Button::Left)) { if (mappedInput.wasPressed(MappedInputManager::Button::Left)) {
const int maxCol = getRowLength(selectedRow) - 1;
// Special bottom row case // Special bottom row case
if (selectedRow == SPECIAL_ROW) { if (selectedRow == SPECIAL_ROW) {
// Bottom row has special key widths // Bottom row has special key widths
if (selectedCol >= SHIFT_COL && selectedCol < SPACE_COL) { 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) { } else if (selectedCol >= SPACE_COL && selectedCol < BACKSPACE_COL) {
// In space bar, move to shift // In space bar, move to shift
selectedCol = SHIFT_COL; selectedCol = SHIFT_COL;
@@ -180,10 +193,9 @@ void KeyboardEntryActivity::loop() {
if (selectedCol > 0) { if (selectedCol > 0) {
selectedCol--; selectedCol--;
} else if (selectedRow > 0) { } else {
// Wrap to previous row // Wrap to end of current row
selectedRow--; selectedCol = maxCol;
selectedCol = getRowLength(selectedRow) - 1;
} }
updateRequired = true; updateRequired = true;
} }
@@ -204,7 +216,8 @@ void KeyboardEntryActivity::loop() {
// In backspace, move to done // In backspace, move to done
selectedCol = DONE_COL; selectedCol = DONE_COL;
} else if (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; updateRequired = true;
return; return;
@@ -212,9 +225,8 @@ void KeyboardEntryActivity::loop() {
if (selectedCol < maxCol) { if (selectedCol < maxCol) {
selectedCol++; selectedCol++;
} else if (selectedRow < NUM_ROWS - 1) { } else {
// Wrap to next row // Wrap to beginning of current row
selectedRow++;
selectedCol = 0; selectedCol = 0;
} }
updateRequired = true; updateRequired = true;
@@ -288,14 +300,14 @@ void KeyboardEntryActivity::render() const {
// Handle bottom row (row 4) specially with proper multi-column keys // Handle bottom row (row 4) specially with proper multi-column keys
if (row == 4) { 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 // Total: 11 visual columns, but we use logical positions for selection
int currentX = startX; int currentX = startX;
// CAPS key (logical col 0, spans 2 key widths) // SHIFT key (logical col 0, spans 2 key widths)
const bool capsSelected = (selectedRow == 4 && selectedCol >= SHIFT_COL && selectedCol < SPACE_COL); const bool shiftSelected = (selectedRow == 4 && selectedCol >= SHIFT_COL && selectedCol < SPACE_COL);
renderItemWithSelector(currentX + 2, rowY, shiftActive ? "CAPS" : "caps", capsSelected); renderItemWithSelector(currentX + 2, rowY, shiftActive ? "SHIFT" : "shift", shiftSelected);
currentX += 2 * (keyWidth + keySpacing); currentX += 2 * (keyWidth + keySpacing);
// Space bar (logical cols 2-6, spans 5 key widths) // Space bar (logical cols 2-6, spans 5 key widths)