ubuntu not working. idk I'm just gonna use windows anyway
This commit is contained in:
+31
-7
@@ -113,8 +113,13 @@ function hasBinary(name) {
|
||||
// Treating it as "available" would leave the session with no click capture AND
|
||||
// no interval fallback, so zero steps get captured.
|
||||
function isWayland() {
|
||||
return process.platform === 'linux'
|
||||
&& (process.env.XDG_SESSION_TYPE === 'wayland' || Boolean(process.env.WAYLAND_DISPLAY));
|
||||
if (process.platform !== 'linux') return false;
|
||||
// XDG_SESSION_TYPE is the authoritative session hint when present. Some
|
||||
// desktops still export WAYLAND_DISPLAY even when the active session is X11,
|
||||
// so only fall back to it when XDG_SESSION_TYPE is unavailable.
|
||||
const sessionType = String(process.env.XDG_SESSION_TYPE || '').toLowerCase();
|
||||
if (sessionType) return sessionType === 'wayland';
|
||||
return Boolean(process.env.WAYLAND_DISPLAY);
|
||||
}
|
||||
|
||||
// ---- evdev (Linux kernel input) click reader --------------------------------
|
||||
@@ -263,6 +268,16 @@ class CaptureService {
|
||||
return this.settings.get('capture.strictClickFrames') !== false;
|
||||
}
|
||||
|
||||
fallbackCaptureTrigger() {
|
||||
const raw = String(this.settings.get('capture.fallbackTrigger') || 'interval').toLowerCase();
|
||||
return raw === 'hotkey' ? 'hotkey' : 'interval';
|
||||
}
|
||||
|
||||
fallbackIntervalSec() {
|
||||
const raw = Number(this.settings.get('capture.autoIntervalSec'));
|
||||
return Number.isFinite(raw) && raw > 0 ? raw : 5;
|
||||
}
|
||||
|
||||
clickCaptureAvailable() {
|
||||
if (this._clickAvail === undefined) {
|
||||
// Three click sources, in order of fidelity:
|
||||
@@ -296,12 +311,19 @@ class CaptureService {
|
||||
|
||||
startSession(guideId, { intervalSec = null } = {}) {
|
||||
this.finishSession();
|
||||
// Default trigger: clicks when the platform supports it, otherwise an
|
||||
// interval so a session always produces steps even if the global hotkey
|
||||
// never fires (common under Wayland/WSLg).
|
||||
// Default trigger: clicks when the platform supports it, otherwise the
|
||||
// user-selected fallback (timer or hotkey-only). That keeps Linux from
|
||||
// silently dropping into an unwanted 5-second timer when click capture
|
||||
// is unavailable.
|
||||
let interval = intervalSec;
|
||||
if (interval == null) {
|
||||
interval = this.clickCaptureAvailable() ? 0 : (this.settings.get('capture.autoIntervalSec') || 5);
|
||||
if (this.clickCaptureAvailable()) {
|
||||
interval = 0;
|
||||
} else if (this.fallbackCaptureTrigger() === 'hotkey') {
|
||||
interval = 0;
|
||||
} else {
|
||||
interval = this.fallbackIntervalSec();
|
||||
}
|
||||
}
|
||||
// Sessions start paused: nothing hides and no capturing happens until
|
||||
// the user explicitly presses "Start recording" in the capture bar, so
|
||||
@@ -1381,7 +1403,9 @@ public static class SFHook {
|
||||
console.error(`[stepforge] click watcher stopped${detail ? `: ${detail}` : ''}`);
|
||||
if (!this.session) return;
|
||||
if (!this.session.intervalSec) {
|
||||
this.session.intervalSec = this.settings.get('capture.autoIntervalSec') || 5;
|
||||
this.session.intervalSec = this.fallbackCaptureTrigger() === 'hotkey'
|
||||
? 0
|
||||
: this.fallbackIntervalSec();
|
||||
this.applyInterval();
|
||||
}
|
||||
this.notify('capture:state', this.state());
|
||||
|
||||
@@ -122,6 +122,7 @@ class StepForgeApp {
|
||||
api.library.trashList(),
|
||||
]);
|
||||
this.state.info = info;
|
||||
document.body.classList.toggle('platform-linux', info.platform === 'linux');
|
||||
this.state.settings = settings;
|
||||
this.state.library = {
|
||||
guides: library.guides || [],
|
||||
|
||||
@@ -312,6 +312,11 @@ function showSettingsDialog({
|
||||
const previewCount = makeInput(settings.exports?.previewStepCount ?? 3, 'number', { min: 1, step: 1 });
|
||||
const openFolder = el('input', { type: 'checkbox', checked: Boolean(settings.exports?.openFolderAfterExport) });
|
||||
const captureOutside = el('input', { type: 'checkbox', checked: Boolean(settings.capture?.captureOutsideClicks) });
|
||||
const fallbackTrigger = makeSelect(settings.capture?.fallbackTrigger || 'interval', [
|
||||
{ value: 'interval', label: 'Timed interval' },
|
||||
{ value: 'hotkey', label: 'Hotkey only' },
|
||||
]);
|
||||
const autoIntervalSec = makeInput(settings.capture?.autoIntervalSec ?? 5, 'number', { min: 1, step: 1 });
|
||||
const confirmSimple = el('input', { type: 'checkbox', checked: Boolean(settings.capture?.confirmSimpleCapture) });
|
||||
const keepLast = makeInput(settings.backups?.keepLast ?? 10, 'number', { min: 0, step: 1 });
|
||||
const aiEnabled = el('input', { type: 'checkbox', checked: Boolean(settings.ai?.enabled) });
|
||||
@@ -326,6 +331,12 @@ function showSettingsDialog({
|
||||
void api.settings.set({ keyPath: 'ai.ollama.model', value: model }).catch(() => {});
|
||||
}, 250);
|
||||
|
||||
const syncFallbackUi = () => {
|
||||
autoIntervalSec.disabled = fallbackTrigger.value === 'hotkey';
|
||||
};
|
||||
fallbackTrigger.addEventListener('change', syncFallbackUi);
|
||||
syncFallbackUi();
|
||||
|
||||
const updateAiStatus = (message, { error = false } = {}) => {
|
||||
aiStatus.textContent = message;
|
||||
aiStatus.classList.toggle('error', Boolean(error));
|
||||
@@ -403,9 +414,14 @@ function showSettingsDialog({
|
||||
labeledRow('Delay (ms)', delayMs),
|
||||
labeledRow('Click marker', clickMarker),
|
||||
labeledRow('Capture outside clicks', captureOutside),
|
||||
labeledRow('When clicks are unavailable', fallbackTrigger),
|
||||
labeledRow('Timer interval (seconds)', autoIntervalSec),
|
||||
labeledRow('Confirm simple capture', confirmSimple),
|
||||
labeledRow('Capture hotkey', captureHotkey),
|
||||
labeledRow('Pause / resume hotkey', pauseHotkey),
|
||||
el('div.muted', {},
|
||||
'Hotkey fallback uses the Capture hotkey. Timer fallback uses the interval above.',
|
||||
),
|
||||
),
|
||||
el('fieldset', {},
|
||||
el('legend', {}, 'Editor'),
|
||||
@@ -455,6 +471,8 @@ function showSettingsDialog({
|
||||
delayMs: Number(delayMs.value || 0),
|
||||
mode: captureMode.value,
|
||||
clickMarker: clickMarker.checked,
|
||||
fallbackTrigger: fallbackTrigger.value === 'hotkey' ? 'hotkey' : 'interval',
|
||||
autoIntervalSec: Math.max(1, Number(autoIntervalSec.value || 5)),
|
||||
hotkeyCapture: captureHotkey.value.trim(),
|
||||
hotkeyPauseResume: pauseHotkey.value.trim(),
|
||||
captureOutsideClicks: captureOutside.checked,
|
||||
|
||||
@@ -49,6 +49,16 @@ body {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
body.platform-linux button {
|
||||
padding: 5px 11px;
|
||||
}
|
||||
|
||||
body.platform-linux input,
|
||||
body.platform-linux select,
|
||||
body.platform-linux textarea {
|
||||
padding: 6px 9px;
|
||||
}
|
||||
|
||||
*::selection { background: rgba(0, 104, 255, 0.2); }
|
||||
|
||||
#app { display: flex; flex-direction: column; height: 100vh; }
|
||||
@@ -183,6 +193,21 @@ kbd {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
body.platform-linux #topbar {
|
||||
height: 52px;
|
||||
gap: 10px;
|
||||
padding: 0 14px;
|
||||
}
|
||||
|
||||
body.platform-linux #capture-status {
|
||||
padding: 5px 9px;
|
||||
gap: 7px;
|
||||
}
|
||||
|
||||
body.platform-linux #capture-status button {
|
||||
padding: 2px 7px;
|
||||
}
|
||||
|
||||
.library, .editor { flex: 1; min-height: 0; display: flex; }
|
||||
|
||||
.lib-side {
|
||||
|
||||
Reference in New Issue
Block a user