Skip to content

Commit bc558ad

Browse files
committed
Complete implementation of other platforms with comments and Refactor
1 parent 06a52b1 commit bc558ad

29 files changed

Lines changed: 2324 additions & 647 deletions

src/hooks/useCaptureProvider.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,12 @@ export function useCaptureProvider(wsRef: React.RefObject<WebSocket | null>) {
2727
}
2828
setIsSharing(false)
2929
}
30+
const getConfig = () => ({
31+
sensitivity:
32+
Number.parseFloat(localStorage.getItem("rein_sensitivity") || "1.0") ||
33+
1.0,
34+
invertScroll: localStorage.getItem("rein_invert") === "true" || false,
35+
})
3036

3137
const captureFrame = () => {
3238
if (!videoRef.current || !canvasRef.current || !wsRef.current) return
@@ -103,7 +109,9 @@ export function useCaptureProvider(wsRef: React.RefObject<WebSocket | null>) {
103109
setIsSharing(true)
104110

105111
if (wsRef.current && wsRef.current.readyState === WebSocket.OPEN) {
106-
wsRef.current.send(JSON.stringify({ type: "start-provider" }))
112+
wsRef.current.send(
113+
JSON.stringify({ type: "start-provider", config: getConfig() }),
114+
)
107115
}
108116

109117
// Start capture loop (approx 12 FPS)

src/hooks/useRemoteConnection.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,20 @@ export const useRemoteConnection = () => {
1111
keys: msg,
1212
})
1313
}
14+
const sendConfigUpdate = (sensitivity: number, invertScroll: boolean) => {
15+
send({
16+
type: "update-settings",
17+
config: { sensitivity, invertScroll },
18+
})
19+
}
1420

15-
return { status, platform, send, sendCombo, wsRef, subscribe }
21+
return {
22+
status,
23+
platform,
24+
send,
25+
sendCombo,
26+
sendConfigUpdate,
27+
wsRef,
28+
subscribe,
29+
}
1630
}

src/hooks/useTrackpadGesture.ts

Lines changed: 18 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,4 @@
11
import { useEffect, useRef, useState } from "react"
2-
import {
3-
PINCH_THRESHOLD,
4-
TOUCH_MOVE_THRESHOLD,
5-
TOUCH_TIMEOUT,
6-
calculateAccelerationMult,
7-
} from "../utils/math"
82

