keyboard keymap also

This commit is contained in:
Matt Hill
2026-01-20 14:24:45 -07:00
parent 0a0f0850d7
commit 99727e132c
6 changed files with 63 additions and 57 deletions

View File

@@ -82,7 +82,7 @@ export default class KeyboardPage {
this.stateService.language as LanguageCode, this.stateService.language as LanguageCode,
) )
selected = selected =
this.keyboards.find(k => k.code === this.stateService.keyboard) || this.keyboards.find(k => k.layout === this.stateService.keyboard) ||
this.keyboards[0]! this.keyboards[0]!
readonly saving = signal(false) readonly saving = signal(false)
@@ -95,13 +95,14 @@ export default class KeyboardPage {
try { try {
// Send keyboard to backend // Send keyboard to backend
await this.api.setKeyboard({ await this.api.setKeyboard({
layout: this.selected.code, layout: this.selected.layout,
keymap: this.selected.keymap,
model: null, model: null,
variant: null, variant: null,
options: [], options: [],
}) })
this.stateService.keyboard = this.selected.code this.stateService.keyboard = this.selected.layout
await this.navigateToNextStep() await this.navigateToNextStep()
} finally { } finally {
this.saving.set(false) this.saving.set(false)

View File

@@ -1,9 +1,14 @@
import { LanguageCode } from './languages' 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 * Keyboard layout display names
@@ -18,10 +23,11 @@ export type KeyboardName =
| 'Polish' | 'Polish'
/** /**
* Keyboard layout definition * Keyboard definition with layout and keymap
*/ */
export interface Keyboard { export interface Keyboard {
code: KeyboardCode layout: KeyboardLayout
keymap: KeyboardKeymap
name: KeyboardName name: KeyboardName
} }
@@ -29,7 +35,8 @@ export interface Keyboard {
* Full keyboard configuration for backend API * Full keyboard configuration for backend API
*/ */
export interface FullKeyboard { export interface FullKeyboard {
layout: string layout: KeyboardLayout
keymap: KeyboardKeymap
model: string | null model: string | null
variant: string | null variant: string | null
options: string[] options: string[]
@@ -40,29 +47,29 @@ export interface FullKeyboard {
*/ */
export const KEYBOARDS_BY_LANGUAGE: Record<LanguageCode, Keyboard[]> = { export const KEYBOARDS_BY_LANGUAGE: Record<LanguageCode, Keyboard[]> = {
en: [ en: [
{ code: 'us', name: 'US English' }, { layout: 'us', keymap: 'us', name: 'US English' },
{ code: 'gb', name: 'UK English' }, { layout: 'gb', keymap: 'uk', name: 'UK English' },
], ],
es: [ es: [
{ code: 'es', name: 'Spanish' }, { layout: 'es', keymap: 'es', name: 'Spanish' },
{ code: 'latam', name: 'Latin American' }, { layout: 'latam', keymap: 'la', name: 'Latin American' },
], ],
de: [{ code: 'de', name: 'German' }], de: [{ layout: 'de', keymap: 'de', name: 'German' }],
fr: [{ code: 'fr', name: 'French' }], fr: [{ layout: 'fr', keymap: 'fr', name: 'French' }],
pl: [{ code: 'pl', name: 'Polish' }], pl: [{ layout: 'pl', keymap: 'pl', name: 'Polish' }],
} }
/** /**
* All available keyboard layouts * All available keyboard layouts
*/ */
export const ALL_KEYBOARDS: Keyboard[] = [ export const ALL_KEYBOARDS: Keyboard[] = [
{ code: 'us', name: 'US English' }, { layout: 'us', keymap: 'us', name: 'US English' },
{ code: 'gb', name: 'UK English' }, { layout: 'gb', keymap: 'uk', name: 'UK English' },
{ code: 'es', name: 'Spanish' }, { layout: 'es', keymap: 'es', name: 'Spanish' },
{ code: 'latam', name: 'Latin American' }, { layout: 'latam', keymap: 'la', name: 'Latin American' },
{ code: 'de', name: 'German' }, { layout: 'de', keymap: 'de', name: 'German' },
{ code: 'fr', name: 'French' }, { layout: 'fr', keymap: 'fr', name: 'French' },
{ code: 'pl', name: 'Polish' }, { layout: 'pl', keymap: 'pl', name: 'Polish' },
] ]
/** /**
@@ -71,20 +78,20 @@ export const ALL_KEYBOARDS: Keyboard[] = [
*/ */
export function getAllKeyboardsSorted(languageCode: LanguageCode): Keyboard[] { export function getAllKeyboardsSorted(languageCode: LanguageCode): Keyboard[] {
const languageKeyboards = KEYBOARDS_BY_LANGUAGE[languageCode] 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( const otherKeyboards = ALL_KEYBOARDS.filter(
kb => !languageKeyboardCodes.has(kb.code), kb => !languageLayouts.has(kb.layout),
).sort((a, b) => a.name.localeCompare(b.name)) ).sort((a, b) => a.name.localeCompare(b.name))
return [...languageKeyboards, ...otherKeyboards] return [...languageKeyboards, ...otherKeyboards]
} }
/** /**
* Get the display name for a keyboard code. * Get the display name for a keyboard layout.
*/ */
export function getKeyboardName( export function getKeyboardName(
code: KeyboardCode | string, layout: KeyboardLayout | string,
): KeyboardName | 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 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
} }

View File

@@ -18,7 +18,7 @@ import {
i18nPipe, i18nPipe,
i18nService, i18nService,
Keyboard, Keyboard,
KeyboardCode, KeyboardLayout,
Language, Language,
LANGUAGES, LANGUAGES,
LANGUAGE_TO_CODE, LANGUAGE_TO_CODE,
@@ -317,29 +317,30 @@ export default class SystemGeneralComponent {
if (!server) return if (!server) return
const keyboards = getAllKeyboardsSorted(LANGUAGE_TO_CODE[server.language]) 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 this.dialog
.openComponent<KeyboardCode | null>( .openComponent<Keyboard | null>(
new PolymorpheusComponent(KeyboardSelectComponent, this.injector), new PolymorpheusComponent(KeyboardSelectComponent, this.injector),
{ {
label: 'Select Keyboard Layout', label: 'Select Keyboard Layout',
size: 's', size: 's',
data: { keyboards, currentKeyboard }, data: { keyboards, currentLayout },
}, },
) )
.pipe(filter((code): code is KeyboardCode => code !== null)) .pipe(filter((keyboard): keyboard is Keyboard => keyboard !== null))
.subscribe(keyboardCode => { .subscribe(keyboard => {
this.saveKeyboard(keyboardCode) this.saveKeyboard(keyboard)
}) })
} }
private async saveKeyboard(keyboardCode: KeyboardCode) { private async saveKeyboard(keyboard: Keyboard) {
const loader = this.loader.open('Saving').subscribe() const loader = this.loader.open('Saving').subscribe()
try { try {
await this.api.setKeyboard({ await this.api.setKeyboard({
layout: keyboardCode, layout: keyboard.layout,
keymap: keyboard.keymap,
model: null, model: null,
variant: null, variant: null,
options: [], options: [],
@@ -457,17 +458,17 @@ export default class SystemGeneralComponent {
private promptKeyboardSelection(keyboards: Keyboard[]) { private promptKeyboardSelection(keyboards: Keyboard[]) {
this.dialog this.dialog
.openComponent<KeyboardCode | null>( .openComponent<Keyboard | null>(
new PolymorpheusComponent(KeyboardSelectComponent, this.injector), new PolymorpheusComponent(KeyboardSelectComponent, this.injector),
{ {
label: 'Select Keyboard Layout', label: 'Select Keyboard Layout',
size: 's', size: 's',
data: { keyboards, currentKeyboard: null }, data: { keyboards, currentLayout: null },
}, },
) )
.pipe(filter((code): code is KeyboardCode => code !== null)) .pipe(filter((keyboard): keyboard is Keyboard => keyboard !== null))
.subscribe(keyboardCode => { .subscribe(keyboard => {
this.enableKioskWithKeyboard(keyboardCode) 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() const loader = this.loader.open('Enabling').subscribe()
try { try {
await this.api.setKeyboard({ await this.api.setKeyboard({
layout: keyboardCode, layout: keyboard.layout,
keymap: keyboard.keymap,
model: null, model: null,
variant: null, variant: null,
options: [], options: [],

View File

@@ -1,6 +1,6 @@
import { Component, inject } from '@angular/core' import { Component, inject } from '@angular/core'
import { FormsModule } from '@angular/forms' 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 { TUI_IS_MOBILE } from '@taiga-ui/cdk'
import { TuiButton, TuiDialogContext, TuiTextfield } from '@taiga-ui/core' import { TuiButton, TuiDialogContext, TuiTextfield } from '@taiga-ui/core'
import { TuiChevron, TuiDataListWrapper, TuiSelect } from '@taiga-ui/kit' import { TuiChevron, TuiDataListWrapper, TuiSelect } from '@taiga-ui/kit'
@@ -29,7 +29,7 @@ import { injectContext } from '@taiga-ui/polymorpheus'
</button> </button>
<button <button
tuiButton tuiButton
[disabled]="!selected || selected.code === initialCode" [disabled]="!selected || selected.layout === initialLayout"
(click)="confirm()" (click)="confirm()"
> >
{{ 'Confirm' | i18n }} {{ 'Confirm' | i18n }}
@@ -61,16 +61,16 @@ export class KeyboardSelectComponent {
private readonly context = private readonly context =
injectContext< injectContext<
TuiDialogContext< TuiDialogContext<
KeyboardCode | null, Keyboard | null,
{ keyboards: Keyboard[]; currentKeyboard: KeyboardCode | null } { keyboards: Keyboard[]; currentLayout: KeyboardLayout | null }
> >
>() >()
protected readonly mobile = inject(TUI_IS_MOBILE) protected readonly mobile = inject(TUI_IS_MOBILE)
readonly keyboards = this.context.data.keyboards readonly keyboards = this.context.data.keyboards
readonly initialCode = this.context.data.currentKeyboard readonly initialLayout = this.context.data.currentLayout
selected = selected =
this.keyboards.find(kb => kb.code === this.initialCode) || this.keyboards.find(kb => kb.layout === this.initialLayout) ||
this.keyboards[0]! this.keyboards[0]!
readonly stringify = (kb: Keyboard) => kb.name readonly stringify = (kb: Keyboard) => kb.name
@@ -80,6 +80,6 @@ export class KeyboardSelectComponent {
} }
confirm() { confirm() {
this.context.completeWith(this.selected.code) this.context.completeWith(this.selected)
} }
} }

View File

@@ -460,12 +460,7 @@ export class MockApiService extends ApiService {
{ {
op: PatchOp.REPLACE, op: PatchOp.REPLACE,
path: '/serverInfo/keyboard', path: '/serverInfo/keyboard',
value: { value: params,
layout: params.layout,
model: params.model,
variant: params.variant,
options: params.options,
},
}, },
] ]
this.mockRevision(patch) this.mockRevision(patch)

View File

@@ -222,6 +222,7 @@ export const mockPatchData: DataModel = {
language: 'en_US', language: 'en_US',
keyboard: { keyboard: {
layout: 'us', layout: 'us',
keymap: 'us',
model: null, model: null,
variant: null, variant: null,
options: [], options: [],