mirror of
https://github.com/CharaChorder/DeviceManager.git
synced 2026-01-08 11:02:50 +00:00
Compare commits
2 Commits
d91273d27b
...
989e844190
| Author | SHA1 | Date | |
|---|---|---|---|
|
989e844190
|
|||
|
500221f39a
|
@@ -104,6 +104,26 @@ actions:
|
|||||||
<<: *tertiary_keymap
|
<<: *tertiary_keymap
|
||||||
id: "KM_3_R"
|
id: "KM_3_R"
|
||||||
variant: right
|
variant: right
|
||||||
|
558:
|
||||||
|
id: HOLD_COMPOUND
|
||||||
|
title: Activate Chord Library
|
||||||
|
icon: layers
|
||||||
|
description: |
|
||||||
|
When used in a chord includes that chord as a base
|
||||||
|
compound chord for all subsequent chords.
|
||||||
|
This is effectively a library switch.
|
||||||
|
Since library activations can be nested, you
|
||||||
|
usually add a "Reset Chord Library" before this action.
|
||||||
|
559:
|
||||||
|
id: RELEASE_COMPOUND
|
||||||
|
title: Reset Chord Library
|
||||||
|
icon: layers_clear
|
||||||
|
description: |
|
||||||
|
Releases the active compound state, returning
|
||||||
|
to the default library.
|
||||||
|
While "Activate Chord Library" can only be used
|
||||||
|
as an output of a chord, this action can be assigned
|
||||||
|
to switches directly.
|
||||||
576:
|
576:
|
||||||
id: ACTION_DELAY_1000
|
id: ACTION_DELAY_1000
|
||||||
icon: clock_loader_90
|
icon: clock_loader_90
|
||||||
|
|||||||
@@ -55,3 +55,19 @@ export function deserializeActions(native: bigint): number[] {
|
|||||||
|
|
||||||
return actions;
|
return actions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hashes a chord input the same way as CCOS
|
||||||
|
*/
|
||||||
|
export function hashChord(actions: number[]) {
|
||||||
|
const chord = new Uint8Array(16);
|
||||||
|
const view = new DataView(chord.buffer);
|
||||||
|
const serialized = serializeActions(actions);
|
||||||
|
view.setBigUint64(0, serialized & 0xffff_ffff_ffff_ffffn, true);
|
||||||
|
view.setBigUint64(8, serialized >> 64n, true);
|
||||||
|
let hash = 2166136261;
|
||||||
|
for (let i = 0; i < 16; i++) {
|
||||||
|
hash = Math.imul(hash ^ view.getUint8(i), 16777619);
|
||||||
|
}
|
||||||
|
return hash & 0x3fff_ffff;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { persistentWritable } from "$lib/storage";
|
import { persistentWritable } from "$lib/storage";
|
||||||
import { derived } from "svelte/store";
|
import { derived } from "svelte/store";
|
||||||
import type { Chord } from "$lib/serial/chord";
|
import { hashChord, type Chord } from "$lib/serial/chord";
|
||||||
import {
|
import {
|
||||||
deviceChords,
|
deviceChords,
|
||||||
deviceLayout,
|
deviceLayout,
|
||||||
@@ -158,3 +158,9 @@ export const chords = derived([overlay, deviceChords], ([overlay, chords]) => {
|
|||||||
a.localeCompare(b),
|
a.localeCompare(b),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const chordHashes = derived(
|
||||||
|
chords,
|
||||||
|
(chords) =>
|
||||||
|
new Map(chords.map((chord) => [hashChord(chord.actions), chord] as const)),
|
||||||
|
);
|
||||||
|
|||||||
@@ -144,7 +144,6 @@
|
|||||||
progress = i;
|
progress = i;
|
||||||
|
|
||||||
if ("phrase" in chord) {
|
if ("phrase" in chord) {
|
||||||
console.log(encodeChord(chord, osLayout));
|
|
||||||
await index.addAsync(i, encodeChord(chord, osLayout));
|
await index.addAsync(i, encodeChord(chord, osLayout));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { ChordInfo } from "$lib/undo-redo";
|
import type { ChordInfo } from "$lib/undo-redo";
|
||||||
import { changes, ChangeType } from "$lib/undo-redo";
|
import { changes, chordHashes, ChangeType } from "$lib/undo-redo";
|
||||||
import { createEventDispatcher } from "svelte";
|
import { createEventDispatcher } from "svelte";
|
||||||
import LL from "$i18n/i18n-svelte";
|
import LL from "$i18n/i18n-svelte";
|
||||||
import ActionString from "$lib/components/ActionString.svelte";
|
import ActionString from "$lib/components/ActionString.svelte";
|
||||||
@@ -8,6 +8,7 @@
|
|||||||
import { serialPort } from "$lib/serial/connection";
|
import { serialPort } from "$lib/serial/connection";
|
||||||
import { get } from "svelte/store";
|
import { get } from "svelte/store";
|
||||||
import { inputToAction } from "./input-converter";
|
import { inputToAction } from "./input-converter";
|
||||||
|
import { hashChord } from "$lib/serial/chord";
|
||||||
|
|
||||||
export let chord: ChordInfo | undefined = undefined;
|
export let chord: ChordInfo | undefined = undefined;
|
||||||
|
|
||||||
@@ -21,14 +22,15 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function makeChordInput(...actions: number[]) {
|
function makeChordInput(...actions: number[]) {
|
||||||
const compound = compoundIndices ?? [];
|
const compound = compoundInputs[0]
|
||||||
|
? hashChord(compoundInputs[0].actions)
|
||||||
|
: 0;
|
||||||
return [
|
return [
|
||||||
...compound,
|
|
||||||
...Array.from(
|
...Array.from(
|
||||||
{
|
{
|
||||||
length: 12 - (compound.length + actions.length + 1),
|
length: 12 - actions.length,
|
||||||
},
|
},
|
||||||
() => 0,
|
(_, i) => (compound >> (i * 10)) & 0x3ff,
|
||||||
),
|
),
|
||||||
...actions.toSorted(compare),
|
...actions.toSorted(compare),
|
||||||
];
|
];
|
||||||
@@ -73,7 +75,6 @@
|
|||||||
function addSpecial(event: MouseEvent) {
|
function addSpecial(event: MouseEvent) {
|
||||||
selectAction(event, (action) => {
|
selectAction(event, (action) => {
|
||||||
changes.update((changes) => {
|
changes.update((changes) => {
|
||||||
console.log(compoundIndices, chordActions, action);
|
|
||||||
changes.push({
|
changes.push({
|
||||||
type: ChangeType.Chord,
|
type: ChangeType.Chord,
|
||||||
id: chord!.id,
|
id: chord!.id,
|
||||||
@@ -85,10 +86,30 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function* resolveCompound(chord?: ChordInfo) {
|
||||||
|
if (!chord) return;
|
||||||
|
let current = chord;
|
||||||
|
for (let i = 0; i < 10; i++) {
|
||||||
|
if (current.actions[3] !== 0) return;
|
||||||
|
const compound = current.actions
|
||||||
|
.slice(0, 3)
|
||||||
|
.reduce((a, b, i) => a | (b << (i * 10)));
|
||||||
|
if (compound === 0) return;
|
||||||
|
const next = $chordHashes.get(compound);
|
||||||
|
if (!next) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
current = next;
|
||||||
|
yield next;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
$: chordActions = chord?.actions
|
$: chordActions = chord?.actions
|
||||||
.slice(chord.actions.lastIndexOf(0) + 1)
|
.slice(chord.actions.lastIndexOf(0) + 1)
|
||||||
.toSorted(compare);
|
.toSorted(compare);
|
||||||
$: compoundIndices = chord?.actions.slice(0, chord.actions.indexOf(0));
|
$: compoundInputs = [...resolveCompound(chord)].reverse();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
@@ -110,12 +131,15 @@
|
|||||||
<span>{$LL.configure.chords.NEW_CHORD()}</span>
|
<span>{$LL.configure.chords.NEW_CHORD()}</span>
|
||||||
{/if}
|
{/if}
|
||||||
{#if !editing}
|
{#if !editing}
|
||||||
{#each compoundIndices ?? [] as index}
|
{#each compoundInputs as compound}
|
||||||
<sub>{index}</sub>
|
<sub
|
||||||
{/each}
|
><ActionString
|
||||||
{#if compoundIndices?.length}
|
display="keys"
|
||||||
|
actions={compound.actions.slice(compound.actions.lastIndexOf(0) + 1)}
|
||||||
|
></ActionString>
|
||||||
|
</sub>
|
||||||
<span>→</span>
|
<span>→</span>
|
||||||
{/if}
|
{/each}
|
||||||
{/if}
|
{/if}
|
||||||
<ActionString
|
<ActionString
|
||||||
display="keys"
|
display="keys"
|
||||||
|
|||||||
@@ -137,9 +137,6 @@
|
|||||||
if (parent) {
|
if (parent) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
console.log(nodeBefore);
|
|
||||||
|
|
||||||
console.log(context);
|
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user