feat: settings wip

This commit is contained in:
2023-07-24 22:58:10 +02:00
parent e64082d578
commit 2130b6c7b9
10 changed files with 338 additions and 164 deletions

View File

@@ -0,0 +1,89 @@
<script>
import {serialPort} from "$lib/serial/connection"
import LayoutCC1 from "$lib/components/layout/LayoutCC1.svelte"
$: device = $serialPort?.device ?? "ONE"
let activeLayer = 0
</script>
<div>
<select bind:value={device}>
<option value="ONE">CC1</option>
<option value="LITE">Lite</option>
</select>
<fieldset>
{#each [["Numeric Layer", "123", 1], ["Primary Layer", "abc", 0], ["Function Layer", "function", 2]] as [title, icon, value]}
<button
{title}
class="icon"
on:click={() => (activeLayer = value)}
class:active={activeLayer === value}
>
{icon}
</button>
{/each}
</fieldset>
{#if device === "ONE"}
<LayoutCC1 bind:activeLayer />
{:else}
<p>Unsupported device ({$serialPort?.device})</p>
{/if}
</div>
<style lang="scss">
fieldset {
position: relative;
display: flex;
align-items: center;
justify-content: center;
margin-block-end: -36px;
padding: 0;
border: none;
}
button.icon {
cursor: pointer;
z-index: 1;
font-size: 24px;
color: var(--md-sys-color-on-surface-variant);
background: var(--md-sys-color-surface-variant);
border: none;
transition: all 250ms ease;
&:nth-child(2) {
z-index: 2;
aspect-ratio: 1;
font-size: 32px;
border-radius: 50%;
outline: 8px solid var(--md-sys-color-background);
}
&:first-child {
padding-inline-end: 16px;
border-radius: 16px 0 0 16px;
}
&:last-child {
padding-inline-start: 16px;
border-radius: 0 16px 16px 0;
}
&.active {
font-weight: 900;
color: var(--md-sys-color-on-tertiary);
background: var(--md-sys-color-tertiary);
}
}
</style>

View File

@@ -1,121 +1,52 @@
<script>
import RingInput from "$lib/components/layout/RingInput.svelte"
let activeLayer = 0
export let activeLayer = 0
</script>
<div>
<fieldset>
{#each [["Numeric Layer", "123", 1], ["Primary Layer", "abc", 0], ["Function Layer", "function", 2]] as [title, icon, value]}
<button
{title}
class="icon"
on:click={() => (activeLayer = value)}
class:active={activeLayer === value}
>
{icon}
</button>
{/each}
</fieldset>
<div class="col layout" style="gap: 0">
<div class="row" style="gap: 156px">
<div class="row">
<RingInput {activeLayer} keys={{d: 30, e: 31, n: 32, w: 33, s: 34}} type="tertiary" />
<div class="col">
<RingInput {activeLayer} keys={{d: 25, e: 26, n: 27, w: 28, s: 29}} />
<RingInput {activeLayer} keys={{d: 40, e: 41, n: 42, w: 43, s: 44}} type="secondary" />
</div>
<div class="col">
<RingInput {activeLayer} keys={{d: 20, e: 21, n: 22, w: 23, s: 24}} />
<RingInput {activeLayer} keys={{d: 35, e: 36, n: 37, w: 38, s: 39}} type="secondary" />
</div>
<RingInput {activeLayer} keys={{d: 15, e: 16, n: 17, w: 18, s: 19}} />
<div class="col layout" style="gap: 0">
<div class="row" style="gap: 156px">
<div class="row">
<RingInput {activeLayer} keys={{d: 30, e: 31, n: 32, w: 33, s: 34}} type="tertiary" />
<div class="col">
<RingInput {activeLayer} keys={{d: 25, e: 26, n: 27, w: 28, s: 29}} />
<RingInput {activeLayer} keys={{d: 40, e: 41, n: 42, w: 43, s: 44}} type="secondary" />
</div>
<div class="row">
<RingInput {activeLayer} keys={{d: 60, w: 61, n: 62, e: 63, s: 64}} />
<div class="col">
<RingInput {activeLayer} keys={{d: 65, w: 66, n: 67, e: 68, s: 69}} />
<RingInput {activeLayer} keys={{d: 80, w: 81, n: 82, e: 83, s: 84}} />
</div>
<div class="col">
<RingInput {activeLayer} keys={{d: 70, w: 71, n: 72, e: 73, s: 74}} />
<RingInput {activeLayer} keys={{d: 85, w: 86, n: 87, e: 88, s: 89}} />
</div>
<RingInput {activeLayer} keys={{d: 75, w: 76, n: 77, e: 78, s: 79}} />
<div class="col">
<RingInput {activeLayer} keys={{d: 20, e: 21, n: 22, w: 23, s: 24}} />
<RingInput {activeLayer} keys={{d: 35, e: 36, n: 37, w: 38, s: 39}} type="secondary" />
</div>
<RingInput {activeLayer} keys={{d: 15, e: 16, n: 17, w: 18, s: 19}} />
</div>
<div class="row" style="gap: 48px; margin-top: -32px">
<RingInput {activeLayer} keys={{d: 10, e: 11, n: 12, w: 13, s: 14}} />
<RingInput {activeLayer} keys={{d: 55, w: 56, n: 57, e: 58, s: 59}} />
</div>
<div class="row" style="gap: 160px">
<RingInput {activeLayer} keys={{d: 5, e: 6, n: 7, w: 8, s: 9}} />
<RingInput {activeLayer} keys={{d: 50, w: 51, n: 52, e: 53, s: 54}} />
</div>
<div class="row" style="gap: 320px; margin-top: -12px">
<RingInput {activeLayer} keys={{d: 0, e: 1, n: 2, w: 3, s: 4}} type="secondary" />
<RingInput {activeLayer} keys={{d: 45, w: 46, n: 47, e: 48, s: 49}} type="secondary" />
<div class="row">
<RingInput {activeLayer} keys={{d: 60, w: 61, n: 62, e: 63, s: 64}} />
<div class="col">
<RingInput {activeLayer} keys={{d: 65, w: 66, n: 67, e: 68, s: 69}} />
<RingInput {activeLayer} keys={{d: 80, w: 81, n: 82, e: 83, s: 84}} />
</div>
<div class="col">
<RingInput {activeLayer} keys={{d: 70, w: 71, n: 72, e: 73, s: 74}} />
<RingInput {activeLayer} keys={{d: 85, w: 86, n: 87, e: 88, s: 89}} />
</div>
<RingInput {activeLayer} keys={{d: 75, w: 76, n: 77, e: 78, s: 79}} />
</div>
</div>
<div class="row" style="gap: 48px; margin-top: -32px">
<RingInput {activeLayer} keys={{d: 10, e: 11, n: 12, w: 13, s: 14}} />
<RingInput {activeLayer} keys={{d: 55, w: 56, n: 57, e: 58, s: 59}} />
</div>
<div class="row" style="gap: 160px">
<RingInput {activeLayer} keys={{d: 5, e: 6, n: 7, w: 8, s: 9}} />
<RingInput {activeLayer} keys={{d: 50, w: 51, n: 52, e: 53, s: 54}} />
</div>
<div class="row" style="gap: 320px; margin-top: -12px">
<RingInput {activeLayer} keys={{d: 0, e: 1, n: 2, w: 3, s: 4}} type="secondary" />
<RingInput {activeLayer} keys={{d: 45, w: 46, n: 47, e: 48, s: 49}} type="secondary" />
</div>
</div>
<style lang="scss">
fieldset {
position: relative;
display: flex;
align-items: center;
justify-content: center;
margin-block-end: -36px;
padding: 0;
border: none;
}
button.icon {
cursor: pointer;
z-index: 1;
font-size: 24px;
color: var(--md-sys-color-on-surface-variant);
background: var(--md-sys-color-surface-variant);
border: none;
transition: all 250ms ease;
&:nth-child(2) {
z-index: 2;
aspect-ratio: 1;
font-size: 32px;
border-radius: 50%;
outline: 8px solid var(--md-sys-color-background);
}
&:first-child {
padding-inline-end: 16px;
border-radius: 16px 0 0 16px;
}
&:last-child {
padding-inline-start: 16px;
border-radius: 0 16px 16px 0;
}
&.active {
font-weight: 900;
color: var(--md-sys-color-on-tertiary);
background: var(--md-sys-color-tertiary);
}
}
.row,
.col {
display: flex;

View File

@@ -2,6 +2,7 @@ import {LineBreakTransformer} from "$lib/serial/line-break-transformer"
import {serialLog} from "$lib/serial/connection"
import type {Chord} from "$lib/serial/chord"
import {parseChordActions, parsePhrase, stringifyChordActions, stringifyPhrase} from "$lib/serial/chord"
import {dev} from "$app/environment"
export const VENDOR_ID = 0x239a
@@ -24,8 +25,10 @@ export class CharaDevice {
private lock?: Promise<true>
version!: string
deviceId!: string
version!: [number, number, number]
company!: "CHARACHORDER"
device!: "ONE" | "LITE"
chipset!: "M0" | "S2"
constructor(private readonly baudRate = 115200) {}
@@ -58,8 +61,12 @@ export class CharaDevice {
})
.getReader()
this.version = await this.send("VERSION").then(it => it[0])
this.deviceId = await this.send("ID").then(it => it[0])
const [version] = await this.send("VERSION")
this.version = version.split(".").map(Number) as [number, number, number]
const [company, device, chipset] = await this.send("ID")
this.company = company as "CHARACHORDER"
this.device = device as "ONE" | "LITE"
this.chipset = chipset as "M0" | "S2"
}
private async internalRead() {

View File

@@ -1,41 +0,0 @@
export interface DeviceSettings {
enableSerialLog: boolean
enableSerialRaw: boolean
enableSerialChord: boolean
enableSerialKeyboard: boolean
enableSerialMouse: boolean
enableSerialDebug: boolean
enableSerialHeader: boolean
enableHidKeyboard: boolean
pressThreshold: number
releaseThreshold: number
enableHidMouse: number
scrollDelay: number
enableSpurring: boolean
spurKillerToggle: number
spurKiller: number
enableChording: boolean
charKillerToggle: number
charCounterKiller: number
}
export const SETTING_IDS: Record<keyof DeviceSettings, number> = {
enableSerialLog: 0x01,
enableSerialRaw: 0x02,
enableSerialChord: 0x03,
enableSerialKeyboard: 0x04,
enableSerialMouse: 0x05,
enableSerialDebug: 0x06,
enableSerialHeader: 0x07,
enableHidKeyboard: 0x0a,
pressThreshold: 0x0b,
releaseThreshold: 0x0c,
enableHidMouse: 0x14,
scrollDelay: 0x15,
enableSpurring: 0x1e,
spurKillerToggle: 0x1f,
spurKiller: 0x20,
enableChording: 0x28,
charKillerToggle: 0x29,
charCounterKiller: 0x2a,
}

View File

@@ -4,6 +4,7 @@ $height: 1.5em;
label:has(input[type="checkbox"]) {
cursor: pointer;
user-select: none;
display: flex;
gap: $padding;
@@ -12,7 +13,7 @@ label:has(input[type="checkbox"]) {
font-size: 12px;
input {
input[type="checkbox"] {
$width: calc($height * (5 / 3));
$diameter: calc($height - ((2 * $padding) + (2 * $border)));
$radius: calc($diameter / 2);

View File

@@ -65,6 +65,8 @@
flex-direction: column;
align-items: flex-start;
justify-content: center;
width: min-content;
}
.disclaimer {
@@ -91,6 +93,7 @@
align-items: center;
justify-content: center;
width: max-content;
height: 48px;
padding-block: 8px;
padding-inline: 16px;

View File

@@ -1,9 +1,8 @@
<script lang="ts">
import {initSerial, serialPort} from "$lib/serial/connection"
import {browser} from "$app/environment"
import {slide, fade, fly} from "svelte/transition"
import {slide, fade} from "svelte/transition"
import {preference} from "$lib/preferences"
import Terminal from "$lib/components/Terminal.svelte"
let terminal = false
let powerDialog = false
@@ -17,9 +16,11 @@
{#if $serialPort}
<p transition:slide>
{$serialPort.deviceId}
{$serialPort.company}
{$serialPort.device}
{$serialPort.chipset}
<br />
Version {$serialPort.version}
Version {$serialPort.version.map(it => it.toString()).join(".")}
</p>
{/if}

View File

@@ -7,7 +7,6 @@
import type {Chord} from "$lib/serial/chord"
import tippy from "tippy.js"
import {calculateChordCoverage} from "$lib/chords/coverage"
import {SETTING_IDS} from "$lib/serial/settings"
$: searchIndex = $chords?.length > 0 ? buildIndex($chords) : undefined
@@ -45,11 +44,6 @@
{/if}
<button class="icon" on:click={sort}>sort</button>
<button class="icon">filter_list</button>
{#if $serialPort}
{#await $serialPort.getSetting(SETTING_IDS.enableChording) then enableChording}
<label><input type="checkbox" checked={enableChording !== 0} /> Enable Chording</label>
{/await}
{/if}
<section>
<table>

View File

@@ -1,10 +1,10 @@
<script lang="ts">
import LayoutCC1 from "$lib/components/layout/LayoutCC1.svelte"
import {share} from "$lib/share"
import {layout} from "$lib/serial/connection"
import tippy from "tippy.js"
import {onMount} from "svelte"
import {layoutAsUrlComponent, layoutFromUrlComponent} from "$lib/serialization/layout"
import Layout from "$lib/components/layout/Layout.svelte"
onMount(async () => {
const url = new URL(window.location.href)
@@ -30,7 +30,7 @@
<svelte:window use:share={shareLayout} />
<section>
<LayoutCC1 />
<Layout />
</section>
<style lang="scss">

View File

@@ -1,4 +1,193 @@
<script>
import {serialPort} from "$lib/serial/connection"
</script>
<label><input type="checkbox" />Serial Log</label>
{#if $serialPort}
<form>
<fieldset>
<legend><label><input type="checkbox" />Spurring</label></legend>
<p>
"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.
</p>
<p>Spurring also helps new users learn how to chord by eliminating the need to focus on timing.</p>
<p>Spurring is toggled by chording both of the 'mirror' keys together.</p>
<label
>Character Counter Timeout<span class="unit"
><input type="number" step="0.1" min="0" max="25.5" />s</span
></label
>
</fieldset>
<fieldset>
<legend><label><input type="checkbox" />Arpeggiates</label></legend>
<p>
A quick, single key press and release used to indicate a suffix, prefix, or modifier to be associated
with a chord.
</p>
<label>Tolerance<span class="unit"><input type="number" step="1" />ms</span></label>
</fieldset>
<fieldset>
<legend><label><input type="checkbox" />Character Entry</label></legend>
<label>Swap Keymap 0 and 1<input type="checkbox" /></label>
<label>Key Scan Rate<span class="unit"><input type="number" />Hz</span></label>
<label>Key Debounce Press<span class="unit"><input type="number" />ms</span></label>
<label>Key Debounce Release<span class="unit"><input type="number" />ms</span></label>
<label>Output Character Delay<span class="unit"><input type="number" />µs</span></label>
</fieldset>
<fieldset>
<legend><label><input type="checkbox" />Mouse</label></legend>
<label>Mouse Speed<input type="number" /><input type="number" /></label>
<label>Scroll Speed<input type="number" /></label>
<label title="Bounces mouse by 1px every 60s if enabled">Active Mouse<input type="checkbox" /></label>
<label>Poll Rate<span class="unit"><input type="number" />Hz</span></label>
</fieldset>
<fieldset>
<legend><label><input type="checkbox" />Chording</label></legend>
<label
>Character Timeout <span class="unit"><input type="number" min="0" max="25.5" step="0.1" />s</span
></label
>
<label
>Detection Tolerance<span class="unit"><input type="number" min="1" max="50" step="1" />ms</span
></label
>
<label
>Release Tolerance<span class="unit"><input type="number" min="1" max="50" step="1" />ms</span></label
>
<label>Compound Chording<input type="checkbox" /></label>
</fieldset>
<fieldset>
<legend><label>Device</label></legend>
<label>Boot message<input type="checkbox" /></label>
<label>Realtime Feedback<input type="checkbox" /></label>
<label>
Operating System
<select>
<option value="0">Windows</option>
<option value="1">MacOS</option>
<option value="2">Linux</option>
<option value="3">iOS</option>
<option value="4">Android</option>
<option value="255">Unknown</option>
</select>
</label>
</fieldset>
{#if $serialPort.device === "LITE"}
<fieldset>
<legend><label><input type="checkbox" />RGB</label></legend>
<label>Brightness<input type="range" min="0" max="50" step="1" /></label>
<label>Color</label>
<label>Reactive Keys<input type="checkbox" /></label>
</fieldset>
{/if}
</form>
{/if}
<style lang="scss">
form {
overflow: hidden;
display: flex;
flex-flow: row wrap;
gap: 16px;
justify-content: center;
max-width: 30cm;
margin-block: auto;
}
legend,
legend > label {
font-size: 24px;
font-weight: bold;
> input {
font-size: 12px;
}
}
fieldset {
max-width: 400px;
border: 1px solid var(--md-sys-color-outline);
border-radius: 24px;
> label {
display: flex;
gap: 16px;
align-items: center;
justify-content: space-between;
margin-block: 4px;
font-size: 14px;
&:has(input[type="number"]) {
cursor: text;
&:hover {
filter: none;
}
}
input[type="checkbox"] {
font-size: 12px;
}
}
.unit {
overflow: hidden;
display: flex;
gap: 4px;
align-items: center;
justify-content: flex-start;
width: 67px;
padding-inline-end: auto;
font-size: 12px;
font-weight: bold;
background: var(--md-sys-color-secondary-container);
border-radius: 16px;
}
input[type="number"] {
display: flex;
width: 5ch;
height: 100%;
padding-block: 4px;
font-family: "Noto Sans Mono", monospace;
color: var(--md-sys-color-on-secondary);
text-align: end;
background: var(--md-sys-color-secondary);
border: none;
&::-webkit-inner-spin-button {
display: none;
}
&::after {
content: "bleh";
}
&:focus {
filter: brightness(120%);
outline: none;
}
}
p {
font-size: 10px;
}
}
</style>