Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
79 commits
Select commit Hold shift + click to select a range
5c5f434
Rebuild keyboard
IDisposable Apr 8, 2026
ea9090a
Address Cursor and golangci-lint comments
IDisposable Apr 9, 2026
088d4bc
Fix some code review issues
IDisposable Apr 9, 2026
381bd6e
Update docs to reflect revisions
IDisposable Apr 9, 2026
94f78da
Fix docker native build
IDisposable Apr 9, 2026
97fde0d
E2E tests
IDisposable Apr 9, 2026
f7cfe3a
Fixed the Norwegian layout and compact # scancode
IDisposable Apr 11, 2026
9084f17
Fix NumPad Enter/+ wrong shape.
IDisposable Apr 27, 2026
ec52826
Don't add glyphs to pasting character map
IDisposable Apr 27, 2026
c680bc8
Add Quick Actions button text.
IDisposable Apr 27, 2026
9293da6
Remove preview button from keyboard chooser.
IDisposable Apr 27, 2026
1d8ed8f
Fix comment on scancode customization
IDisposable Apr 27, 2026
8214689
Added missing asserts
IDisposable Apr 27, 2026
c8b4c56
Fixed adding-keyboard documentation
IDisposable Apr 27, 2026
d1a50a2
Remove Macro "type on keyboard" and "paste from text"
IDisposable Apr 28, 2026
2ee5b7d
Read and cache only metadata for keyboard list
IDisposable Apr 28, 2026
94d2ab5
Add missing AltGr keys for { [ €
IDisposable Apr 28, 2026
2ac0d6b
Normalize control key legends
IDisposable Apr 28, 2026
682e9f0
Add keyboard audit tool
IDisposable Apr 28, 2026
2427ec9
Harden the keyboard_test against precomposed letters on the keyboard.
IDisposable Apr 28, 2026
0bd53a7
Add missing AltGr key captions.
IDisposable Apr 28, 2026
97e419f
Ignore the built binary
IDisposable Apr 28, 2026
e5104b2
Add Kana support
IDisposable Apr 28, 2026
b5820ec
Fix segmenting issue in PasteModal.
IDisposable Apr 28, 2026
e092647
Preserve the simplest form of a dead-key+space
IDisposable Apr 28, 2026
3fd81f7
Keycap display enhancements
IDisposable Apr 28, 2026
fb892b5
Fix dead-key indicator when it's not the "normal" legend
IDisposable Apr 28, 2026
fa4c8bd
Make the detached keyboard resizeable
IDisposable Apr 28, 2026
3003650
Fix repeated legends on ja-JP keyboard
IDisposable Apr 28, 2026
6f07eb9
Fix borked keyboard tests
IDisposable Apr 28, 2026
773fcc3
Moved audit layouts to scripts and disable linting.
IDisposable Apr 28, 2026
f385ac7
Fix 75% keyboard arrow keys.
IDisposable Apr 29, 2026
d1b297f
Ignore locale_* in localization audit reports.
IDisposable Apr 29, 2026
6e582c7
Add scancode validation to audit_layouts
IDisposable Apr 29, 2026
e645ed1
Correct layout validation issues
IDisposable Apr 29, 2026
ef42372
Review cleanup
IDisposable Apr 30, 2026
704a1a6
Add devcontainer share for GPG signing.
IDisposable Apr 30, 2026
cb36297
Fix latching-mode interacts with physical key press/release
IDisposable Apr 30, 2026
35c5d25
Fix edge case of emtpy layouts
IDisposable Apr 30, 2026
cc1fe59
Fix missing push for hidHashTilde
IDisposable Apr 30, 2026
cf3a41f
Review cleanups
IDisposable Apr 30, 2026
f402ca5
Ignore CMakeCache
IDisposable May 4, 2026
d3dbbb1
Save and restore KVM config around e2e tests
IDisposable May 4, 2026
dfaddde
Fix handling of canonicalized keycap names.
IDisposable May 5, 2026
fc9ee67
Localize modifier in Aria labels
IDisposable May 5, 2026
7f2b45d
Fix paste delay validation error message
IDisposable May 5, 2026
5ad5d3e
Drop import/order rule from oxlint config
IDisposable May 5, 2026
e538dbe
Add paste e2e tests with host-side verification
IDisposable May 5, 2026
ad302da
Run keyboard-paste e2e as its own dependent project
IDisposable May 5, 2026
3453b1c
Quiet template-expression lint warnings on RTC error logs
IDisposable May 5, 2026
4fef544
Add macro execution e2e tests (timing, MACRO_RESET, cancel)
IDisposable May 5, 2026
3a6f022
Add virtual keyboard UI e2e tests (no host required)
IDisposable May 5, 2026
e488cda
Layout management e2e tests
IDisposable May 5, 2026
08e7485
Remove unreachable de-DE fallback in AltGr keyboard-ui test
IDisposable May 5, 2026
4e706b3
fix: remove tracked .gitignore from inlang project
IDisposable May 5, 2026
917a048
Fix possible alias confusions for tab/end
IDisposable May 5, 2026
fe6a111
Map newline / CRLF / tab to scancodes for paste
IDisposable May 5, 2026
91511af
Clean up ScancodeProducesText and simplest dead-key canonicalization
IDisposable May 5, 2026
f9d6a40
ControlLike classification only in go.
IDisposable May 5, 2026
246ebc7
Fix lint issues
IDisposable May 5, 2026
7da9e29
Center long legend in small keys
IDisposable May 5, 2026
89a9a18
Tweak size of single-legend keycaps
IDisposable May 5, 2026
6d7f604
Use known-good keyboard layout for e2e testing.
IDisposable May 5, 2026
e84b803
Cleanup handling of shift/unshift same character
IDisposable May 5, 2026
5350c36
Add ADDING_A_LAYOUT.md — step-by-step contributor walkthrough
IDisposable May 5, 2026
c45eb02
Update keyboard-layout issue template to point at ADDING_A_LAYOUT.md
IDisposable May 5, 2026
f13ccd1
Add keyboard CI workflow — unit tests + kbdlayout.info audit on PRs
IDisposable May 5, 2026
c2ccb05
Migrate tribal knowledge from CLAUDE.md to DEVELOPMENT.md
IDisposable May 5, 2026
6248ddd
Make keyboard CI path filters explicit
IDisposable May 5, 2026
c680942
Audit pass on keyboard docs — fix outdated field names and prune hist…
IDisposable May 5, 2026
ae474f8
Ignore inlang detritus and upgrade packages
IDisposable May 5, 2026
c74d265
Machine translated i18n
IDisposable May 5, 2026
85dc277
Add Docker CLI into devcontainer
IDisposable May 5, 2026
d34fc7a
Moved the keyboard wrapper min-width to the component
IDisposable May 5, 2026
b7c62d4
Fix minimum delay on Paste Modal
IDisposable May 5, 2026
b070ec1
Remove Claude detritus
IDisposable May 5, 2026
7470486
Fix missing .so for playwright e2e
IDisposable May 5, 2026
0c94d2b
Ensure we have a remote agent for e2e tests
IDisposable May 5, 2026
24c1a09
Fix keyaliases defensive alias/canonical test
IDisposable May 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .devcontainer/docker/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
}
},
"mounts": [
"source=${localEnv:HOME}/.ssh,target=/home/vscode/.ssh,type=bind,consistency=cached"
"source=${localEnv:HOME}/.ssh,target=/home/vscode/.ssh,type=bind,consistency=cached",
"source=${localEnv:HOME}/.gnupg,target=/home/vscode/.gnupg,type=bind,consistency=cached"
],
"onCreateCommand": ".devcontainer/install-deps.sh",
"customizations": {
Expand Down
23 changes: 23 additions & 0 deletions .devcontainer/install-deps.sh
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ APT_PACKAGES=(
zstd
python3-venv
python3-kconfiglib
ripgrep
ca-certificates
curl
gnupg
nodejs
npm
)

if [ "${ARCH}" = "amd64" ]; then
Expand All @@ -61,3 +67,20 @@ wget https://github.com/jetkvm/rv1106-system/releases/download/${BUILDKIT_VERSIO
rm buildkit.tar.zst
popd
rm -rf "${BUILDKIT_TMPDIR}"

# Playwright Chromium system libraries (libnspr4, libnss3, libgbm, X11/xcb, etc.)
# Needed for `make test_e2e` / `npx playwright test` to launch the bundled headless shell.
sudo env "PATH=$PATH" npm exec --yes playwright@latest install-deps chromium

# Docker CLI
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian \
trixie stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

sudo apt-get update && \
sudo apt-get install -y docker-ce-cli && \
sudo rm -rf /var/lib/apt/lists/*
3 changes: 2 additions & 1 deletion .devcontainer/podman/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
"HOME": "/home/vscode"
},
"mounts": [
"source=${localEnv:HOME}/.ssh,target=/home/vscode/.ssh,type=bind,consistency=cached"
"source=${localEnv:HOME}/.ssh,target=/home/vscode/.ssh,type=bind,consistency=cached",
"source=${localEnv:HOME}/.gnupg,target=/home/vscode/.gnupg,type=bind,consistency=cached"
],
"onCreateCommand": ".devcontainer/install-deps.sh",
"customizations": {
Expand Down
141 changes: 141 additions & 0 deletions .github/ISSUE_TEMPLATE/keyboard-layout.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
name: Keyboard Layout
type: 'Feature'
description: Submit a new keyboard layout, fix an existing one, or request one we don't ship.
labels:
- 'type: keyboard-layout'
body:
- type: markdown
attributes:
value: |
Thanks for helping us cover more keyboard layouts!

## Are you ready to open a PR?

**If yes**, please follow the step-by-step contributor walkthrough — it covers everything from picking a starting point to validating against `kbdlayout.info`:

👉 **[docs/keyboard/ADDING_A_LAYOUT.md](https://github.com/jetkvm/kvm/blob/dev/docs/keyboard/ADDING_A_LAYOUT.md)**

A PR is the fastest path: you drop a single `.kle.json` into `internal/keyboard/layouts/`, the test suite tells you if anything is off, and we can merge it directly.

**If no** (you don't code Go, you can't run the build, or you're just flagging a bug), keep filling in this issue. The fields below give us enough to do the work for you.

---

## What we need

- The **locale code** and **display name** (always).
- At least one of: a `kbdlayout.info` URL **or** a KLE JSON pasted below.
- Anything you know about **dead keys** on this layout.

- type: input
id: locale
attributes:
label: Locale code
description: |
Use `language-REGION` with a hyphen, e.g. `ko-KR`, `tr-TR`, `pt-BR`, `el-GR`.
Lowercased language, uppercased region.
placeholder: "e.g. ko-KR"
validations:
required: true

- type: input
id: layout-name
attributes:
label: Display name
description: |
What the dropdown will show. Convention: native script + locale code + form factor —
e.g. "한국어 ko-KR (ANSI 103)", "Türkçe tr-TR (ISO 105)", "Português (Brasil) pt-BR (ABNT2)".
placeholder: 'e.g. 한국어 ko-KR (ANSI 103)'
validations:
required: true

- type: dropdown
id: layout-type
attributes:
label: Physical layout type
description: |
ANSI is the flat single-row Enter (US standard).
ISO is the L-shaped Enter (most of Europe).
JIS is the Japanese variant with extra keys around the spacebar.
options:
- ISO 105-key (most European/international keyboards)
- ANSI 104-key (US standard)
- JIS 109-key (Japanese)
- Other (describe in Notes)
validations:
required: true

- type: input
id: kbdlayout-url
attributes:
label: kbdlayout.info URL (preferred)
description: |
If your layout exists at [kbdlayout.info](https://kbdlayout.info/), paste the URL here.
This is the **most reliable** way to give us what we need — the page has the canonical
legends and dead-key behaviour, and our audit script can validate against it directly.
placeholder: "https://kbdlayout.info/00000412/"
validations:
required: false

- type: textarea
id: kle-json
attributes:
label: KLE JSON (alternative if no kbdlayout.info URL)
description: |
If your layout isn't on kbdlayout.info, paste a KLE JSON here. You can:

- Download one from [kbdlayout.info](https://kbdlayout.info/) for the closest match and edit it, or
- Build one on [keyboard-layout-editor.com](https://www.keyboard-layout-editor.com) and copy the **Raw data** tab.

If you can run Go locally, please validate first:

```bash
go run scripts/validate_layout.go path/to/your-layout.kle.json
```
render: json
validations:
required: false

- type: textarea
id: dead-keys
attributes:
label: Dead keys
description: |
A **dead key** is one that doesn't type a character on its own — pressing it puts
the keyboard in a "waiting" state, and the next key combines to produce an accented
character (e.g. on French AZERTY, `^` then `a` produces `â`).

Paste the literal characters that act as dead keys on this layout, separated by
spaces — e.g. `^ ¨ ´ ` ~`. If the layout has no dead keys, write `none`.

**Verify on a real machine running this layout** — some characters look like
accents but type immediately on a given layout.
placeholder: "^ ¨ ´ ` ~ (or 'none')"
validations:
required: true

- type: textarea
id: notes
attributes:
label: Additional notes
description: |
Anything we should know — regional variants, AltGr-layer quirks, keys that
differ from kbdlayout.info, alternative locale codes that should alias to
this layout (e.g. `nl-BE` aliasing to `fr-BE`), unusual physical layouts.
validations:
required: false

- type: checkboxes
attributes:
label: Checklist
options:
- label: The locale code matches `language-REGION` (hyphen, lowercase language, uppercase region).
required: true
- label: I have access to a real machine running this layout (or the kbdlayout.info reference) and have verified the legends.
required: true
- label: The dead-keys list reflects actual dead-key behaviour on the target OS, not just keys that look like accents.
required: true
- label: 'I have read [ADDING_A_LAYOUT.md](https://github.com/jetkvm/kvm/blob/dev/docs/keyboard/ADDING_A_LAYOUT.md) (optional but recommended — many questions are answered there).'
required: false
- label: 'I have run `go run scripts/validate_layout.go` against my KLE JSON (optional, only if you have Go installed).'
required: false
86 changes: 86 additions & 0 deletions .github/workflows/keyboard.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
name: keyboard
# Validates keyboard layouts whenever the parser, the layout files, the
# scripts that reason about them, or the docs that reference them change.
# Skipped on unrelated PRs to keep CI fast.

on:
push:
branches: [dev, main]
paths:
- 'internal/keyboard/layouts/**' # built-in layout files (KLE JSON)
- 'internal/keyboard/testdata/**' # KLE fixtures used by unit tests
- 'internal/keyboard/keyaliases.json' # special-key taxonomy
- 'internal/keyboard/**.go' # parser, validator, tests, helpers
- 'scripts/audit_layouts.go' # the audit tool itself
- 'scripts/validate_layout.go' # the single-file validator
- '.github/workflows/keyboard.yml' # this workflow
pull_request:
paths:
- 'internal/keyboard/layouts/**'
- 'internal/keyboard/testdata/**'
- 'internal/keyboard/keyaliases.json'
- 'internal/keyboard/**.go'
- 'scripts/audit_layouts.go'
- 'scripts/validate_layout.go'
- '.github/workflows/keyboard.yml'

permissions:
contents: read

jobs:
layouts:
name: Layouts (unit tests + kbdlayout.info audit)
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v5

- uses: actions/setup-go@v6
with:
go-version: "^1.25.1"
cache: true

# Cache the kbdlayout.info reference downloads. The audit script
# writes them to whatever --cache points at; persist that across
# runs so we only hit kbdlayout.info on first-time misses.
- name: Restore kbdlayout.info cache
id: kbdcache
uses: actions/cache@v5
with:
path: ~/.cache/kbdlayout-audit
key: kbdlayout-audit-${{ hashFiles('internal/keyboard/layouts/*.kle.json') }}
restore-keys: |
kbdlayout-audit-

- name: Unit tests (parser, charMap, drift guards)
run: go test -v -count=1 ./internal/keyboard/...

# Audit the locally-parsed layouts against the canonical
# kbdlayout.info reference. The script exits 1 only on real
# regressions (charMap entries missing on this side); known
# ISO/ANSI / dead-key differences are emitted as warnings and
# don't fail the job.
- name: Audit against kbdlayout.info
run: |
mkdir -p ~/.cache/kbdlayout-audit
go run ./scripts/audit_layouts.go --cache ~/.cache/kbdlayout-audit | tee audit-output.txt

- name: Summarise audit
if: always()
run: |
{
echo "## Layout audit"
echo
echo '```'
tail -n 25 audit-output.txt 2>/dev/null || echo "(no audit output)"
echo '```'
} >> "$GITHUB_STEP_SUMMARY"

- name: Upload audit log
if: always()
uses: actions/upload-artifact@v4
with:
name: layout-audit
path: audit-output.txt
if-no-files-found: ignore
retention-days: 14
17 changes: 17 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,20 @@ ui/reports

# compiled remote-agent test binary
e2e/remote-agent/remote-agent

# compiled keyboard-layouts test binary
audit-layouts

# build artifacts
build/.cmake/
build/_deps/
build/CMakeFiles/
build/CMakeCache.txt
ui/tsconfig.node.tsbuildinfo

# devcontainer lock file
.devcontainer/docker/devcontainer-lock.json

ui/localization/jetKVM.UI.inlang/cache/
ui/localization/jetKVM.UI.inlang/README.md
ui/localization/jetKVM.UI.inlang/.meta.json
3 changes: 3 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ linters:
- linters:
- forbidigo
path: cmd/main.go
- linters:
- forbidigo
path: scripts/audit_layouts.go
- linters:
- gochecknoinits
path: internal/logging/sse.go
Expand Down
Loading
Loading