mirror of
https://github.com/DeeJanuz/frametop.git
synced 2026-10-06 01:00:06 +02:00
Remove leftovers before a release
- gaze/tracker/lab/eyes_track.py: nothing used it - Input Settings: the pointer role backend, whose page was removed - ft-screens: no log line for every floating-window resize - hands: ft-hands --help gives the palm-down default (1: off), the uninstall removes ft-handsctl's link, .frame-job is ignored - Display Settings: "Save as profile…", not "Save current arrangement" - two stale comments (ft-pointer's grabprobe, ft-gaze) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
3da17bc838
commit
0ac2b10cd7
10 files changed
+14
-70
No files matched your search
@@ -445,7 +445,7 @@ class Backend(QObject):
|
|||||||
f"{reply or 'the desktop is not running'}", True)
|
f"{reply or 'the desktop is not running'}", True)
|
||||||
elif which == "all" and where != "none":
|
elif which == "all" and where != "none":
|
||||||
place = "on your head" if where == "head" else f"on your {where} wrist"
|
place = "on your head" if where == "head" else f"on your {where} wrist"
|
||||||
self.message.emit(f"All screens ride {place} now. Save current arrangement (Layout) keeps it.", False)
|
self.message.emit(f"All screens ride {place} now. Save as profile… (Layout & profiles) keeps it.", False)
|
||||||
self._check_running()
|
self._check_running()
|
||||||
|
|
||||||
# --- power: ft-powerd and Steam's sleep setting ---
|
# --- power: ft-powerd and Steam's sleep setting ---
|
||||||
|
|||||||
@@ -411,8 +411,8 @@ Kirigami.ApplicationWindow {
|
|||||||
text: spage.md
|
text: spage.md
|
||||||
? "Each screen is a real monitor of its own: any resolution, portrait by choosing a tall one. Resolution, "
|
? "Each screen is a real monitor of its own: any resolution, portrait by choosing a tall one. Resolution, "
|
||||||
+ "width, and curve apply at once. In VR: move a screen by the bar underneath, curve it with the round "
|
+ "width, and curve apply at once. In VR: move a screen by the bar underneath, curve it with the round "
|
||||||
+ "button next to the bar, resize it by the tab on its bottom right corner; Save current arrangement on the "
|
+ "button next to the bar, resize it by the tab on its bottom right corner; Save as profile… on the "
|
||||||
+ "Layout page keeps all of it."
|
+ "Layout & profiles page keeps all of it."
|
||||||
: "gamescope draws every screen at the same resolution, at most 1920 × 1080 worth of pixels. Portrait turns "
|
: "gamescope draws every screen at the same resolution, at most 1920 × 1080 worth of pixels. Portrait turns "
|
||||||
+ "a screen on its side. Rotation and scale apply at once; the rest when the desktop starts."
|
+ "a screen on its side. Rotation and scale apply at once; the rest when the desktop starts."
|
||||||
}
|
}
|
||||||
@@ -949,7 +949,7 @@ Kirigami.ApplicationWindow {
|
|||||||
+ "it.\n\nPin a screen to your head: choose On your head above. It rides on the headset where it "
|
+ "it.\n\nPin a screen to your head: choose On your head above. It rides on the headset where it "
|
||||||
+ "is now, like a HUD, and shows whenever the screens do. Grab its bar to move it; it stays on "
|
+ "is now, like a HUD, and shows whenever the screens do. Grab its bar to move it; it stays on "
|
||||||
+ "your head where you let go. Choosing a pin above keeps the screen where it is now, so place "
|
+ "your head where you let go. Choosing a pin above keeps the screen where it is now, so place "
|
||||||
+ "it first. Save current arrangement (Layout) keeps pins."
|
+ "it first. Save as profile… (Layout) keeps pins."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
// ft-gaze: the headset's eye tracking as rays and Frametop screen pixels (OpenVR overlay
|
// ft-gaze: the headset's eye tracking as rays and Frametop screen pixels (OpenVR overlay
|
||||||
// client, runs in the dev container). An experiment for gaze input; ft-gazeprobe reads it.
|
// client, runs in the dev container). The gaze service (ft-gazed) and the gaze probe run it.
|
||||||
//
|
//
|
||||||
// Every eye tracker sample (90 Hz) becomes one JSON line on stdout with each gaze source
|
// Every eye tracker sample (90 Hz) becomes one JSON line on stdout with each gaze source
|
||||||
// hit-tested against the Frametop screens:
|
// hit-tested against the Frametop screens:
|
||||||
|
|||||||
@@ -1,41 +0,0 @@
|
|||||||
"""Per-frame pupil ellipses through a recording, cached in the capture (numbers only).
|
|
||||||
|
|
||||||
ellipses(cap) -> {camera: array of rows (t, x, y, a, b, major, fill, glint mid x, y)}, every
|
|
||||||
EVERY-th frame of each camera; the glint midpoint is NaN when the pair isn't seen.
|
|
||||||
"""
|
|
||||||
import numpy as np
|
|
||||||
|
|
||||||
import eyes_lab # noqa: F401 (puts gaze/tracker on the path)
|
|
||||||
import eyes_pupil
|
|
||||||
|
|
||||||
EVERY = 2
|
|
||||||
VERSION = 2
|
|
||||||
|
|
||||||
|
|
||||||
def load_index(cap):
|
|
||||||
return np.array([[float(v) for v in l.split()]
|
|
||||||
for l in (cap / "index.txt").read_text().splitlines() if len(l.split()) == 4])
|
|
||||||
|
|
||||||
|
|
||||||
def ellipses(cap):
|
|
||||||
cache = cap / f"ellipses-v{VERSION}.npz"
|
|
||||||
if cache.exists():
|
|
||||||
z = np.load(cache)
|
|
||||||
return {0: z["cam0"], 1: z["cam1"]}
|
|
||||||
idx = load_index(cap)
|
|
||||||
frames = np.memmap(cap / "frames.raw", dtype=np.uint8, mode="r").reshape(-1, 400, 512)
|
|
||||||
idx = idx[:len(frames)]
|
|
||||||
out = {}
|
|
||||||
for c in (0, 1):
|
|
||||||
rows, prev = [], None
|
|
||||||
for i in np.where(idx[:, 2] == c)[0][::EVERY]:
|
|
||||||
p = eyes_pupil.find_pupil(frames[i], prev)
|
|
||||||
prev = p
|
|
||||||
if p is None:
|
|
||||||
continue
|
|
||||||
pair = eyes_pupil.glint_pair(p)
|
|
||||||
mx, my = ((pair[0][0] + pair[1][0]) / 2, (pair[0][1] + pair[1][1]) / 2) if pair else (np.nan, np.nan)
|
|
||||||
rows.append((idx[i, 3], p["x"], p["y"], p["a"], p["b"], p["major"], p["fill"], mx, my))
|
|
||||||
out[c] = np.array(rows).reshape(-1, 9)
|
|
||||||
np.savez(cache, cam0=out[0], cam1=out[1])
|
|
||||||
return out
|
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
# Model sources that tools/convert_models.py downloads; the converted ncnn models are kept
|
# Model sources that tools/convert_models.py downloads; the converted ncnn models are kept
|
||||||
models/onnx/
|
models/onnx/
|
||||||
models/*.task
|
models/*.task
|
||||||
|
# frame-job settings (where replays run, and the lab's capture folder): personal, not shipped
|
||||||
|
.frame-job
|
||||||
+2
-1
@@ -54,7 +54,8 @@ mkdir -p ~/.local/bin && ln -sfn $(printf %q "$FRAME_REPO/hands/ft-handsctl") ~/
|
|||||||
$states; echo 'start it with: ft-handsctl on'" ;;
|
$states; echo 'start it with: ft-handsctl on'" ;;
|
||||||
caps) set_caps ;;
|
caps) set_caps ;;
|
||||||
uninstall) "$frame" --host "systemctl --user disable --now $units 2>/dev/null
|
uninstall) "$frame" --host "systemctl --user disable --now $units 2>/dev/null
|
||||||
for u in $units; do rm -f ~/.config/systemd/user/\$u; done; systemctl --user daemon-reload; echo removed" ;;
|
for u in $units; do rm -f ~/.config/systemd/user/\$u; done; systemctl --user daemon-reload
|
||||||
|
[ -L ~/.local/bin/ft-handsctl ] && rm -f ~/.local/bin/ft-handsctl; echo removed" ;;
|
||||||
start|stop|restart) "$frame" --host "systemctl --user $1 $units; $states" ;;
|
start|stop|restart) "$frame" --host "systemctl --user $1 $units; $states" ;;
|
||||||
status) "$frame" --host "$states; journalctl --user -u frametop-hands.service --no-pager -o cat -n 4" || true ;;
|
status) "$frame" --host "$states; journalctl --user -u frametop-hands.service --no-pager -o cat -n 4" || true ;;
|
||||||
log) "$frame" --host "journalctl --user -u frametop-camd.service -u frametop-hands.service --no-pager -o short -n ${2:-30}" ;;
|
log) "$frame" --host "journalctl --user -u frametop-camd.service -u frametop-hands.service --no-pager -o short -n ${2:-30}" ;;
|
||||||
|
|||||||
@@ -221,7 +221,7 @@ int main(int argc, char **argv) {
|
|||||||
" [--keep-presence P] (0.5) [--ring PATH] (ft-camd's, or ft-ringplay's)\n"
|
" [--keep-presence P] (0.5) [--ring PATH] (ft-camd's, or ft-ringplay's)\n"
|
||||||
" [--cams auto|mono|color|all] (auto) [--bright all|color] (all) [--bright-on L] (40) [--bright-off L] (25)\n"
|
" [--cams auto|mono|color|all] (auto) [--bright all|color] (all) [--bright-on L] (40) [--bright-off L] (25)\n"
|
||||||
" [--color-left color_video0|color_video3] [--color-crop subtract|none]\n"
|
" [--color-left color_video0|color_video3] [--color-crop subtract|none]\n"
|
||||||
" [--pinch-begin M] (0.020) [--pinch-end M] (0.035) [--pinch-triangulated] [--pinch-palm-down MAX] (0.6)\n"
|
" [--pinch-begin M] (0.020) [--pinch-end M] (0.035) [--pinch-triangulated] [--pinch-palm-down MAX] (1: off)\n"
|
||||||
" [--grip-begin R] (1.2) [--grip-end R] (1.45) [--gesture-log]\n"
|
" [--grip-begin R] (1.2) [--grip-end R] (1.45) [--gesture-log]\n"
|
||||||
" [--contrast MODE|PALM/HAND] (clahe[:CLIP], none, stretch; default clahe:2/none)\n"
|
" [--contrast MODE|PALM/HAND] (clahe[:CLIP], none, stretch; default clahe:2/none)\n"
|
||||||
"Recording saves every frame set for S seconds (120) to DIR/sets.bin, for ft-handreplay; SIGUSR1\n"
|
"Recording saves every frame set for S seconds (120) to DIR/sets.bin, for ft-handreplay; SIGUSR1\n"
|
||||||
|
|||||||
@@ -138,8 +138,6 @@ GAZE_SETTINGS = [
|
|||||||
# In gaze mode, what the mouse's left button does (POINTER_GAZE_MOUSE).
|
# In gaze mode, what the mouse's left button does (POINTER_GAZE_MOUSE).
|
||||||
GAZE_MOUSE = {"precision": "Gaze precision: hold to steer with the mouse, release to click",
|
GAZE_MOUSE = {"precision": "Gaze precision: hold to steer with the mouse, release to click",
|
||||||
"direct": "Click right away where the pointer is"}
|
"direct": "Click right away where the pointer is"}
|
||||||
# The hand role the pointer's virtual controller takes (POINTER_ROLE).
|
|
||||||
POINTER_ROLES = {"right": "Right hand", "left": "Left hand", "stylus": "Stylus (no hand)"}
|
|
||||||
# Key combinations ("key_bindings" in the rules): modifiers, either side folded into the left code.
|
# Key combinations ("key_bindings" in the rules): modifiers, either side folded into the left code.
|
||||||
MODIFIER_CODES = {29: 29, 97: 29, 42: 42, 54: 42, 56: 56, 100: 56, 125: 125, 126: 125}
|
MODIFIER_CODES = {29: 29, 97: 29, 42: 42, 54: 42, 56: 56, 100: 56, 125: 125, 126: 125}
|
||||||
MODIFIER_NAMES = {29: "Ctrl", 42: "Shift", 56: "Alt", 125: "Meta"}
|
MODIFIER_NAMES = {29: "Ctrl", 42: "Shift", 56: "Alt", 125: "Meta"}
|
||||||
@@ -885,23 +883,6 @@ class Backend(QObject):
|
|||||||
self.pointerChanged.emit()
|
self.pointerChanged.emit()
|
||||||
self.message.emit("Gaze dot: " + ("always shown" if on else "shown only while the mouse moves it"), False)
|
self.message.emit("Gaze dot: " + ("always shown" if on else "shown only while the mouse moves it"), False)
|
||||||
|
|
||||||
@Property(str, notify=pointerChanged)
|
|
||||||
def pointerRole(self):
|
|
||||||
v = read_conf().get("POINTER_ROLE", "right")
|
|
||||||
return v if v in POINTER_ROLES else "right"
|
|
||||||
|
|
||||||
@Property("QVariantList", constant=True)
|
|
||||||
def pointerRoles(self):
|
|
||||||
return [{"value": k, "text": v} for k, v in POINTER_ROLES.items()]
|
|
||||||
|
|
||||||
@Slot(str)
|
|
||||||
def setPointerRole(self, role):
|
|
||||||
if role in POINTER_ROLES:
|
|
||||||
write_conf_value("POINTER_ROLE", role)
|
|
||||||
self.reload_timer.start()
|
|
||||||
self.pointerChanged.emit()
|
|
||||||
self.message.emit(f"Pointer role: {POINTER_ROLES[role].lower()} (from its next wake)", False)
|
|
||||||
|
|
||||||
# --- key combinations ("key_bindings") ---
|
# --- key combinations ("key_bindings") ---
|
||||||
def comboName(self, combo):
|
def comboName(self, combo):
|
||||||
parts = [int(c) for c in combo.split("+") if c.isdigit()]
|
parts = [int(c) for c in combo.split("+") if c.isdigit()]
|
||||||
|
|||||||
@@ -1139,8 +1139,8 @@ int main() {
|
|||||||
return "";
|
return "";
|
||||||
};
|
};
|
||||||
|
|
||||||
// Spike: aim down from the panel's bottom edge, 1 cm a step, and log where SteamVR's
|
// grabprobe (maintenance): aim down from the panel's bottom edge, 1 cm a step, and log where
|
||||||
// laser hits something (the hit dot shows) and whether the window controls are up.
|
// SteamVR's laser hits something (the hit dot shows) and whether the window controls are up.
|
||||||
auto grabProbe = [&](const char *key) {
|
auto grabProbe = [&](const char *key) {
|
||||||
Panel p;
|
Panel p;
|
||||||
Vec3 eye;
|
Vec3 eye;
|
||||||
|
|||||||
+2
-1
@@ -890,7 +890,8 @@ void SendFloat(const std::string &msg) {
|
|||||||
std::memcpy(addr.sun_path + 1, name, sizeof name - 1);
|
std::memcpy(addr.sun_path + 1, name, sizeof name - 1);
|
||||||
sendto(fd, msg.data(), msg.size(), MSG_DONTWAIT, reinterpret_cast<sockaddr *>(&addr),
|
sendto(fd, msg.data(), msg.size(), MSG_DONTWAIT, reinterpret_cast<sockaddr *>(&addr),
|
||||||
socklen_t(offsetof(sockaddr_un, sun_path) + 1 + sizeof name - 1));
|
socklen_t(offsetof(sockaddr_un, sun_path) + 1 + sizeof name - 1));
|
||||||
std::printf("to ft-floatd: %s\n", msg.c_str());
|
if (msg.rfind("resize ", 0) != 0) // an edge drag sends many resizes a second
|
||||||
|
std::printf("to ft-floatd: %s\n", msg.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Where a device's ray meets the screen's plane, in the screen's x (right) and y (up),
|
// Where a device's ray meets the screen's plane, in the screen's x (right) and y (up),
|
||||||
|
|||||||
Reference in new issue
Block a user