diff --git a/ui/shared/power/brightness.js b/ui/shared/power/brightness.js index 04a4042..4d30f2d 100644 --- a/ui/shared/power/brightness.js +++ b/ui/shared/power/brightness.js @@ -9,8 +9,15 @@ function powerApi() { return globalThis.navigator?.embedder?.power ?? null; } -class ScreenBrightness { +class Backlight { #ready = null; + #hints = []; + #kind = null; + + constructor(hints, kind = "backlight") { + this.#hints = hints; + this.#kind = kind; + } /** * Resolve (once) the backlight this UI controls, or null when the device has @@ -30,10 +37,17 @@ class ScreenBrightness { } try { const devices = await api.devices(); - // Prefer a real backlight and ignore LEDs. - return devices.find((device) => device.kind === "backlight") ?? null; + return ( + devices.find((device) => { + if (device.kind !== this.#kind) { + return false; + } + const name = device.name.toLowerCase(); + return this.#hints.some((hint) => name.includes(hint)); + }) ?? null + ); } catch (error) { - console.warn("[brightness] Failed to list power devices:", error); + console.warn("[Backlight] Failed to list devices:", error); return null; } } @@ -68,7 +82,9 @@ class ScreenBrightness { } } -export const screenBrightness = new ScreenBrightness(); +export const screenBrightness = new Backlight(["backlight", "panel"]); + +export const keyboardBrightness = new Backlight(["keyboard", "kbd"], "led"); // Names that suggest a camera flash / torch LED rather than a notification, // charging or keyboard-backlight LED. Matched case-insensitively against the diff --git a/ui/shared/power/brightness_slider.js b/ui/shared/power/brightness_slider.js index 33eef6d..317da0e 100644 --- a/ui/shared/power/brightness_slider.js +++ b/ui/shared/power/brightness_slider.js @@ -10,7 +10,10 @@ import { html, css, } from "beaver://shared/third_party/lit/lit-all.min.js"; -import { screenBrightness } from "beaver://shared/power/brightness.js"; +import { + screenBrightness, + keyboardBrightness, +} from "beaver://shared/power/brightness.js"; // Never let the screen go fully dark from this control: the user would have no // way to see the UI to turn it back up. @@ -24,8 +27,12 @@ export class BrightnessSlider extends LitElement { // rAF handle coalescing hardware writes while dragging. #pendingWrite = null; + // Either screenBrightness or keyboardBrightness, according to the 'kind' property. + #device = null; + static properties = { percent: { type: Number }, + kind: { type: String }, }; static styles = css` @@ -136,7 +143,13 @@ export class BrightnessSlider extends LitElement { } async #init() { - const device = await screenBrightness.device(); + if (this.kind == "keyboard") { + this.#device = keyboardBrightness; + } else { + this.#device = screenBrightness; + } + + const device = await this.#device.device(); if (!device) { this.hidden = true; return; @@ -147,7 +160,7 @@ export class BrightnessSlider extends LitElement { /** Re-read the hardware; call when the containing panel opens. */ async refresh() { - const value = await screenBrightness.get(); + const value = await this.#device.get(); if (value !== null) { this.percent = Math.round(value); } @@ -175,7 +188,7 @@ export class BrightnessSlider extends LitElement { if (this.#pendingWrite === null) { this.#pendingWrite = requestAnimationFrame(() => { this.#pendingWrite = null; - screenBrightness.set(this.percent); + this.#device.set(this.percent); }); } } @@ -222,15 +235,20 @@ export class BrightnessSlider extends LitElement { if (this.#pendingWrite !== null) { cancelAnimationFrame(this.#pendingWrite); this.#pendingWrite = null; - screenBrightness.set(this.percent); + this.#device.set(this.percent); } } render() { + let iconName = "sun"; + if (this.kind == "keyboard") { + iconName = "keyboard"; + } + return html`