feat(binarykeyboard): show fixed QWERTY layout with shaded halves
This commit is contained in:
@@ -2,8 +2,10 @@
|
||||
|
||||
Proof of concept for entering text by recursively bisecting a QWERTY-ordered character set.
|
||||
|
||||
- Left side button selects the left group.
|
||||
- Right side button selects the right group.
|
||||
The full QWERTY layout stays in fixed positions. Remaining candidates are shaded by group; eliminated keys disappear.
|
||||
|
||||
- Up selects the plain (white) group.
|
||||
- Down selects the shaded (dark) group.
|
||||
- Back undoes one choice, or exits from the root.
|
||||
- Confirm inserts a space.
|
||||
- Left front button deletes a character.
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
-- DESCRIPTION: Two-button recursive keyboard experiment
|
||||
|
||||
local KEYS = {
|
||||
"Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P",
|
||||
"A", "S", "D", "F", "G", "H", "J", "K", "L",
|
||||
"Z", "X", "C", "V", "B", "N", "M"
|
||||
local ROWS = {
|
||||
{ "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P" },
|
||||
{ "A", "S", "D", "F", "G", "H", "J", "K", "L" },
|
||||
{ "Z", "X", "C", "V", "B", "N", "M" }
|
||||
}
|
||||
|
||||
local KEYS = {}
|
||||
for _, row in ipairs(ROWS) do
|
||||
for _, key in ipairs(row) do KEYS[#KEYS + 1] = key end
|
||||
end
|
||||
local MAX_TEXT_BYTES = 80
|
||||
|
||||
local text = ""
|
||||
@@ -57,21 +62,47 @@ local function undo()
|
||||
needsDraw = true
|
||||
end
|
||||
|
||||
local function drawPanel(x, y, width, height, title, values)
|
||||
gui.drawRoundedRect(x, y, width, height, 2, 8, COLOR_BLACK)
|
||||
gui.drawText(FONT_UI_10, x + 12, y + 32, title, COLOR_BLACK, STYLE_BOLD)
|
||||
gui.drawText(FONT_UI_12, x + 12, y + math.floor(height / 2), table.concat(values), COLOR_BLACK, STYLE_NORMAL)
|
||||
-- Side Lookup - Rendering needs per-key shading, but candidates are stored in layout order.
|
||||
local function sides()
|
||||
local leftHalf, rightHalf = halves()
|
||||
local result = {}
|
||||
for _, key in ipairs(leftHalf) do result[key] = "left" end
|
||||
for _, key in ipairs(rightHalf) do result[key] = "right" end
|
||||
return result
|
||||
end
|
||||
|
||||
local function drawKeyboard(width, top, bottom)
|
||||
local gap = 6
|
||||
local margin = 16
|
||||
local keyWidth = math.floor((width - margin * 2 - gap * 9) / 10)
|
||||
local keyHeight = math.min(56, math.floor((bottom - top - gap * 2) / 3))
|
||||
local side = sides()
|
||||
|
||||
for rowIndex, row in ipairs(ROWS) do
|
||||
local rowWidth = #row * keyWidth + (#row - 1) * gap
|
||||
local startX = math.floor((width - rowWidth) / 2)
|
||||
local y = top + (rowIndex - 1) * (keyHeight + gap)
|
||||
|
||||
for columnIndex, key in ipairs(row) do
|
||||
local keySide = side[key]
|
||||
if keySide then
|
||||
local x = startX + (columnIndex - 1) * (keyWidth + gap)
|
||||
local shaded = keySide == "right"
|
||||
gui.fillRoundedRect(x, y, keyWidth, keyHeight, 4, shaded and COLOR_DARK_GRAY or COLOR_WHITE)
|
||||
gui.drawRoundedRect(x, y, keyWidth, keyHeight, 1, 4, COLOR_BLACK)
|
||||
local label = uppercase and key or key:lower()
|
||||
local textX = x + math.floor((keyWidth - gui.getTextWidth(FONT_NOTOSANS_16, label, STYLE_BOLD)) / 2)
|
||||
gui.drawText(FONT_NOTOSANS_16, textX, y + math.floor(keyHeight / 2) - 10, label,
|
||||
shaded and COLOR_WHITE or COLOR_BLACK, STYLE_BOLD)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function render()
|
||||
local width = gui.width()
|
||||
local height = gui.height()
|
||||
local margin = 20
|
||||
local gap = 12
|
||||
local panelWidth = math.floor((width - margin * 2 - gap) / 2)
|
||||
local panelTop = 185
|
||||
local panelHeight = math.min(220, height - panelTop - 100)
|
||||
local leftHalf, rightHalf = halves()
|
||||
|
||||
gui.clear()
|
||||
gui.drawCenteredText(FONT_UI_12, 24, "Binary Keyboard", COLOR_BLACK, STYLE_BOLD)
|
||||
@@ -79,10 +110,8 @@ local function render()
|
||||
local visibleText = text == "" and "Type with the side buttons" or text:sub(-38)
|
||||
gui.drawText(FONT_UI_12, margin + 12, 96, visibleText, COLOR_BLACK, STYLE_NORMAL)
|
||||
|
||||
local progress = string.rep("•", #history)
|
||||
gui.drawCenteredText(FONT_UI_10, 155, progress == "" and "Choose a half" or progress, COLOR_BLACK, STYLE_NORMAL)
|
||||
drawPanel(margin, panelTop, panelWidth, panelHeight, "LEFT SIDE", leftHalf)
|
||||
drawPanel(margin + panelWidth + gap, panelTop, panelWidth, panelHeight, "RIGHT SIDE", rightHalf)
|
||||
gui.drawCenteredText(FONT_UI_10, 170, "UP = plain DOWN = shaded", COLOR_BLACK, STYLE_NORMAL)
|
||||
drawKeyboard(width, 195, height - 90)
|
||||
|
||||
gui.drawButtonHints(#history == 0 and "Exit" or "Undo", "Space", "Delete", uppercase and "lower" or "UPPER")
|
||||
gui.refresh(firstDraw and REFRESH_HALF or REFRESH_FAST)
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
XTEINK-MANIFEST|1
|
||||
main.lua|3720|8e275a05358e32b0187a7e2c00a93eabe658a32c10112c5451e2d8a78f3d3932
|
||||
main.lua|4726|1a958ed089a1c3b6c8757298a94aed32fb2603732d83d3ed6c3ea98f31bd816a
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
XTEINK-CATALOG|1
|
||||
AppStore|Install apps from public Xteink repositories|apps/AppStore/manifest.txt|192|2eb608b92de6bdeff4fc8ed447b9319f45c0d79d5d73b14db1ab5a92f91e42d4
|
||||
BinaryKeyboard|Two-button recursive keyboard experiment|apps/BinaryKeyboard/manifest.txt|97|b72b6250bb3124fb1639c9c1eb0c1b7730d62356189f450e26035dde288f9f2b
|
||||
BinaryKeyboard|Two-button recursive keyboard experiment|apps/BinaryKeyboard/manifest.txt|97|8d26b7d2057f7ebdca133b936ea5d2074e8771af5235e9bf9722689a6fd8f5fd
|
||||
HomeAssistant|Home Assistant status cards|apps/HomeAssistant/manifest.txt|177|b38ca49804444fd383a505ce9c51680ad9b7443950d682ca1b9ef3047bff98a5
|
||||
Wordle|Guess the five-letter word in six tries|apps/Wordle/manifest.txt|177|199fafdf0d0f6e77916befc011f6e8466c254867800e1d4a9e67e95a06d0366b
|
||||
|
||||
Reference in New Issue
Block a user