From 99727e132c3237aba2fc51825edc3decbe470519 Mon Sep 17 00:00:00 2001 From: Matt Hill Date: Tue, 20 Jan 2026 14:24:45 -0700 Subject: [PATCH] keyboard keymap also --- .../src/app/pages/keyboard.page.ts | 7 ++- web/projects/shared/src/util/keyboards.ts | 57 +++++++++++-------- .../routes/general/general.component.ts | 34 +++++------ .../general/keyboard-select.component.ts | 14 ++--- .../services/api/embassy-mock-api.service.ts | 7 +-- .../ui/src/app/services/api/mock-patch.ts | 1 + 6 files changed, 63 insertions(+), 57 deletions(-) diff --git a/web/projects/setup-wizard/src/app/pages/keyboard.page.ts b/web/projects/setup-wizard/src/app/pages/keyboard.page.ts index ce343d7a6..fbd4e5c11 100644 --- a/web/projects/setup-wizard/src/app/pages/keyboard.page.ts +++ b/web/projects/setup-wizard/src/app/pages/keyboard.page.ts @@ -82,7 +82,7 @@ export default class KeyboardPage { this.stateService.language as LanguageCode, ) selected = - this.keyboards.find(k => k.code === this.stateService.keyboard) || + this.keyboards.find(k => k.layout === this.stateService.keyboard) || this.keyboards[0]! readonly saving = signal(false) @@ -95,13 +95,14 @@ export default class KeyboardPage { try { // Send keyboard to backend await this.api.setKeyboard({ - layout: this.selected.code, + layout: this.selected.layout, + keymap: this.selected.keymap, model: null, variant: null, options: [], }) - this.stateService.keyboard = this.selected.code + this.stateService.keyboard = this.selected.layout await this.navigateToNextStep() } finally { this.saving.set(false) diff --git a/web/projects/shared/src/util/keyboards.ts b/web/projects/shared/src/util/keyboards.ts index f281267c7..de8688564 100644 --- a/web/projects/shared/src/util/keyboards.ts +++ b/web/projects/shared/src/util/keyboards.ts @@ -1,9 +1,14 @@ import { LanguageCode } from './languages' /** - * Keyboard layout codes + * Keyboard layout codes (X11/Wayland) */ -export type KeyboardCode = 'us' | 'gb' | 'es' | 'latam' | 'de' | 'fr' | 'pl' +export type KeyboardLayout = 'us' | 'gb' | 'es' | 'latam' | 'de' | 'fr' | 'pl' + +/** + * Keyboard keymap codes (console/TTY) + */ +export type KeyboardKeymap = 'us' | 'uk' | 'es' | 'la' | 'de' | 'fr' | 'pl' /** * Keyboard layout display names @@ -18,10 +23,11 @@ export type KeyboardName = | 'Polish' /** - * Keyboard layout definition + * Keyboard definition with layout and keymap */ export interface Keyboard { - code: KeyboardCode + layout: KeyboardLayout + keymap: KeyboardKeymap name: KeyboardName } @@ -29,7 +35,8 @@ export interface Keyboard { * Full keyboard configuration for backend API */ export interface FullKeyboard { - layout: string + layout: KeyboardLayout + keymap: KeyboardKeymap model: string | null variant: string | null options: string[] @@ -40,29 +47,29 @@ export interface FullKeyboard { */ export const KEYBOARDS_BY_LANGUAGE: Record = { en: [ - { code: 'us', name: 'US English' }, - { code: 'gb', name: 'UK English' }, + { layout: 'us', keymap: 'us', name: 'US English' }, + { layout: 'gb', keymap: 'uk', name: 'UK English' }, ], es: [ - { code: 'es', name: 'Spanish' }, - { code: 'latam', name: 'Latin American' }, + { layout: 'es', keymap: 'es', name: 'Spanish' }, + { layout: 'latam', keymap: 'la', name: 'Latin American' }, ], - de: [{ code: 'de', name: 'German' }], - fr: [{ code: 'fr', name: 'French' }], - pl: [{ code: 'pl', name: 'Polish' }], + de: [{ layout: 'de', keymap: 'de', name: 'German' }], + fr: [{ layout: 'fr', keymap: 'fr', name: 'French' }], + pl: [{ layout: 'pl', keymap: 'pl', name: 'Polish' }], } /** * All available keyboard layouts */ export const ALL_KEYBOARDS: Keyboard[] = [ - { code: 'us', name: 'US English' }, - { code: 'gb', name: 'UK English' }, - { code: 'es', name: 'Spanish' }, - { code: 'latam', name: 'Latin American' }, - { code: 'de', name: 'German' }, - { code: 'fr', name: 'French' }, - { code: 'pl', name: 'Polish' }, + { layout: 'us', keymap: 'us', name: 'US English' }, + { layout: 'gb', keymap: 'uk', name: 'UK English' }, + { layout: 'es', keymap: 'es', name: 'Spanish' }, + { layout: 'latam', keymap: 'la', name: 'Latin American' }, + { layout: 'de', keymap: 'de', name: 'German' }, + { layout: 'fr', keymap: 'fr', name: 'French' }, + { layout: 'pl', keymap: 'pl', name: 'Polish' }, ] /** @@ -71,20 +78,20 @@ export const ALL_KEYBOARDS: Keyboard[] = [ */ export function getAllKeyboardsSorted(languageCode: LanguageCode): Keyboard[] { const languageKeyboards = KEYBOARDS_BY_LANGUAGE[languageCode] - const languageKeyboardCodes = new Set(languageKeyboards.map(kb => kb.code)) + const languageLayouts = new Set(languageKeyboards.map(kb => kb.layout)) const otherKeyboards = ALL_KEYBOARDS.filter( - kb => !languageKeyboardCodes.has(kb.code), + kb => !languageLayouts.has(kb.layout), ).sort((a, b) => a.name.localeCompare(b.name)) return [...languageKeyboards, ...otherKeyboards] } /** - * Get the display name for a keyboard code. + * Get the display name for a keyboard layout. */ export function getKeyboardName( - code: KeyboardCode | string, + layout: KeyboardLayout | string, ): KeyboardName | string { - const keyboard = ALL_KEYBOARDS.find(kb => kb.code === code) + const keyboard = ALL_KEYBOARDS.find(kb => kb.layout === layout) if (keyboard) return keyboard.name - return code // fallback to the code itself if not found + return layout // fallback to the layout itself if not found } diff --git a/web/projects/ui/src/app/routes/portal/routes/system/routes/general/general.component.ts b/web/projects/ui/src/app/routes/portal/routes/system/routes/general/general.component.ts index 3adf6fc83..aaff817d0 100644 --- a/web/projects/ui/src/app/routes/portal/routes/system/routes/general/general.component.ts +++ b/web/projects/ui/src/app/routes/portal/routes/system/routes/general/general.component.ts @@ -18,7 +18,7 @@ import { i18nPipe, i18nService, Keyboard, - KeyboardCode, + KeyboardLayout, Language, LANGUAGES, LANGUAGE_TO_CODE, @@ -317,29 +317,30 @@ export default class SystemGeneralComponent { if (!server) return const keyboards = getAllKeyboardsSorted(LANGUAGE_TO_CODE[server.language]) - const currentKeyboard = (server.keyboard?.layout as KeyboardCode) || null + const currentLayout = (server.keyboard?.layout as KeyboardLayout) || null this.dialog - .openComponent( + .openComponent( new PolymorpheusComponent(KeyboardSelectComponent, this.injector), { label: 'Select Keyboard Layout', size: 's', - data: { keyboards, currentKeyboard }, + data: { keyboards, currentLayout }, }, ) - .pipe(filter((code): code is KeyboardCode => code !== null)) - .subscribe(keyboardCode => { - this.saveKeyboard(keyboardCode) + .pipe(filter((keyboard): keyboard is Keyboard => keyboard !== null)) + .subscribe(keyboard => { + this.saveKeyboard(keyboard) }) } - private async saveKeyboard(keyboardCode: KeyboardCode) { + private async saveKeyboard(keyboard: Keyboard) { const loader = this.loader.open('Saving').subscribe() try { await this.api.setKeyboard({ - layout: keyboardCode, + layout: keyboard.layout, + keymap: keyboard.keymap, model: null, variant: null, options: [], @@ -457,17 +458,17 @@ export default class SystemGeneralComponent { private promptKeyboardSelection(keyboards: Keyboard[]) { this.dialog - .openComponent( + .openComponent( new PolymorpheusComponent(KeyboardSelectComponent, this.injector), { label: 'Select Keyboard Layout', size: 's', - data: { keyboards, currentKeyboard: null }, + data: { keyboards, currentLayout: null }, }, ) - .pipe(filter((code): code is KeyboardCode => code !== null)) - .subscribe(keyboardCode => { - this.enableKioskWithKeyboard(keyboardCode) + .pipe(filter((keyboard): keyboard is Keyboard => keyboard !== null)) + .subscribe(keyboard => { + this.enableKioskWithKeyboard(keyboard) }) } @@ -484,12 +485,13 @@ export default class SystemGeneralComponent { } } - private async enableKioskWithKeyboard(keyboardCode: KeyboardCode) { + private async enableKioskWithKeyboard(keyboard: Keyboard) { const loader = this.loader.open('Enabling').subscribe() try { await this.api.setKeyboard({ - layout: keyboardCode, + layout: keyboard.layout, + keymap: keyboard.keymap, model: null, variant: null, options: [], diff --git a/web/projects/ui/src/app/routes/portal/routes/system/routes/general/keyboard-select.component.ts b/web/projects/ui/src/app/routes/portal/routes/system/routes/general/keyboard-select.component.ts index 5808d825b..b74c99576 100644 --- a/web/projects/ui/src/app/routes/portal/routes/system/routes/general/keyboard-select.component.ts +++ b/web/projects/ui/src/app/routes/portal/routes/system/routes/general/keyboard-select.component.ts @@ -1,6 +1,6 @@ import { Component, inject } from '@angular/core' import { FormsModule } from '@angular/forms' -import { i18nPipe, Keyboard, KeyboardCode } from '@start9labs/shared' +import { i18nPipe, Keyboard, KeyboardLayout } from '@start9labs/shared' import { TUI_IS_MOBILE } from '@taiga-ui/cdk' import { TuiButton, TuiDialogContext, TuiTextfield } from '@taiga-ui/core' import { TuiChevron, TuiDataListWrapper, TuiSelect } from '@taiga-ui/kit' @@ -29,7 +29,7 @@ import { injectContext } from '@taiga-ui/polymorpheus'