mirror of
https://github.com/DeeJanuz/frametop.git
synced 2026-10-06 05:00:08 +02:00
Frametop: a multi-screen desktop and universal 3D mouse for the Steam Frame
Several KDE Plasma screens floating in SteamVR, each a real monitor of any resolution and shape, shown by our own compositor (ft-screens), with a layout, wrist pinning, and visibility modes; a Bluetooth mouse that drives all of SteamVR as a room-anchored 3D pointer (input relay, ft-pointer helper, ft_pointer SteamVR driver); two settings apps; and Bluetooth LE fixes. Installs on the headset with ./install.sh. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
commit
d439bc3f25
61 files changed
+8785
No files matched your search
Executable
+44
@@ -0,0 +1,44 @@
|
||||
#!/bin/bash
|
||||
# Installed to /etc/steamframe/bt-fixups.sh by setup/bluetooth/install.sh.
|
||||
# Runs as root from steamframe-bt-fixups.service after every bluetoothd start,
|
||||
# and by hand after pairing a new LE device: sudo /etc/steamframe/bt-fixups.sh
|
||||
#
|
||||
# Works around two things that stop Bluetooth LE mice like the Swiftpoint Z3
|
||||
# from reconnecting:
|
||||
# 1. BlueZ 5.79 never sets the ADDRESS_RESOLUTION device flag, so kernel 6.18
|
||||
# never programs a bonded device's IRK into the controller's resolving list,
|
||||
# and devices that advertise with private addresses never reconnect.
|
||||
# Fixed upstream in BlueZ f1fb4f95f4 ("core: Fix not resolving addresses").
|
||||
# Workaround: set flags 0x6 on every bonded LE device that has an IRK.
|
||||
# 2. The Z3 doesn't accept the host's IRK when pairing, so it only knows the
|
||||
# Frame's public address. Controller privacy has to be off.
|
||||
set -u
|
||||
|
||||
# btmgmt quits before the reply unless stdin stays open for a moment.
|
||||
mgmt() { sleep 2 | btmgmt --index 0 "$@" 2>&1; }
|
||||
|
||||
# Wait for the controller to come up and be powered on (can take a while after boot).
|
||||
for _ in $(seq 60); do
|
||||
mgmt info | grep -q "current settings:.* powered" && break
|
||||
sleep 1
|
||||
done
|
||||
|
||||
if mgmt info | grep -q "current settings:.* privacy"; then
|
||||
mgmt power off >/dev/null
|
||||
mgmt privacy off >/dev/null
|
||||
mgmt power on >/dev/null
|
||||
echo "privacy turned off"
|
||||
fi
|
||||
|
||||
ctrl=$(mgmt info | awk '/^\s*addr /{print $2; exit}')
|
||||
for info in /var/lib/bluetooth/"$ctrl"/*/info; do
|
||||
[ -f "$info" ] || continue
|
||||
grep -q '^\[IdentityResolvingKey\]' "$info" || continue
|
||||
addr=$(basename "$(dirname "$info")")
|
||||
case $(sed -n 's/^AddressType=//p' "$info") in
|
||||
public) type=1 ;;
|
||||
*) type=2 ;;
|
||||
esac
|
||||
echo "$(mgmt set-flags -f 0x6 -t "$type" "$addr" | tail -n 1)"
|
||||
done
|
||||
exit 0
|
||||
Executable
+43
@@ -0,0 +1,43 @@
|
||||
#!/usr/bin/env bash
|
||||
# Install (or remove) the persistent Bluetooth LE workarounds on the Frame.
|
||||
# Needs host sudo. On the Frame, sudo asks for the password in the terminal.
|
||||
# From a PC (or with no terminal), the password comes from steamos_root_pwd in the
|
||||
# repo's .env and is sent to sudo -S on stdin, never on a command line.
|
||||
# Usage: setup/bluetooth/install.sh [install|uninstall|run]
|
||||
# run re-apply now without restarting bluetooth (after pairing a new device)
|
||||
set -euo pipefail
|
||||
|
||||
root=$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)
|
||||
. "$root/scripts/_env.sh"
|
||||
src=$FRAME_REPO/setup/bluetooth
|
||||
|
||||
sudo_run() {
|
||||
if [ "$FRAME_LOCAL" = 1 ] && [ -t 0 ]; then
|
||||
sudo bash -c "$1" # asks for the password here
|
||||
return
|
||||
fi
|
||||
local pw
|
||||
pw=$(sed -n 's/^steamos_root_pwd=//p' "$root/.env" 2>/dev/null)
|
||||
pw=${pw#[\"\']}; pw=${pw%[\"\']} # .env values may be quoted
|
||||
[ -n "$pw" ] || { echo "no terminal for sudo, and steamos_root_pwd is missing from $root/.env" >&2; exit 1; }
|
||||
printf '%s\n' "$pw" | on_frame "sudo -S -p '' bash -c $(printf %q "$1")"
|
||||
}
|
||||
|
||||
case ${1:-install} in
|
||||
install)
|
||||
"$root/scripts/sync.sh" >/dev/null
|
||||
sudo_run "set -e
|
||||
install -D -m 0755 -o root -g root $src/bt-fixups.sh /etc/steamframe/bt-fixups.sh
|
||||
install -D -m 0644 -o root -g root $src/steamframe-bt-fixups.service /etc/systemd/system/steamframe-bt-fixups.service
|
||||
rm -f /etc/systemd/system/bluetooth.service.d/steamframe.conf
|
||||
rmdir /etc/systemd/system/bluetooth.service.d 2>/dev/null || true
|
||||
systemctl daemon-reload
|
||||
systemctl enable steamframe-bt-fixups.service
|
||||
echo installed" ;;
|
||||
uninstall)
|
||||
sudo_run "systemctl disable steamframe-bt-fixups.service 2>/dev/null
|
||||
rm -f /etc/systemd/system/steamframe-bt-fixups.service /etc/systemd/system/bluetooth.service.d/steamframe.conf /etc/steamframe/bt-fixups.sh
|
||||
rmdir /etc/systemd/system/bluetooth.service.d /etc/steamframe 2>/dev/null; systemctl daemon-reload; echo removed" ;;
|
||||
run) sudo_run "/etc/steamframe/bt-fixups.sh" ;;
|
||||
*) echo "usage: $0 [install|uninstall|run]" >&2; exit 2 ;;
|
||||
esac
|
||||
@@ -0,0 +1,17 @@
|
||||
# Installed to /etc/systemd/system/ by setup/bluetooth/install.sh.
|
||||
# Re-applies the Bluetooth LE workarounds after every bluetoothd start.
|
||||
# A separate unit rather than ExecStartPost: the controller only powers up
|
||||
# after bluetooth.service is active, so waiting inside it deadlocks.
|
||||
[Unit]
|
||||
Description=SteamFrame Bluetooth LE workarounds (address resolution, privacy off)
|
||||
After=bluetooth.service set-bluetooth-mac-address.service
|
||||
PartOf=bluetooth.service
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
RemainAfterExit=yes
|
||||
ExecStart=/etc/steamframe/bt-fixups.sh
|
||||
TimeoutStartSec=5min
|
||||
|
||||
[Install]
|
||||
WantedBy=bluetooth.service
|
||||
Reference in new issue
Block a user