93
interface TrackedTouch {
104
identifier: number
@@ -30,8 +24,6 @@ const BUTTON_MAP: Record<number, "left" | "right" | "middle"> = {
3024
export const useTrackpadGesture = (
3125
send: (msg: unknown) => void,
3226
scrollMode: boolean,
33-
sensitivity = 1.5,
34-
invertScroll = false,
3527
axisThreshold = 2.5,
3628
) => {
3729
const [isTracking, setIsTracking] = useState(false)
@@ -43,20 +35,20 @@ export const useTrackpadGesture = (
4335
const releasedCount = useRef(0)
4436
const dragging = useRef(false)
4537
const draggingTimeout = useRef<NodeJS.Timeout | null>(null)
38+
const TOUCH_MOVE_THRESHOLD = [10, 15, 15]
39+
const TOUCH_TIMEOUT = 250
40+
const PINCH_THRESHOLD = 10
4641
const lastPinchDist = useRef<number | null>(null)
4742
const pinching = useRef(false)
4843

4944
const processMovement = (sumX: number, sumY: number) => {
5045
const touchCount = ongoingTouches.current.size
46+
5147
if (dragging.current) {
52-
send({
53-
type: "move",
54-
dx: Math.round(sumX * sensitivity * 10) / 10,
55-
dy: Math.round(sumY * sensitivity * 10) / 10,
56-
})
48+
send({ type: "move", dx: sumX, dy: sumY })
5749
return
5850
}
59-
const invertMult = invertScroll ? -1 : 1
51+
6052
if (!scrollMode && touchCount === 2) {
6153
const touches = Array.from(ongoingTouches.current.values())
6254
const dist = getTouchDistance(touches[0], touches[1])
@@ -65,38 +57,23 @@ export const useTrackpadGesture = (
6557
if (pinching.current || Math.abs(delta) > PINCH_THRESHOLD) {
6658
pinching.current = true
6759
lastPinchDist.current = dist
68-
send({ type: "zoom", delta: delta * sensitivity * invertMult })
60+
send({ type: "zoom", delta })
6961
} else {
7062
lastPinchDist.current = dist
71-
send({
72-
type: "scroll",
73-
dx: -sumX * sensitivity * invertMult,
74-
dy: -sumY * sensitivity * invertMult,
75-
})
63+
send({ type: "scroll", dx: -sumX, dy: -sumY })
7664
}
7765
} else if (scrollMode || touchCount === 2) {
78-
let scrollDx = sumX
79-
let scrollDy = sumY
66+
let dx = sumX,
67+
dy = sumY
8068
if (scrollMode) {
81-
const absDx = Math.abs(scrollDx)
82-
const absDy = Math.abs(scrollDy)
83-
if (absDx > absDy * axisThreshold) {
84-
scrollDy = 0
85-
} else if (absDy > absDx * axisThreshold) {
86-
scrollDx = 0
87-
}
69+
const absDx = Math.abs(dx),
70+
absDy = Math.abs(dy)
71+
if (absDx > absDy * axisThreshold) dy = 0
72+
else if (absDy > absDx * axisThreshold) dx = 0
8873
}
89-
send({
90-
type: "scroll",
91-
dx: Math.round(-scrollDx * sensitivity * 10 * invertMult) / 10,
92-
dy: Math.round(-scrollDy * sensitivity * 10 * invertMult) / 10,
93-
})
74+
send({ type: "scroll", dx: -dx, dy: -dy })
9475
} else if (touchCount === 1) {
95-
send({
96-
type: "move",
97-
dx: Math.round(sumX * sensitivity * 10) / 10,
98-
dy: Math.round(sumY * sensitivity * 10) / 10,
99-
})
76+
send({ type: "move", dx: sumX, dy: sumY })
10077
}
10178
}
10279

@@ -173,18 +150,10 @@ export const useTrackpadGesture = (
173150
moved.current = true
174151
}
175152
}
176-
177-
// Calculate delta with acceleration
178153
const dx = touch.pageX - tracked.pageX
179154
const dy = touch.pageY - tracked.pageY
180-
const timeDelta = e.timeStamp - tracked.timeStamp
181-
182-
if (timeDelta > 0) {
183-
const speedX = (Math.abs(dx) / timeDelta) * 1000
184-
const speedY = (Math.abs(dy) / timeDelta) * 1000
185-
sumX += dx * calculateAccelerationMult(speedX)
186-
sumY += dy * calculateAccelerationMult(speedY)
187-
}
155+
sumX += dx
156+
sumY += dy
188157

189158
// Update tracked position
190159
tracked.pageX = touch.pageX

src/routes/settings.tsx

Lines changed: 37 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { createFileRoute } from "@tanstack/react-router"
22
import QRCode from "qrcode"
3-
import { useEffect, useState } from "react"
3+
import { useEffect, useState, useRef, useMemo } from "react"
44
import { APP_CONFIG, THEMES } from "../config"
55
import serverConfig from "../server-config.json"
6-
6+
import { useRemoteConnection } from "../hooks/useRemoteConnection"
77
export const Route = createFileRoute("/settings")({
88
component: SettingsPage,
99
})
@@ -14,26 +14,26 @@ function SettingsPage() {
1414
String(serverConfig.frontendPort),
1515
)
1616
const [originalPort] = useState(String(serverConfig.frontendPort))
17-
1817
const serverConfigChanged = frontendPort !== originalPort
19-
18+
const sendConfigUpdate = useRemoteConnection().sendConfigUpdate
2019
// Client Side Settings (LocalStorage)
21-
const [invertScroll, setInvertScroll] = useState(() => {
22-
if (typeof window === "undefined") return false
20+
const [initialSensitivity, initialInvert] = (() => {
2321
try {
24-
const saved = localStorage.getItem("rein_invert")
25-
return saved === "true"
22+
const savedSensitivity = localStorage.getItem("rein_sensitivity")
23+
const parsed = savedSensitivity
24+
? Number.parseFloat(savedSensitivity)
25+
: Number.NaN
26+
return [
27+
Number.isFinite(parsed) ? parsed : 1.0,
28+
localStorage.getItem("rein_invert") === "true",
29+
] as const
2630
} catch {
27-
return false
31+
return [1.0, false] as const
2832
}
29-
})
33+
})()
3034

31-
const [sensitivity, setSensitivity] = useState(() => {
32-
if (typeof window === "undefined") return 1.0
33-
const saved = localStorage.getItem("rein_sensitivity")
34-
const parsed = saved ? Number.parseFloat(saved) : Number.NaN
35-
return Number.isFinite(parsed) ? parsed : 1.0
36-
})
35+
const sensitivity = useRef(initialSensitivity)
36+
const invertScroll = useRef(initialInvert)
3737

3838
const [theme, setTheme] = useState(() => {
3939
if (typeof window === "undefined") return THEMES.DEFAULT
@@ -48,6 +48,16 @@ function SettingsPage() {
4848
})
4949

5050
const [qrData, setQrData] = useState("")
51+
const setConfig = (sensitivity_val: number, invertedScroll_val: boolean) => {
52+
sensitivity.current = sensitivity_val
53+
invertScroll.current = invertedScroll_val
54+
localStorage.setItem("rein_sensitivity", String(sensitivity_val))
55+
localStorage.setItem("rein_invert", JSON.stringify(invertedScroll_val))
56+
const timer = setTimeout(() => {
57+
sendConfigUpdate(sensitivity.current, invertScroll.current)
58+
}, 300)
59+
return () => clearTimeout(timer)
60+
}
5161

5262
// Load initial state (IP is not stored in localStorage; only sensitivity, invert, theme are client settings)
5363
const [authToken, setAuthToken] = useState(() => {
@@ -112,15 +122,6 @@ function SettingsPage() {
112122
}
113123
}, [])
114124

115-
// Effect: Update LocalStorage when settings change
116-
useEffect(() => {
117-
localStorage.setItem("rein_sensitivity", String(sensitivity))
118-
}, [sensitivity])
119-
120-
useEffect(() => {
121-
localStorage.setItem("rein_invert", JSON.stringify(invertScroll))
122-
}, [invertScroll])
123-
124125
// Effect: Theme
125126
useEffect(() => {
126127
if (typeof window === "undefined") return
@@ -137,20 +138,6 @@ function SettingsPage() {
137138
.catch((e) => console.error("QR Error:", e))
138139
}, [ip, shareUrl])
139140

140-
const [acceleration, setAcceleration] = useState(() => {
141-
if (typeof window === "undefined") return true
142-
try {
143-
const saved = localStorage.getItem("rein_acceleration")
144-
return saved === "true"
145-
} catch {
146-
return true
147-
}
148-
})
149-
150-
useEffect(() => {
151-
localStorage.setItem("rein_acceleration", JSON.stringify(acceleration))
152-
}, [acceleration])
153-
154141
// Effect: Auto-detect LAN IP from Server (only if on localhost)
155142
useEffect(() => {
156143
if (typeof window === "undefined") return
@@ -195,19 +182,22 @@ function SettingsPage() {
195182
<label className="label mb-3" htmlFor="sensitivity-slider">
196183
<span className="label-text">Mouse Sensitivity</span>
197184
<span className="label-text-alt font-mono">
198-
{sensitivity.toFixed(1)}x
185+
{sensitivity.current.toFixed(1)}x
199186
</span>
200187
</label>
201188

202189
<input
203190
type="range"
204191
id="sensitivity-slider"
205192
min="0.1"
206-
max="3.0"
193+
max="6.0"
207194
step="0.1"
208-
value={sensitivity}
195+
defaultValue={sensitivity.current}
209196
onChange={(e) =>
210-
setSensitivity(Number.parseFloat(e.target.value))
197+
setConfig(
198+
parseFloat(e.target.value) || 1.0,
199+
invertScroll.current,
200+
)
211201
}
212202
className="range range-primary range-sm w-full"
213203
/>
@@ -229,8 +219,10 @@ function SettingsPage() {
229219
id="invert-scroll-toggle"
230220
type="checkbox"
231221
className="toggle toggle-primary"
232-
checked={invertScroll}
233-
onChange={(e) => setInvertScroll(e.target.checked)}
222+
defaultChecked={invertScroll.current}
223+
onChange={(e) =>
224+
setConfig(sensitivity.current, e.target.checked)
225+
}
234226
/>
235227
</label>
236228

src/routes/trackpad.tsx

Lines changed: 3 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,7 @@ import { ExtraKeys } from "../components/Trackpad/ExtraKeys"
77
import { TouchArea } from "../components/Trackpad/TouchArea"
88
import { useRemoteConnection } from "../hooks/useRemoteConnection"
99
import { useTrackpadGesture } from "../hooks/useTrackpadGesture"
10-
import { useWindowsTouch } from "../hooks/useWindowsTouch"
1110
import { ScreenMirror } from "../components/Trackpad/ScreenMirror"
12-
1311
export const Route = createFileRoute("/trackpad")({
1412
component: TrackpadPage,
1513
})
@@ -24,36 +22,10 @@ function TrackpadPage() {
2422
const isComposingRef = useRef(false)
2523
const [keyboardOpen, setKeyboardOpen] = useState(false)
2624
const [extraKeysVisible, setExtraKeysVisible] = useState(true)
25+
const { send, sendCombo } = useRemoteConnection()
26+
const gesture = useTrackpadGesture(send, scrollMode)
2727

28-
// Load Client Settings
29-
const [sensitivity] = useState(() => {
30-
if (typeof window === "undefined") return 1.0
31-
const s = localStorage.getItem("rein_sensitivity")
32-
return s ? Number.parseFloat(s) : 1.0
33-
})
34-
35-
const [invertScroll] = useState(() => {
36-
if (typeof window === "undefined") return false
37-
const s = localStorage.getItem("rein_invert")
38-
return s ? JSON.parse(s) : false
39-
})
40-
41-
const { send, sendCombo, platform } = useRemoteConnection()
42-
43-
const isWindows = platform === "win32"
44-
45-
// Gesture hook for non-windows
46-
const gesture = useTrackpadGesture(
47-
send,
48-
scrollMode,
49-
sensitivity,
50-
invertScroll,
51-
)
52-
53-
// Native touch hook for windows
54-
const winTouch = useWindowsTouch(send, canvasRef)
55-
56-
const { isTracking, handlers } = isWindows ? winTouch : gesture
28+
const { isTracking, handlers } = gesture
5729

5830
// When keyboardOpen changes, focus or blur the hidden input
5931
useEffect(() => {

src/server-config.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,7 @@
22
"host": "0.0.0.0",
33
"frontendPort": 3000,
44
"address": "rein.local",
5-
"inputThrottleMs": 8
5+
"inputThrottleMs": 8,
6+
"sensitivity": 4.8,
7+
"invertScroll": false
68
}

0 commit comments

Comments
 (0)