Monorepo for Aesthetic.Computer aesthetic.computer
4
fork

Configure Feed

Select the types of activity you want to include in your feed.

notepat-remote: [active] focus signal + focus-transition logs

Max patcher adds an [active] object whose int outlet is sprintf'd
into window.acSetLiveFocus(N) — Live's window activation/deactivation
now pushes focus state directly into jweb, since the DOM-level
blur/focus listeners inside jweb~ don't observe Live's OS focus
transitions.

Every focus transition is logged with its source path so the Max
Console shows which hook actually caught the change:
[focus] max.active → ACTIVE (Max [active] push)
[focus] window.blur → inactive (DOM blur)
[focus] document.hasFocus() → … (sim poll fallback)
[focus] ac-event:focus → … (AC internal event)

Whichever one fires tells us the reliable path for this environment.

+33 -12
+10
oven/bundler.mjs
··· 1096 1096 { box: { id: "obj-live-observe-color", maxclass: "newobj", numinlets: 2, numoutlets: 3, outlettype: ["","",""], patching_rect: [10,600,220,22], text: "live.observer @property color" } }, 1097 1097 { box: { id: "obj-route-track-color", maxclass: "newobj", numinlets: 1, numoutlets: 2, outlettype: ["",""], patching_rect: [10,630,120,22], text: "route color" } }, 1098 1098 { box: { id: "obj-sprintf-track-color", maxclass: "newobj", numinlets: 1, numoutlets: 1, outlettype: [""], patching_rect: [10,660,480,22], text: "sprintf executejavascript window.acSetLiveTrackColor(%ld)" } }, 1099 + // ── Host-window focus detection ───────────────────────────────── 1100 + // [active] fires 1 when Live's window becomes the foreground window 1101 + // and 0 when it loses focus. The DOM-level blur/focus listeners 1102 + // inside jweb don't see Live's OS focus transitions, so we push the 1103 + // state in from Max via window.acSetLiveFocus(N). 1104 + { box: { id: "obj-active", maxclass: "newobj", numinlets: 1, numoutlets: 1, outlettype: ["int"], patching_rect: [10,700,60,22], text: "active" } }, 1105 + { box: { id: "obj-sprintf-focus", maxclass: "newobj", numinlets: 1, numoutlets: 1, outlettype: [""], patching_rect: [10,730,440,22], text: "sprintf executejavascript window.acSetLiveFocus(%ld)" } }, 1099 1106 // MIDI routing (downstream of the unmatched outlet). 1100 1107 { box: { id: "obj-route", maxclass: "newobj", numinlets: 1, numoutlets: 7, outlettype: ["","","","","","",""], patching_rect: [10,300,560,22], text: "route note channel notedown noteup octave focus ping" } }, 1101 1108 { box: { id: "obj-noteout", maxclass: "newobj", numinlets: 2, numoutlets: 0, patching_rect: [10,450,60,22], text: "noteout" } }, ··· 1125 1132 { patchline: { source: ["obj-live-observe-color", 0], destination: ["obj-route-track-color", 0] } }, 1126 1133 { patchline: { source: ["obj-route-track-color", 0], destination: ["obj-sprintf-track-color", 0] } }, 1127 1134 { patchline: { source: ["obj-sprintf-track-color", 0], destination: ["obj-jweb", 0] } }, 1135 + // Host-window focus chain: [active] → sprintf → jweb: 1136 + { patchline: { source: ["obj-active", 0], destination: ["obj-sprintf-focus", 0] } }, 1137 + { patchline: { source: ["obj-sprintf-focus", 0], destination: ["obj-jweb", 0] } }, 1128 1138 { patchline: { source: ["obj-route", 0], destination: ["obj-noteout", 0] } }, 1129 1139 { patchline: { source: ["obj-route", 1], destination: ["obj-noteout", 1] } }, 1130 1140 { patchline: { source: ["obj-route", 2], destination: ["obj-pack-on", 0] } },
+23 -12
system/public/aesthetic.computer/disks/notepat-remote.mjs
··· 213 213 214 214 // ── Focus detection ──────────────────────────────────────────────── 215 215 // jweb inside Max for Live doesn't always surface DOM blur/focus as AC 216 - // events. Hook the native listeners ourselves so the red-X unfocused 217 - // overlay actually tracks "can my keyboard drive this right now?". 216 + // events. We listen on four paths: (1) AC act() events, (2) native 217 + // window blur/focus, (3) document visibilitychange, (4) Max [active] 218 + // object pushing via window.acSetLiveFocus. Each transition logs its 219 + // source so the Max Console shows which hook actually catches it. 218 220 if (typeof window !== "undefined") { 219 - const setFocus = (f) => { 221 + const setFocus = (f, source) => { 220 222 if (focused !== f) { 221 223 focused = f; 222 224 focusedChangedFrame = frame; 223 225 if (!f) heldKeys.clear(); 226 + try { console.log(`[focus] ${source} → ${f ? "ACTIVE" : "inactive"}`); } catch {} 224 227 } 225 228 }; 226 229 try { 227 - window.addEventListener("blur", () => setFocus(false)); 228 - window.addEventListener("focus", () => setFocus(true)); 229 - document.addEventListener?.("visibilitychange", () => setFocus(!document.hidden)); 230 + window.addEventListener("blur", () => setFocus(false, "window.blur")); 231 + window.addEventListener("focus", () => setFocus(true, "window.focus")); 232 + document.addEventListener?.("visibilitychange", () => 233 + setFocus(!document.hidden, "document.visibilitychange")); 230 234 } catch {} 231 235 // Max side pushes focus + theme state via these globals. Defining 232 236 // them unconditionally lets the patcher call them whenever it likes. 233 - window.acSetLiveFocus = (f) => setFocus(!!f); 237 + window.acSetLiveFocus = (f) => setFocus(!!f, "max.active"); 234 238 window.acSetLiveTrackColor = (colorInt) => { 235 239 const n = Number(colorInt) >>> 0; 236 240 if (!Number.isFinite(n)) return; ··· 282 286 focused = hf; 283 287 focusedChangedFrame = frame; 284 288 if (!hf) heldKeys.clear(); 289 + try { console.log(`[focus] document.hasFocus() → ${hf ? "ACTIVE" : "inactive"}`); } catch {} 285 290 } 286 291 } 287 292 } ··· 318 323 319 324 // Focus/blur signals from AC (if AC forwards them; harmless if it doesn't). 320 325 if (e.is("focus")) { 321 - focused = true; 322 - focusedChangedFrame = frame; 326 + if (!focused) { 327 + focused = true; 328 + focusedChangedFrame = frame; 329 + try { console.log("[focus] ac-event:focus → ACTIVE"); } catch {} 330 + } 323 331 return; 324 332 } 325 333 if (e.is("blur")) { 326 - focused = false; 327 - focusedChangedFrame = frame; 328 - heldKeys.clear(); 334 + if (focused) { 335 + focused = false; 336 + focusedChangedFrame = frame; 337 + heldKeys.clear(); 338 + try { console.log("[focus] ac-event:blur → inactive"); } catch {} 339 + } 329 340 return; 330 341 } 331 342
system/public/m4l/notepat.com.amxd

This is a binary file and will not be displayed.