UI improvements, prepare for config overriding

This commit is contained in:
Nik Rozman
2026-03-03 08:34:43 +01:00
parent 5c9aa62cda
commit 8f63d7c0b5
3 changed files with 37 additions and 20 deletions

View File

@@ -11,7 +11,7 @@ const CHR = {
// Local shadow of the current config (kept in sync with device)
const config = { sensitivity:600, deadZone:0.06, accelStrength:0.08, curve:0, axisFlip:0, chargeMode:1,
tapThreshold:12, tapAction:0, tapKey:0, tapMod:0, jerkThreshold:2000 };
tapThreshold:12, tapAction:0, tapKey:0, tapMod:0, tapFreezeEnabled:1, jerkThreshold:2000 };
let device=null, server=null, chars={}, userDisconnected=false;
let currentChargeStatus=0, currentBattPct=null, currentBattVoltage=null;
@@ -200,10 +200,11 @@ async function checkHashMatch() {
}
// ── ConfigBlob read / write ──────────────────────────────────────────────────
// ConfigBlob layout (20 bytes LE):
// ConfigBlob layout (24 bytes LE):
// float sensitivity [0], float deadZone [4], float accelStrength [8]
// uint8 curve [12], uint8 axisFlip [13], uint8 chargeMode [14]
// uint8 tapThreshold [15], uint8 tapAction [16], uint8 tapKey [17], uint8 tapMod [18], uint8 pad [19]
// uint8 tapThreshold [15], uint8 tapAction [16], uint8 tapKey [17], uint8 tapMod [18], uint8 tapFreezeEnabled [19]
// float jerkThreshold [20]
async function readConfigBlob() {
if (!chars.configBlob) return;
@@ -217,10 +218,11 @@ async function readConfigBlob() {
config.axisFlip = view.getUint8(13);
config.chargeMode = view.getUint8(14);
if (view.byteLength >= 20) {
config.tapThreshold = view.getUint8(15);
config.tapAction = view.getUint8(16);
config.tapKey = view.getUint8(17);
config.tapMod = view.getUint8(18);
config.tapThreshold = view.getUint8(15);
config.tapAction = view.getUint8(16);
config.tapKey = view.getUint8(17);
config.tapMod = view.getUint8(18);
config.tapFreezeEnabled = view.getUint8(19);
}
if (view.byteLength >= 24) {
config.jerkThreshold = view.getFloat32(20, true);
@@ -241,8 +243,10 @@ function applyConfigToUI() {
document.getElementById('flipX').checked = !!(config.axisFlip & 1);
document.getElementById('flipY').checked = !!(config.axisFlip & 2);
setChargeModeUI(config.chargeMode);
document.getElementById('tapFreezeEnabled').checked = !!config.tapFreezeEnabled;
document.getElementById('slJerkThreshold').value = config.jerkThreshold;
updateDisplay('jerkThreshold', config.jerkThreshold);
updateTapFreezeUI(!!config.tapFreezeEnabled);
document.getElementById('slTapThreshold').value = config.tapThreshold;
updateDisplay('tapThreshold', config.tapThreshold);
setTapActionUI(config.tapAction);
@@ -272,6 +276,7 @@ async function _doWriteConfigBlob() {
| (document.getElementById('tapModShift').checked ? 0x02 : 0)
| (document.getElementById('tapModAlt').checked ? 0x04 : 0)
| (document.getElementById('tapModGui').checked ? 0x08 : 0);
config.tapFreezeEnabled = document.getElementById('tapFreezeEnabled').checked ? 1 : 0;
config.jerkThreshold = +document.getElementById('slJerkThreshold').value;
// config.curve, config.chargeMode, config.tapAction, config.tapKey updated directly
@@ -287,7 +292,7 @@ async function _doWriteConfigBlob() {
view.setUint8(16, config.tapAction);
view.setUint8(17, config.tapKey);
view.setUint8(18, config.tapMod);
view.setUint8(19, 0);
view.setUint8(19, config.tapFreezeEnabled);
view.setFloat32(20, config.jerkThreshold, true);
try {
@@ -325,6 +330,17 @@ function setChargeModeUI(val) {
document.getElementById('ciMode').textContent = ['Off (0mA)','50 mA','100 mA'][val] ?? '--';
}
function onTapFreezeChange(enabled) {
config.tapFreezeEnabled = enabled ? 1 : 0;
updateTapFreezeUI(enabled);
writeConfigBlob();
}
function updateTapFreezeUI(enabled) {
const slider = document.getElementById('slJerkThreshold');
// Only grey out when connected (on disconnect, setStatus handles all inputs)
if (device) slider.disabled = !enabled;
}
function setTapAction(val) {
config.tapAction = val;
setTapActionUI(val);
@@ -820,12 +836,12 @@ let orientLastT = 0;
function initOrientViewer() {
const el = document.getElementById('orientCanvas');
const W = el.clientWidth || 340, H = 160;
const W = el.clientWidth || 340, H = el.clientHeight || W;
el.width = W; el.height = H;
orientScene = new THREE.Scene();
orientCamera = new THREE.PerspectiveCamera(40, W / H, 0.01, 10);
orientCamera.position.set(0.6, 0.5, 0.9);
orientCamera = new THREE.PerspectiveCamera(55, W / H, 0.01, 10);
orientCamera.position.set(0.75, 0.60, 1.10);
orientCamera.lookAt(0, 0, 0);
orientRenderer = new THREE.WebGLRenderer({ canvas: el, antialias: true, alpha: true });

View File

@@ -32,6 +32,8 @@
<button class="btn btn-disconnect" id="disconnectBtn" onclick="doDisconnect()" style="display:none"><span>Disconnect</span></button>
<label class="toggle" title="Auto-Reconnect" style="margin-left:6px;flex-shrink:0"><input type="checkbox" id="autoReconnect"><div class="toggle-track"></div><div class="toggle-thumb"></div></label>
<span style="font-family:var(--mono);font-size:9px;color:var(--label);white-space:nowrap">AUTO-RECONNECT</span>
<label class="toggle" style="margin-left:10px;flex-shrink:0" title="Advanced"><input type="checkbox" id="advancedToggle" onchange="toggleAdvanced(this.checked)"><div class="toggle-track"></div><div class="toggle-thumb"></div></label>
<span style="font-family:var(--mono);font-size:9px;color:var(--label);white-space:nowrap">ADVANCED</span>
</div>
</header>
@@ -93,14 +95,16 @@
<div class="ci-item"><div class="ci-val" id="ciPct">--%</div><div class="ci-lbl">Level</div></div>
<div class="ci-item ci-advanced" id="ciVoltItem" style="display:none"><div class="ci-val accent" id="ciVolt">--</div><div class="ci-lbl">Voltage</div></div>
</div>
<div class="advanced-row">
<label class="toggle"><input type="checkbox" id="advancedToggle" onchange="toggleAdvanced(this.checked)"><div class="toggle-track"></div><div class="toggle-thumb"></div></label>
<span class="advanced-label">ADVANCED</span>
</div>
</div>
<div class="section-label">Tap Configuration</div>
<div class="card">
<div class="param">
<div><div class="param-label">Tap Freeze</div><div class="param-desc">Freeze cursor during tap impacts (jerk detection)</div></div>
<div style="grid-column:2/4;display:flex;justify-content:flex-end;align-items:center">
<label class="toggle"><input type="checkbox" id="tapFreezeEnabled" onchange="onTapFreezeChange(this.checked)" disabled><div class="toggle-track"></div><div class="toggle-thumb"></div></label>
</div>
</div>
<div class="param">
<div><div class="param-label">Tap Freeze Sensitivity</div><div class="param-desc">Jerk² threshold — lower = more aggressive cursor freeze during taps</div></div>
<input type="range" id="slJerkThreshold" min="500" max="10000" step="100" value="2000"

View File

@@ -110,7 +110,7 @@
.logo-sub { font-size:10px; color:var(--label); letter-spacing:0.25em; text-transform:uppercase; margin-top:3px; }
.header-right { margin-left:auto; display:flex; align-items:center; gap:10px; flex-wrap:wrap; justify-content:flex-end; }
.status-pill { display:flex; align-items:center; gap:8px; padding:6px 12px; border:1px solid var(--border); font-size:11px; letter-spacing:0.15em; text-transform:uppercase; color:var(--label); transition:all 0.3s; white-space:nowrap; }
.status-pill { display:flex; align-items:center; gap:8px; padding:8px 14px; border:1px solid var(--border); font-size:11px; letter-spacing:0.15em; text-transform:uppercase; color:var(--label); transition:all 0.3s; white-space:nowrap; }
.status-pill.connected { border-color:var(--ok); color:var(--ok); }
.status-pill.connecting { border-color:var(--warn); color:var(--warn); }
.dot { width:7px; height:7px; border-radius:50%; background:var(--dim); flex-shrink:0; }
@@ -225,7 +225,7 @@
.viz-header { display:flex; justify-content:space-between; align-items:center; margin-bottom:12px; }
.viz-title { font-family:var(--sans); font-size:11px; font-weight:600; letter-spacing:0.25em; text-transform:uppercase; color:var(--label); }
.orient-card { padding:12px; display:flex; flex-direction:column; align-items:center; }
#orientCanvas { display:block; width:100%; height:160px; }
#orientCanvas { display:block; width:100%; aspect-ratio:1; }
.viz-ctrl-btn { background:none; border:1px solid var(--border); color:var(--label); font-size:11px; line-height:1; padding:3px 8px; cursor:pointer; letter-spacing:0.05em; }
.viz-ctrl-btn:hover { border-color:var(--accent); color:var(--accent); }
.viz-live { font-size:9px; letter-spacing:0.2em; display:block; }
@@ -254,9 +254,6 @@
.ci-val { font-family:var(--sans); font-size:16px; font-weight:700; }
.ci-lbl { font-size:9px; letter-spacing:0.2em; text-transform:uppercase; color:var(--label); margin-top:3px; }
.advanced-row { display:flex; align-items:center; gap:8px; margin-top:10px; justify-content:flex-end; }
.advanced-label { font-family:var(--mono); font-size:9px; color:var(--label); letter-spacing:0.15em; }
.overlay { display:none; position:fixed; inset:0; background:rgba(0,0,0,0.88); z-index:500; align-items:center; justify-content:center; }
.overlay.show { display:flex; }
.modal { background:var(--panel); border:1px solid var(--accent2); padding:28px; max-width:360px; width:100%; }