diff --git a/src/lib/assets/settings.yml b/src/lib/assets/settings.yml index 1649e9c3..9ace9ea7 100644 --- a/src/lib/assets/settings.yml +++ b/src/lib/assets/settings.yml @@ -1,118 +1,154 @@ -settings: - 0x1: - title: Enable Serial Header - description: boolean 0 or 1, default is 0 - 0x2: - title: Enable Serial Logging - description: boolean 0 or 1, default is 0 - 0x3: - title: Enable Serial Debugging - description: boolean 0 or 1, default is 0 - 0x4: - title: Enable Serial Raw - description: boolean 0 or 1, default is 0 - 0x5: - title: Enable Serial Chord - description: boolean 0 or 1, default is 0 - 0x6: - title: Enable Serial Keyboard - description: boolean 0 or 1, default is 0 - 0x7: - title: Enable Serial Mouse - description: boolean 0 or 1, default is 0 - 0x11: - title: Enable USB HID Keyboard - description: boolean 0 or 1, default is 1 - 0x12: - title: Enable Character Entry - description: boolean 0 or 1 - 0x13: - title: GUI-CTRL Swap Mode - description: boolean 0 or 1; 1 swaps keymap 0 and 1. (CCL only) - 0x14: - title: Key Scan Duration - description: scan rate described in milliseconds; default is 2ms = 500Hz - 0x15: - title: Key Debounce Press Duration - description: debounce time in milliseconds; default is 7ms on the One and 20ms on the Lite - 0x16: - title: Key Debounce Release Duration - description: debounce time in milliseconds; default is 7ms on the One and 20ms on the Lite - 0x17: - title: Keyboard Output Character Microsecond Delays - description: delay time in microseconds (one delay for press and again for release); default is 480us; max is 10240us; increments of 40us - 0x21: - title: Enable USB HID Mouse - description: boolean 0 or 1; default is 1 - 0x22: - title: Slow Mouse Speed - description: pixels to move at the mouse poll rate; default for CC1 is 5 = 250px/s - 0x23: - title: Fast Mouse Speed - description: pixels to move at the mouse poll rate; default for CC1 is 25 = 1250px/s - 0x24: - title: Enable Active Mouse - description: boolean 0 or 1; moves mouse back and forth every 60s - 0x25: - title: Mouse Scroll Speed - description: default is 1; polls at 1/4th the rate of the mouse move updates - 0x26: - title: Mouse Poll Duration - description: poll rate described in milliseconds; default is 20ms = 50Hz - 0x31: - title: Enable Chording - description: boolean 0 or 1 - 0x32: - title: Enable Chording Character Counter Timeout - description: boolean 0 or 1; default is 1 - 0x33: - title: Chording Character Counter Timeout Timer - description: 0-255 deciseconds; default is 40 or 4.0 seconds - 0x34: - title: Chord Detection Press Tolerance(ms) - description: 1-50 milliseconds - 0x35: - title: Chord Detection Release Tolerance(ms) - description: 1-50 milliseconds - 0x41: - title: Enable Spurring - description: boolean 0 or 1; default is 1 - 0x42: - title: Enable Spurring Character Counter Timeout - description: boolean 0 or 1; default is 1 - 0x43: - title: Spurring Character Counter Timeout Timer - description: 0-255 seconds; default is 240 - 0x51: - title: Enable Arpeggiates - description: boolean 0 or 1; default is 1 - 0x54: - title: Arpeggiate Tolerance - description: in milliseconds; default 800ms - 0x61: - title: Enable Compound Chording (coming soon) - description: boolean 0 or 1; default is 0 - 0x64: - title: Compound Tolerance - description: in milliseconds; default 1500ms - 0x81: - title: LED Brightness - description: 0-50 (CCL only); default is 5, which draws around 100 mA of current - 0x82: - title: LED Color Code - description: Color Codes to be listed (CCL only) - 0x83: - title: Enable LED Key Highlight (coming soon) - description: boolean 0 or 1 (CCL only) - 0x84: - title: Enable LEDs - description: boolean 0 or 1; default is 1 (CCL only) - 0x91: - title: Operating System - description: Operating system codes listed below - 0x92: - title: Enable Realtime Feedback - description: boolean 0 or 1; default is 1 - 0x93: - title: Enable CharaChorder Ready on startup - description: boolean 0 or 1; default is 1 +- name: spurring + description: | + "Chording only" mode which tells your device to output chords on a press + rather than a press & release. It also enables you to jump from one + chord to another without releasing everything and can be activated in + GTM or by chording both mirror keys. It can provide significant speed + gains with chording, but also takes away the flexibility of character + entry. + items: + - id: 0x41 + name: enable + range: [0, 1] + - id: 0x43 + name: character counter timeout + range: [0, 240000] + step: 1000 + scale: 0.001 + unit: s +- name: arpeggiates + description: | + Allows chord modifiers to be hit after instead of with a chord, + and enables select keys to be placed before auto-spaces. + items: + - id: 0x51 + name: enable + range: [0, 1] + - id: 0x54 + name: timeout + range: [0, 2550] + step: 10 + unit: ms +- name: keyboard + items: + - id: 0x11 + name: enable + range: [0, 1] + - id: 0x12 + name: character entry + range: [0, 1] + - id: 0x13 + name: command option swap + range: [0, 1] + description: | + Swaps ⌥ and ⌘ to make transitioning between Mac and other systems easier. + - id: 0x14 + name: poll rate + range: [0, 255] + unit: Hz + inverse: 1000 + - id: 0x15 + name: debounce press + range: [0, 255] + unit: ms + - id: 0x16 + name: debounce release + range: [0, 255] + unit: ms + - id: 0x17 + name: output delay + range: [0, 10200] + step: 40 + unit: µs +- name: mouse + items: + - id: 0x21 + name: enable + range: [0, 1] + - id: 0x22 + name: slow speed + range: [0, 255] + unit: px + - id: 0x23 + name: fast speed + range: [0, 255] + unit: px + - id: 0x24 + name: caffeine + range: [0, 1] + description: | + Keeps computer alive by moving the mouse back and forth one pixel every 60s + - id: 0x25 + name: scroll speed + range: [0, 255] + unit: pg + - id: 0x26 + name: poll rate + range: [0, 255] + unit: Hz + inverse: 1000 +- name: chording + items: + - id: 0x31 + name: enable + range: [0, 1] + - id: 0x33 + name: auto delete timeout + range: [0, 25500] + step: 100 + - id: 0x34 + name: press tolerance + description: | + Scales with the number of chord inputs. + range: [0, 255] + unit: ms + - id: 0x35 + name: release tolerance + description: | + Scales with the number of chord inputs. + range: [0, 255] + unit: ms +- name: leds + items: + - id: 0x84 + name: enable + range: [0, 1] + - id: 0x81 + name: brightness + range: [0, 50] + - id: 0x82 + name: base color code + enum: + white: 0 + red: 1 + orange: 2 + yellow: 3 + charteuse: 4 + green: 5 + spring green: 6 + cyan: 7 + azure: 8 + blue: 9 + violet: 10 + magenta: 11 + rose: 12 + rainbow: 13 + - id: 0x83 + name: highlight + range: [0, 1] +- name: misc + items: + - id: 0x91 + name: operating system + enum: + windows: 0 + mac: 1 + linux: 2 + ios: 3 + android: 4 + - id: 0x92 + name: GTM realtime feedback + range: [0, 1] + - id: 0x93 + name: startup message + range: [0, 1] diff --git a/src/lib/meta/meta-storage.ts b/src/lib/meta/meta-storage.ts index f63b5360..11c176b4 100644 --- a/src/lib/meta/meta-storage.ts +++ b/src/lib/meta/meta-storage.ts @@ -1,4 +1,4 @@ -import type { RawVersionMeta, VersionMeta } from "./types/meta"; +import type { RawVersionMeta, SettingsMeta, VersionMeta } from "./types/meta"; import type { Listing } from "./types/listing"; import type { KeymapCategory } from "./types/actions"; import { browser } from "$app/environment"; @@ -9,7 +9,7 @@ export async function getMeta( device: string, version: string, fetch: typeof window.fetch = window.fetch, -): Promise { +): Promise { while (lock) await lock; let resolveLock!: () => void; lock = new Promise((resolve) => (resolveLock = resolve)); @@ -17,15 +17,19 @@ export async function getMeta( try { if (!browser) return fetchMeta(device, version, fetch); - const dbRequest = indexedDB.open("version-meta", 1); + const dbRequest = indexedDB.open("version-meta", 2); const db = await new Promise((resolve, reject) => { dbRequest.onsuccess = () => resolve(dbRequest.result); dbRequest.onerror = () => reject(dbRequest.error); dbRequest.onupgradeneeded = () => { const db = dbRequest.result; + if (db.objectStoreNames.contains("meta")) { + db.deleteObjectStore("meta"); + } db.createObjectStore("meta", { keyPath: ["device", "version"] }); }; }); + console.log("upgrading version meta db"); try { const readTransaction = db.transaction(["meta"], "readonly"); @@ -39,7 +43,6 @@ export async function getMeta( if (item) return item; const meta = await fetchMeta(device, version); - if (!meta) return undefined; const putTransaction = db.transaction(["meta"], "readwrite"); const putStore = putTransaction.objectStore("meta"); @@ -60,7 +63,7 @@ export async function getMeta( resolveLock(); lock = undefined; } - return undefined; + return fetchMeta(device, version, fetch); } async function fetchMeta( @@ -69,7 +72,9 @@ async function fetchMeta( fetch: typeof window.fetch = window.fetch, ): Promise { const path = `${import.meta.env.VITE_FIRMWARE_URL}/${device}/${version}`; - const files: Listing[] = await fetch(`${path}/`).then((res) => res.json()); + const files: Listing[] = await fetch(`${path}/`) + .then((res) => res.json()) + .catch(() => []); const meta: Partial | undefined = files.some( (entry) => entry.type === "file" && entry.name === "meta.json", ) @@ -105,6 +110,16 @@ async function fetchMeta( ), } : undefined, + settings: await (meta?.settings + ? fetch(`${path}/${meta.settings}`).then((it) => it.json()) + : import("$lib/assets/settings.yml") + .then((it) => (it as any).default) + .then((settings: SettingsMeta[]) => { + if (!device.startsWith("lite_")) { + settings = settings.filter((it) => it.name === "leds"); + } + return settings; + })), actions: await (meta?.actions ? fetch(`${path}/${meta.actions}`).then((it) => it.json()) : Promise.all( diff --git a/src/lib/meta/types/meta.ts b/src/lib/meta/types/meta.ts index d36ff17a..729ea862 100644 --- a/src/lib/meta/types/meta.ts +++ b/src/lib/meta/types/meta.ts @@ -5,6 +5,23 @@ import type { } from "$lib/share/chara-file"; import type { KeymapCategory } from "./actions"; +export interface SettingsMeta { + name: string; + description?: string; + items: SettingsItemMeta[]; +} + +export interface SettingsItemMeta { + id: number; + description?: string; + enum?: string[]; + range: [number, number]; + step?: number; + unit?: string; + inverse?: number; + scale?: number; +} + export interface RawVersionMeta { version: string; target: string; @@ -14,6 +31,7 @@ export interface RawVersionMeta { public_build: boolean; development_mode: number; actions: string; + settings: string; factory_defaults: { layout: string; settings: string; @@ -38,6 +56,7 @@ export interface VersionMeta { dirty: boolean; developmentBuild: boolean; actions: KeymapCategory[]; + settings: SettingsMeta[]; factoryDefaults?: { layout: CharaLayoutFile; settings: CharaSettingsFile; diff --git a/src/lib/serial/connection.ts b/src/lib/serial/connection.ts index f78aa320..83b89490 100644 --- a/src/lib/serial/connection.ts +++ b/src/lib/serial/connection.ts @@ -5,7 +5,6 @@ import type { Writable } from "svelte/store"; import type { CharaLayout } from "$lib/serialization/layout"; import { persistentWritable } from "$lib/storage"; import { userPreferences } from "$lib/preferences"; -import settingInfo from "$lib/assets/settings.yml"; import { getMeta } from "$lib/meta/meta-storage"; import type { VersionMeta } from "$lib/meta/types/meta"; @@ -69,19 +68,19 @@ export async function initSerial(manual = false, withSync = true) { export async function sync() { const device = get(serialPort); if (!device) return; - getMeta( + syncStatus.set("downloading"); + const meta = await getMeta( `${device.device}_${device.chipset}`.toLowerCase(), device.version.toString(), - ).then((meta) => { - deviceMeta.set(meta); - }); + ); + deviceMeta.set(meta); const chordCount = await device.getChordCount(); - syncStatus.set("downloading"); - const max = - Object.keys(settingInfo["settings"]).length + - device.keyCount * 3 + - chordCount; + const maxSettings = meta.settings + .map((it) => it.items.length) + .reduce((a, b) => a + b, 0); + + const max = maxSettings + device.keyCount * 3 + chordCount; let current = 0; syncProgress.set({ max, current }); function progressTick() { @@ -90,12 +89,12 @@ export async function sync() { } const parsedSettings: number[] = []; - for (const key in settingInfo["settings"]) { - try { - parsedSettings[Number.parseInt(key)] = await device.getSetting( - Number.parseInt(key), - ); - } catch {} + for (const category of meta.settings) { + for (const setting of category.items) { + try { + parsedSettings[setting.id] = await device.getSetting(setting.id); + } catch {} + } progressTick(); } deviceSettings.set(parsedSettings); diff --git a/src/routes/(app)/config/settings/+page.svelte b/src/routes/(app)/config/settings/+page.svelte index a705f3d8..fe99e5ef 100644 --- a/src/routes/(app)/config/settings/+page.svelte +++ b/src/routes/(app)/config/settings/+page.svelte @@ -17,6 +17,21 @@ import { preference } from "$lib/preferences"; import { action } from "$lib/title"; import { fly } from "svelte/transition"; + import type { SettingsItemMeta } from "$lib/meta/types/meta"; + + function titlecase(str: string) { + return str.charAt(0).toUpperCase() + str.slice(1); + } + + function settingValue(value: number, setting: SettingsItemMeta) { + if (setting.inverse !== undefined) { + return setting.inverse / value; + } + if (setting.scale !== undefined) { + return value * setting.scale; + } + return value; + } @@ -71,15 +86,6 @@ /> {#if $serialPort} - - {#if $deviceMeta?.factoryDefaults?.settings} {/if} - - {#if $serialPort} -
- -

- "Chording only" mode which tells your device to output chords on a press - rather than a press & release. It also enables you to jump from one - chord to another without releasing everything and can be activated in - GTM or by chording both mirror keys. It can provide significant speed - gains with chording, but also takes away the flexibility of character - entry. -

-

- Spurring also helps new users learn how to chord by eliminating the need - to focus on timing. -

-

- Spurring is toggled by chording and - together. -

- -
- -
- -

- A quick, single key press and release used to indicate a suffix, prefix, - or modifier to be associated with a chord. -

-

- The following keys have special behavior when arpeggiates are enabled: -

-
    -
  • - , and will be placed before the - auto-inserted space -
  • -
  • - , and will be placed before the - auto-inserted space and capitalize the next word -
  • -
  • - and will replace the auto-inserted space -
  • -
- -
- -
- Chord Modifiers -

- Chord modifiers change a chord when held with the chord or when pressed - after (arpeggiated), provided that arpeggiates are enabled. -

-
    -
  • - Capitalizes the first letter of - a chord -
  • -
  • - Present Tense (supported words only) -
  • -
  • - Plural (supported words only) -
  • -
  • - Past Tense (supported words only) -
  • -
  • - Comparative (supported words only) -
  • -
-
- -
- Character Entry - {#if $serialPort.device === "LITE"} - - {/if} - - - - - -
- -
- - - - - -
- -
- - - - -
- - {#if $serialPort.device === "LITE"} + {#if $deviceMeta} + {#each $deviceMeta.settings as category}
- - - + + {#if category.items[0]?.name === "enable"} + + {:else} + {titlecase(category.name)} + {/if} + + {#if category.description} +

{category.description}

+ {/if} + {#each category.items as item} + {#if item.name !== "enable"} + + {/if} + {/each}
- {/if} + {/each} {/if}