guides:bluetooth
Differences
This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revision | |||
| guides:bluetooth [2025/12/15 00:05] – [Connecting a new Bluetooth keyboard] dpip | guides:bluetooth [2026/09/09 16:00] (current) – Add auto-pairing BT programing cwervo | ||
|---|---|---|---|
| Line 1: | Line 1: | ||
| ====== Connect keyboards to Folk via Bluetooth ====== | ====== Connect keyboards to Folk via Bluetooth ====== | ||
| + | ===== Folk program to connect a Bluetooth keyboard ===== | ||
| - | ===== Connecting a new Bluetooth | + | < |
| + | # --------------------------------------------------------- | ||
| + | # Bluetooth | ||
| + | # Last updated: Wednesday, September 9, 2026 | ||
| + | # Tested on: folk-hex, folk-convivial, | ||
| + | # --------------------------------------------------------- | ||
| + | # Defensive Cleanup: Clear stale state from previous runs | ||
| + | Retract! $this has phase /any/ | ||
| + | Retract! $this target is /any/ named /any/ | ||
| + | |||
| + | # Initialize the state machine | ||
| + | When /nobody/ claims $this has phase /any/ { | ||
| + | puts " | ||
| + | Hold! -key [list $this phase] Claim $this has phase scanning | ||
| + | } | ||
| + | |||
| + | # Phase: scanning | ||
| + | When $this has phase scanning { | ||
| + | puts " | ||
| + | set scanner [list scanner $this] | ||
| + | | ||
| + | Wish $this is outlined blue | ||
| + | |||
| + | # Start the Bluetooth scanning pipeline | ||
| + | Wish $scanner runs Unix command "/ | ||
| + | [list " | ||
| + | |||
| + | When $scanner has Unix output lines /lines/ { | ||
| + | foreach line $lines { | ||
| + | # Look for lines matching: "[NEW] Device F4: | ||
| + | if {[regexp {Device ([0-9A-F: | ||
| + | set name [string trim $name]; puts " | ||
| + | if {[regexp -nocase {keyboard|k380|mac} $name]} { | ||
| + | puts " | ||
| + | Hold! -key [list $this target] Claim $this target is $mac named $name | ||
| + | Hold! -key [list $this phase] Claim $this has phase connecting | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | |||
| + | # Display scanning dots | ||
| + | When $this has phase scanning &\ | ||
| + | the clock time is /t/ { | ||
| + | set dot_states [list " | ||
| + | set dots [lindex $dot_states [expr {int($t * 4) % 3}]] | ||
| + | Wish $this is footnoted " | ||
| + | } | ||
| + | |||
| + | # Phase: connecting | ||
| + | When $this has phase connecting &\ | ||
| + | $this target is /mac/ named /name/ { | ||
| + | puts " | ||
| + | set connector [list connector $this $mac] | ||
| + | | ||
| + | Wish $this is outlined yellow | ||
| + | Wish $this is footnoted " | ||
| + | | ||
| + | Wish $connector runs Unix command "/ | ||
| + | | ||
| + | When $connector has Unix output lines / | ||
| + | if {[llength $connectLines] > 0} { | ||
| + | set start_idx [expr {[llength $connectLines] - 10}] | ||
| + | if {$start_idx < 0} { set start_idx 0 } | ||
| + | set recent_lines [join [lrange $connectLines $start_idx end] " | ||
| + | set full_output [join $connectLines " | ||
| + | Wish $this is labelled $recent_lines | ||
| + | | ||
| + | if {[regexp -nocase {successful} $full_output]} { | ||
| + | puts " | ||
| + | Wish $this is footnoted " | ||
| + | Hold! -key [list $this phase] Claim $this has phase connected | ||
| + | } elseif {[regexp -nocase {failed|error|not available} $full_output]} { | ||
| + | puts " | ||
| + | Wish $this is footnoted " | ||
| + | Hold! -key [list $this phase] Claim $this has phase scanning | ||
| + | } else { | ||
| + | Wish $this is footnoted " | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | |||
| + | # Phase: connected | ||
| + | When $this has phase connected &\ | ||
| + | $this target is /mac/ named /name/ { | ||
| + | puts " | ||
| + | Wish $this is outlined green | ||
| + | Wish $this is footnoted " | ||
| + | |||
| + | # Set up the visual countdown start time | ||
| + | When /nobody/ claims $this has countdown-start /any/ { | ||
| + | Hold! -key [list $this countdown-start] Claim $this has countdown-start [expr {[clock milliseconds] / 1000.0}] | ||
| + | | ||
| + | # Trigger the robust 3-second state transition timer | ||
| + | Hold! -keep 3000ms -key [list $this reset-timer] Claim $this is waiting for reset | ||
| + | Hold! -key [list $this reset-timer] {} | ||
| + | } | ||
| + | } | ||
| + | |||
| + | # Process state transition when the timer expires | ||
| + | When $this has phase connected &\ | ||
| + | / | ||
| + | puts " | ||
| + | |||
| + | # Re-scan for new keyboards in / | ||
| + | set allDevices [glob -nocomplain "/ | ||
| + | foreach device $allDevices { | ||
| + | set properties [exec udevadm info --query=property --name=$device] | ||
| + | if {[string match *ID_INPUT_KEYBOARD=1* $properties]} { | ||
| + | if {[file readable $device] == 0} { | ||
| + | puts stderr " | ||
| + | catch {exec sudo chmod +r $device} | ||
| + | } | ||
| + | # Assert a global claim for the new keyboard so builtin-programs/ | ||
| + | Hold! -key [list auto-bt-keyboard $device] Claim $device is a keyboard device | ||
| + | } | ||
| + | } | ||
| + | |||
| + | Hold! -key [list $this target] {} | ||
| + | Hold! -key [list $this countdown-start] {} | ||
| + | Hold! -key [list $this phase] Claim $this has phase scanning | ||
| + | } | ||
| + | |||
| + | # Visual countdown display | ||
| + | When $this has phase connected &\ | ||
| + | $this has countdown-start /start_t/ &\ | ||
| + | the clock time is /t/ { | ||
| + | set elapsed [expr {$t - $start_t}] | ||
| + | set remaining [expr {3 - int($elapsed)}] | ||
| + | if {$remaining > 0} { | ||
| + | Wish $this is titled " | ||
| + | } | ||
| + | } | ||
| + | |||
| + | When $this target is /mac/ named /name/ { | ||
| + | Wish $this is left-margined " | ||
| + | } | ||
| + | |||
| + | When /nobody/ claims $this target is /any/ named /any/ { | ||
| + | Wish $this is left-margined " | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | ===== Connecting a new Bluetooth keyboard manually ===== | ||
| * Follow the entire [[https:// | * Follow the entire [[https:// | ||
guides/bluetooth.1765757147.txt.gz · Last modified: by dpip
