9 Commits

Author SHA1 Message Date
f0ad19e6c2 1.4.0 2024-02-14 00:55:10 +01:00
9022a09b4c fix: allow 0-return on chord deletion 2024-02-07 00:11:10 +01:00
7e3e61afd7 feat: force backup when putting the device into bootloader mode 2024-02-05 21:03:36 +01:00
08f594d164 feat: read full chord actions every time
feat: add special view for compound chords
fix: make it possible to delete compound chords
fixes #94
2024-02-05 20:39:05 +01:00
046595b51f feat: add device firmware update instructions
resolves #89
2024-02-05 20:08:50 +01:00
fbc5303690 fix: backup title is confusing
fixes #83
2024-02-05 19:55:26 +01:00
ad41d39bfb fix: remove logging statement
fixes #80
2024-02-05 19:50:37 +01:00
6faaa18b3b 1.3.2 2024-01-30 19:49:52 +01:00
6ab6959129 fix: disallow null inputs when editing
feat: allow special inputs while creating a chord input
fixes #93
2024-01-30 19:49:10 +01:00
19 changed files with 54 additions and 35 deletions

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{ {
"name": "charachorder-device-manager", "name": "charachorder-device-manager",
"version": "1.3.1", "version": "1.4.0",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "charachorder-device-manager", "name": "charachorder-device-manager",
"version": "1.3.1", "version": "1.4.0",
"hasInstallScript": true, "hasInstallScript": true,
"license": "AGPL-3.0-or-later", "license": "AGPL-3.0-or-later",
"devDependencies": { "devDependencies": {

View File

@@ -1,6 +1,6 @@
{ {
"name": "charachorder-device-manager", "name": "charachorder-device-manager",
"version": "1.3.1", "version": "1.4.0",
"license": "AGPL-3.0-or-later", "license": "AGPL-3.0-or-later",
"private": true, "private": true,
"repository": { "repository": {

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "app" name = "app"
version = "1.3.1" version = "1.4.0"
description = "A Tauri App" description = "A Tauri App"
authors = ["Thea Schöbl <dev@theaninova.de>"] authors = ["Thea Schöbl <dev@theaninova.de>"]
license = "AGPL-3" license = "AGPL-3"

View File

@@ -6,7 +6,7 @@
"devPath": "http://localhost:5173", "devPath": "http://localhost:5173",
"distDir": "../build" "distDir": "../build"
}, },
"package": { "productName": "amacc1ng", "version": "1.3.1" }, "package": { "productName": "amacc1ng", "version": "1.4.0" },
"tauri": { "tauri": {
"allowlist": { "all": false }, "allowlist": { "all": false },
"bundle": { "bundle": {

1
src/env.d.ts vendored
View File

@@ -12,6 +12,7 @@ interface ImportMetaEnv {
readonly VITE_BUGS_URL: string readonly VITE_BUGS_URL: string
readonly VITE_DOCS_URL: string readonly VITE_DOCS_URL: string
readonly VIET_LEARN_URL: string readonly VIET_LEARN_URL: string
readonly VITE_LATEST_FIRMWARE: string
} }
interface ImportMeta { interface ImportMeta {

View File

@@ -17,10 +17,9 @@ const de = {
RELOAD: "Neu laden", RELOAD: "Neu laden",
}, },
backup: { backup: {
TITLE: "Verlauf speichern", TITLE: "Lokale Kopie",
INDIVIDUAL: "Einzeldateien", INDIVIDUAL: "Einzeldateien",
DISCLAIMER: DISCLAIMER: "Das Backup in diesem Browser gespeichert und bleibt nur auf diesem Computer.",
"Der Verlauf wird als Backup in diesem Browser gespeichert. Der Verlauf bleibt auf diesem Computer.",
DOWNLOAD: "Alles herunterladen", DOWNLOAD: "Alles herunterladen",
RESTORE: "Wiederherstellen", RESTORE: "Wiederherstellen",
}, },

View File

@@ -12,9 +12,9 @@ const en = {
TITLE: "Update your device", TITLE: "Update your device",
}, },
backup: { backup: {
TITLE: "Store History", TITLE: "Local backup",
INDIVIDUAL: "Individual backups", INDIVIDUAL: "Individual backups",
DISCLAIMER: "Your history is stored as a backup in this browser. The history remains on your computer.", DISCLAIMER: "A backup is made and stored in this browser, and always remains only on your computer.",
DOWNLOAD: "Download Everything", DOWNLOAD: "Download Everything",
RESTORE: "Restore", RESTORE: "Restore",
}, },

View File

@@ -6,41 +6,49 @@ actions:
id: "LEFT_CTRL" id: "LEFT_CTRL"
display: CTRL display: CTRL
title: Control Keyboard Modifier title: Control Keyboard Modifier
keyCode: ControlLeft
variant: left variant: left
513: &left_shift 513: &left_shift
id: "LEFT_SHIFT" id: "LEFT_SHIFT"
title: Shift Keyboard Modifier title: Shift Keyboard Modifier
keyCode: ShiftLeft
variant: left variant: left
icon: shift icon: shift
514: &left_alt 514: &left_alt
id: "LEFT_ALT" id: "LEFT_ALT"
display: ALT display: ALT
title: Alt Keyboard Modifier title: Alt Keyboard Modifier
keyCode: AltLeft
variant: left variant: left
515: &left_gui 515: &left_gui
id: "LEFT_GUI" id: "LEFT_GUI"
title: GUI Keyboard Modifier title: GUI Keyboard Modifier
keyCode: MetaLeft
icon: apps icon: apps
variant: left variant: left
516: 516:
variationOf: 512 variationOf: 512
<<: *left_ctrl <<: *left_ctrl
id: "RIGHT_CTRL" id: "RIGHT_CTRL"
keyCode: ControlRight
variant: right variant: right
517: 517:
variationOf: 513 variationOf: 513
<<: *left_shift <<: *left_shift
id: "RIGHT_SHIFT" id: "RIGHT_SHIFT"
keyCode: ShiftRight
variant: right variant: right
518: 518:
variationOf: 514 variationOf: 514
<<: *left_alt <<: *left_alt
id: "RIGHT_ALT" id: "RIGHT_ALT"
keyCode: AltRight
variant: right variant: right
519: 519:
variationOf: 515 variationOf: 515
<<: *left_gui <<: *left_gui
id: "RIGHT_GUI" id: "RIGHT_GUI"
keyCode: MetaRight
variant: right variant: right
520: 520:
id: "RELEASE_MOD" id: "RELEASE_MOD"

View File

@@ -920,35 +920,27 @@ actions:
description: Not required to be supported by any OS description: Not required to be supported by any OS
480: 480:
id: "KSC_E0" id: "KSC_E0"
keyCode: "ControlLeft"
title: Keyboard Left Control title: Keyboard Left Control
481: 481:
id: "KSC_E1" id: "KSC_E1"
keyCode: "ShiftLeft"
title: Keyboard Left Shift title: Keyboard Left Shift
482: 482:
id: "KSC_E2" id: "KSC_E2"
keyCode: "AltLeft"
title: Keyboard Left Alt title: Keyboard Left Alt
483: 483:
id: "KSC_E3" id: "KSC_E3"
keyCode: "MetaLeft"
title: Keyboard Left GUI title: Keyboard Left GUI
484: 484:
id: "KSC_E4" id: "KSC_E4"
keyCode: "ControlRight"
title: Keyboard Right Control title: Keyboard Right Control
485: 485:
id: "KSC_E5" id: "KSC_E5"
keyCode: "ShiftRight"
title: Keyboard Right Shift title: Keyboard Right Shift
486: 486:
id: "KSC_E6" id: "KSC_E6"
keyCode: "AltRight"
title: Keyboard Right Alt title: Keyboard Right Alt
487: 487:
id: "KSC_E7" id: "KSC_E7"
keyCode: "MetaRight"
title: Keyboard Right GUI title: Keyboard Right GUI
488: 488:
id: "KSC_E8" id: "KSC_E8"

View File

@@ -61,7 +61,6 @@ export async function restoreBackup(event: Event) {
} else if (isCsvChords(text)) { } else if (isCsvChords(text)) {
restoreFromFile(csvChordsToJson(text)) restoreFromFile(csvChordsToJson(text))
} else { } else {
alert("Unknown backup format")
} }
} }

View File

@@ -48,9 +48,7 @@ export function deserializeActions(native: bigint): number[] {
const actions = [] const actions = []
for (let i = 0; i < 12; i++) { for (let i = 0; i < 12; i++) {
const action = Number(native & 0x3ffn) const action = Number(native & 0x3ffn)
if (action !== 0) { actions.push(action)
actions.push(action)
}
native >>= 10n native >>= 10n
} }

View File

@@ -244,7 +244,7 @@ export class CharaDevice {
async deleteChord(chord: Pick<Chord, "actions">) { async deleteChord(chord: Pick<Chord, "actions">) {
const status = await this.send(`CML C4 ${stringifyChordActions(chord.actions)}`) const status = await this.send(`CML C4 ${stringifyChordActions(chord.actions)}`)
console.log(status) console.log(status)
if (status.at(-1) !== "2") throw new Error(`Failed with status ${status}`) if (status.at(-1) !== "2" && status.at(-1) !== "0") throw new Error(`Failed with status ${status}`)
} }
/** /**

View File

@@ -33,7 +33,3 @@ export const KEYMAP_IDS: Map<string, KeyInfo> = new Map(
), ),
).filter(([id]) => id !== undefined), ).filter(([id]) => id !== undefined),
) )
export const specialKeycodes = new Map([
[" ", 32], // Space
])

View File

@@ -9,7 +9,6 @@ export const setting: Action<HTMLInputElement, {id: number; inverse?: number; sc
const type = node.getAttribute("type") as "number" | "checkbox" const type = node.getAttribute("type") as "number" | "checkbox"
const min = node.hasAttribute("min") ? Number(node.getAttribute("min")) : undefined const min = node.hasAttribute("min") ? Number(node.getAttribute("min")) : undefined
const max = node.hasAttribute("max") ? Number(node.getAttribute("max")) : undefined const max = node.hasAttribute("max") ? Number(node.getAttribute("max")) : undefined
console.log(min, max, "|", id, "|", node.getAttribute("min"), node.getAttribute("max"))
const unsubscribe = settings.subscribe(async settings => { const unsubscribe = settings.subscribe(async settings => {
if (id in settings) { if (id in settings) {

View File

@@ -4,6 +4,7 @@
import {slide, fade} from "svelte/transition" import {slide, fade} from "svelte/transition"
import {preference} from "$lib/preferences" import {preference} from "$lib/preferences"
import LL from "../i18n/i18n-svelte" import LL from "../i18n/i18n-svelte"
import {downloadBackup} from "$lib/backup/backup"
function reboot() { function reboot() {
$serialPort?.reboot() $serialPort?.reboot()
@@ -15,6 +16,7 @@
} }
function bootloader() { function bootloader() {
downloadBackup()
$serialPort?.bootloader() $serialPort?.bootloader()
$serialPort = undefined $serialPort = undefined
rebootInfo = true rebootInfo = true
@@ -51,6 +53,11 @@
<br /> <br />
Version {$serialPort.version} Version {$serialPort.version}
</p> </p>
{#if $serialPort.version.toString() !== import.meta.env.VITE_LATEST_FIRMWARE}
<a href="https://docs.charachorder.com/CharaChorder%20One.html#updating-the-firmware"
>Firmware Update Instructions</a
>
{/if}
<!--<button on:click={updateFirmware}>Update</button>--> <!--<button on:click={updateFirmware}>Update</button>-->
{/if} {/if}

View File

@@ -28,7 +28,12 @@
function keydown(event: KeyboardEvent) { function keydown(event: KeyboardEvent) {
if (!editing) return if (!editing) return
event.preventDefault() event.preventDefault()
pressedKeys.add(inputToAction(event, get(serialPort)?.device === "X")!) const input = inputToAction(event, get(serialPort)?.device === "X")
if (input == undefined) {
alert("Invalid key")
return
}
pressedKeys.add(input)
pressedKeys = pressedKeys pressedKeys = pressedKeys
} }
@@ -61,12 +66,19 @@
}) })
}) })
} }
$: chordActions = chord?.actions.slice(chord.actions.lastIndexOf(0) + 1).toSorted(compare)
$: compoundIndices = chord?.actions.slice(0, chord.actions.indexOf(0))
$: {
console.log(chord?.actions, chordActions, compoundIndices)
}
</script> </script>
<button <button
class:deleted={chord && chord.deleted} class:deleted={chord && chord.deleted}
class:edited={chord && chord.actionsChanged} class:edited={chord && chord.actionsChanged}
class:invalid={chord && chord.actions.toSorted(compare).some((it, i) => chord?.actions[i] !== it)} class:invalid={chord && chordActions?.some((it, i) => chordActions?.[i] !== it)}
class="chord" class="chord"
on:click={edit} on:click={edit}
on:keydown={keydown} on:keydown={keydown}
@@ -77,7 +89,15 @@
{:else if !editing && !chord} {:else if !editing && !chord}
<span>{$LL.configure.chords.NEW_CHORD()}</span> <span>{$LL.configure.chords.NEW_CHORD()}</span>
{/if} {/if}
<ActionString display="keys" actions={editing ? [...pressedKeys].sort(compare) : chord?.actions ?? []} /> {#if !editing}
{#each compoundIndices ?? [] as index}
<sub>{index}</sub>
{/each}
{#if compoundIndices?.length}
<span>&rarr;</span>
{/if}
{/if}
<ActionString display="keys" actions={editing ? [...pressedKeys].sort(compare) : chordActions ?? []} />
<button class="icon add" on:click|stopPropagation={addSpecial}>add_circle</button> <button class="icon add" on:click|stopPropagation={addSpecial}>add_circle</button>
<sup></sup> <sup></sup>
</button> </button>

View File

@@ -1,7 +1,5 @@
<script lang="ts"> <script lang="ts">
import {KEYMAP_IDS, specialKeycodes} from "$lib/serial/keymap-codes"
import {tick} from "svelte" import {tick} from "svelte"
import ActionSelector from "$lib/components/layout/ActionSelector.svelte"
import {changes, ChangeType} from "$lib/undo-redo" import {changes, ChangeType} from "$lib/undo-redo"
import type {ChordInfo} from "$lib/undo-redo" import type {ChordInfo} from "$lib/undo-redo"
import {scale} from "svelte/transition" import {scale} from "svelte/transition"
@@ -26,6 +24,7 @@
} else if (event.key === "Delete") { } else if (event.key === "Delete") {
deleteAction(cursorPosition) deleteAction(cursorPosition)
} else { } else {
if (event.key === "Shift") return
const action = inputToAction(event, get(serialPort)?.device === "X") const action = inputToAction(event, get(serialPort)?.device === "X")
if (action !== undefined) { if (action !== undefined) {
insertAction(cursorPosition, action) insertAction(cursorPosition, action)

View File

@@ -1,9 +1,9 @@
import {KEYMAP_IDS, KEYMAP_KEYCODES, specialKeycodes} from "$lib/serial/keymap-codes" import {KEYMAP_IDS, KEYMAP_KEYCODES} from "$lib/serial/keymap-codes"
export function inputToAction(event: KeyboardEvent, useKeycodes?: boolean): number | undefined { export function inputToAction(event: KeyboardEvent, useKeycodes?: boolean): number | undefined {
if (useKeycodes) { if (useKeycodes) {
return KEYMAP_KEYCODES.get(event.code) return KEYMAP_KEYCODES.get(event.code)
} else { } else {
return KEYMAP_IDS.get(event.key)?.code ?? specialKeycodes.get(event.key) return KEYMAP_IDS.get(event.key)?.code ?? KEYMAP_KEYCODES.get(event.code)
} }
} }

View File

@@ -17,6 +17,7 @@ process.env.VITE_HOMEPAGE_URL = repository.url.replace(/\.git$/, "")
process.env.VITE_DOCS_URL = homepage process.env.VITE_DOCS_URL = homepage
process.env.VITE_BUGS_URL = bugs.url process.env.VITE_BUGS_URL = bugs.url
process.env.VITE_LEARN_URL = "https://www.iq-eq.io/" process.env.VITE_LEARN_URL = "https://www.iq-eq.io/"
process.env.VITE_LATEST_FIRMWARE = "1.1.3"
export default defineConfig({ export default defineConfig({
build: { build: {