Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 14 additions & 18 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
module.exports = {
root: true,
env: { browser: true, es2020: true },
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:react-hooks/recommended',
],
ignorePatterns: ['dist', '.eslintrc.cjs'],
parser: '@typescript-eslint/parser',
plugins: ['react-refresh'],
rules: {
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true },
],
},
}

root: true,
env: { browser: true, es2020: true },
extends: [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:react-hooks/recommended",
],
ignorePatterns: ["dist", ".eslintrc.cjs"],
parser: "@typescript-eslint/parser",
plugins: ["react-refresh"],
rules: {
"react-refresh/only-export-components": ["warn", { allowConstantExport: true }],
},
};
52 changes: 26 additions & 26 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,32 @@ logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-electron
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
release/**
*.kiro/
# npx electron-builder --mac --win
.tmp/
.history/
*.tsbuildinfo
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-electron
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
release/**
*.kiro/
# npx electron-builder --mac --win
.tmp/
.history/
*.tsbuildinfo
vite.config.js
vite.config.d.ts

Expand Down
1 change: 0 additions & 1 deletion biome.json
Original file line number Diff line number Diff line change
Expand Up @@ -162,4 +162,3 @@
"actions": { "source": { "organizeImports": "on" } }
}
}

41 changes: 20 additions & 21 deletions components.json
Original file line number Diff line number Diff line change
@@ -1,23 +1,22 @@
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "new-york",
"rsc": false,
"tsx": true,
"tailwind": {
"config": "tailwind.config.cjs",
"css": "src/index.css",
"baseColor": "stone",
"cssVariables": true,
"prefix": ""
},
"iconLibrary": "lucide",
"aliases": {
"components": "@/components",
"utils": "@/lib/utils",
"ui": "@/components/ui",
"lib": "@/lib",
"hooks": "@/hooks"
},
"registries": {}
"$schema": "https://ui.shadcn.com/schema.json",
"style": "new-york",
"rsc": false,
"tsx": true,
"tailwind": {
"config": "tailwind.config.cjs",
"css": "src/index.css",
"baseColor": "stone",
"cssVariables": true,
"prefix": ""
},
"iconLibrary": "lucide",
"aliases": {
"components": "@/components",
"utils": "@/lib/utils",
"ui": "@/components/ui",
"lib": "@/lib",
"hooks": "@/hooks"
},
"registries": {}
}

2 changes: 1 addition & 1 deletion electron/appPaths.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ if (process.env["VITE_DEV_SERVER_URL"]) {
}

export const USER_DATA_PATH = app.getPath("userData");
export const RECORDINGS_DIR = path.join(USER_DATA_PATH, "recordings");
export const RECORDINGS_DIR = path.join(USER_DATA_PATH, "recordings");
148 changes: 75 additions & 73 deletions electron/cursorHider.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { spawnSync } from 'node:child_process'
import { spawnSync } from "node:child_process";

const PY_HIDE_WIN = `
import ctypes, sys
Expand All @@ -25,7 +25,7 @@ for _ in range(32):
user32.ShowCursor(False)

sys.exit(0)
`.trim()
`.trim();

const PY_SHOW_WIN = `
import ctypes, sys
Expand All @@ -52,90 +52,92 @@ for _ in range(32):
user32.ShowCursor(True)

sys.exit(0)
`.trim()
`.trim();

function getPowerShellCommand(show: boolean) {
const desiredFlag = show ? 1 : 0
const showLiteral = show ? '$true' : '$false'

return [
'$signature = @"',
'using System;',
'using System.Runtime.InteropServices;',
'public struct POINT { public int X; public int Y; }',
'public struct CURSORINFO { public int cbSize; public int flags; public IntPtr hCursor; public POINT ptScreenPos; }',
'public static class CursorNative {',
' [DllImport("user32.dll")] public static extern int ShowCursor(bool show);',
' [DllImport("user32.dll")] public static extern bool GetCursorInfo(ref CURSORINFO info);',
'}',
'"@;',
'Add-Type -TypeDefinition $signature -Language CSharp -ErrorAction SilentlyContinue | Out-Null;',
'$info = New-Object CURSORINFO;',
'$info.cbSize = [Runtime.InteropServices.Marshal]::SizeOf([type]CURSORINFO);',
'for ($i = 0; $i -lt 32; $i++) {',
' if ([CursorNative]::GetCursorInfo([ref]$info) -and (($info.flags -band 1) -eq ' + desiredFlag + ')) { exit 0 }',
' [CursorNative]::ShowCursor(' + showLiteral + ') | Out-Null;',
'}',
'exit 0',
].join(' ')
const desiredFlag = show ? 1 : 0;
const showLiteral = show ? "$true" : "$false";

return [
'$signature = @"',
"using System;",
"using System.Runtime.InteropServices;",
"public struct POINT { public int X; public int Y; }",
"public struct CURSORINFO { public int cbSize; public int flags; public IntPtr hCursor; public POINT ptScreenPos; }",
"public static class CursorNative {",
' [DllImport("user32.dll")] public static extern int ShowCursor(bool show);',
' [DllImport("user32.dll")] public static extern bool GetCursorInfo(ref CURSORINFO info);',
"}",
'"@;',
"Add-Type -TypeDefinition $signature -Language CSharp -ErrorAction SilentlyContinue | Out-Null;",
"$info = New-Object CURSORINFO;",
"$info.cbSize = [Runtime.InteropServices.Marshal]::SizeOf([type]CURSORINFO);",
"for ($i = 0; $i -lt 32; $i++) {",
" if ([CursorNative]::GetCursorInfo([ref]$info) -and (($info.flags -band 1) -eq " +
desiredFlag +
")) { exit 0 }",
" [CursorNative]::ShowCursor(" + showLiteral + ") | Out-Null;",
"}",
"exit 0",
].join(" ");
}

function runPythonSnippet(code: string) {
for (const executable of ['python', 'python3', 'py']) {
const result = spawnSync(executable, ['-c', code], { timeout: 5000 })
if (!result.error && result.status === 0) {
return true
}
}

return false
for (const executable of ["python", "python3", "py"]) {
const result = spawnSync(executable, ["-c", code], { timeout: 5000 });
if (!result.error && result.status === 0) {
return true;
}
}

return false;
}

function runPowerShellSnippet(command: string) {
const result = spawnSync(
'powershell.exe',
['-NoProfile', '-NonInteractive', '-WindowStyle', 'Hidden', '-Command', command],
{ timeout: 8000 },
)
const result = spawnSync(
"powershell.exe",
["-NoProfile", "-NonInteractive", "-WindowStyle", "Hidden", "-Command", command],
{ timeout: 8000 },
);

return !result.error && result.status === 0
return !result.error && result.status === 0;
}

let cursorHidden = false
let cursorHidden = false;

export function hideCursor() {
if (process.platform !== 'win32' || cursorHidden) {
return false
}

try {
const didHide = runPythonSnippet(PY_HIDE_WIN)
|| runPowerShellSnippet(getPowerShellCommand(false))

if (didHide) {
cursorHidden = true
}

return didHide
} catch (error) {
console.error('[cursorHider] Failed to hide Windows cursor:', error)
return false
}
if (process.platform !== "win32" || cursorHidden) {
return false;
}

try {
const didHide =
runPythonSnippet(PY_HIDE_WIN) || runPowerShellSnippet(getPowerShellCommand(false));

if (didHide) {
cursorHidden = true;
}

return didHide;
} catch (error) {
console.error("[cursorHider] Failed to hide Windows cursor:", error);
return false;
}
}

export function showCursor() {
if (process.platform !== 'win32' || !cursorHidden) {
return false
}

try {
const didShow = runPythonSnippet(PY_SHOW_WIN)
|| runPowerShellSnippet(getPowerShellCommand(true))
return didShow
} catch (error) {
console.error('[cursorHider] Failed to show Windows cursor:', error)
return false
} finally {
cursorHidden = false
}
}
if (process.platform !== "win32" || !cursorHidden) {
return false;
}

try {
const didShow =
runPythonSnippet(PY_SHOW_WIN) || runPowerShellSnippet(getPowerShellCommand(true));
return didShow;
} catch (error) {
console.error("[cursorHider] Failed to show Windows cursor:", error);
return false;
} finally {
cursorHidden = false;
}
}
Loading