feat: kde wayland support #57
This commit is contained in:
+113
-49
@@ -17,12 +17,13 @@ global.HARDWARE = global.HARDWARE || {
|
|||||||
},
|
},
|
||||||
display: {
|
display: {
|
||||||
status: {
|
status: {
|
||||||
path: null,
|
|
||||||
value: null,
|
value: null,
|
||||||
|
path: null,
|
||||||
|
command: null,
|
||||||
},
|
},
|
||||||
brightness: {
|
brightness: {
|
||||||
path: null,
|
|
||||||
value: null,
|
value: null,
|
||||||
|
path: null,
|
||||||
max: null,
|
max: null,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -37,7 +38,7 @@ global.HARDWARE = global.HARDWARE || {
|
|||||||
* @returns {bool} Returns true if the initialization was successful.
|
* @returns {bool} Returns true if the initialization was successful.
|
||||||
*/
|
*/
|
||||||
const init = async () => {
|
const init = async () => {
|
||||||
if (!compatibleDevice()) {
|
if (!compatibleSystem()) {
|
||||||
console.warn("Operating system is not supported\n");
|
console.warn("Operating system is not supported\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -49,14 +50,13 @@ const init = async () => {
|
|||||||
// Init globals
|
// Init globals
|
||||||
HARDWARE.session.user = sessionUser();
|
HARDWARE.session.user = sessionUser();
|
||||||
HARDWARE.session.type = sessionType();
|
HARDWARE.session.type = sessionType();
|
||||||
|
HARDWARE.session.desktop = sessionDesktop();
|
||||||
HARDWARE.battery.level.path = getBatteryLevelPath();
|
HARDWARE.battery.level.path = getBatteryLevelPath();
|
||||||
HARDWARE.support.batteryLevel = HARDWARE.battery.level.path !== null;
|
|
||||||
HARDWARE.display.status.path = getDisplayStatusPath();
|
HARDWARE.display.status.path = getDisplayStatusPath();
|
||||||
HARDWARE.support.displayStatus = HARDWARE.display.status.path !== null;
|
HARDWARE.display.status.command = getDisplayStatusCommand();
|
||||||
HARDWARE.display.brightness.path = getDisplayBrightnessPath();
|
HARDWARE.display.brightness.path = getDisplayBrightnessPath();
|
||||||
HARDWARE.support.displayBrightness = HARDWARE.display.brightness.path !== null;
|
|
||||||
HARDWARE.display.brightness.max = getDisplayBrightnessMax();
|
HARDWARE.display.brightness.max = getDisplayBrightnessMax();
|
||||||
HARDWARE.support.keyboardVisibility = processRuns("squeekboard");
|
HARDWARE.support = checkSupport();
|
||||||
HARDWARE.initialized = true;
|
HARDWARE.initialized = true;
|
||||||
|
|
||||||
// Show supported features
|
// Show supported features
|
||||||
@@ -65,6 +65,7 @@ const init = async () => {
|
|||||||
// Show session infos
|
// Show session infos
|
||||||
console.log("\nUser:", HARDWARE.session.user);
|
console.log("\nUser:", HARDWARE.session.user);
|
||||||
console.log("Session:", HARDWARE.session.type);
|
console.log("Session:", HARDWARE.session.type);
|
||||||
|
console.log("Desktop:", HARDWARE.session.desktop);
|
||||||
|
|
||||||
// Show device infos
|
// Show device infos
|
||||||
console.log("\nModel:", getModel());
|
console.log("\nModel:", getModel());
|
||||||
@@ -80,9 +81,23 @@ const init = async () => {
|
|||||||
console.log("Processor Temperature:", getProcessorTemperature());
|
console.log("Processor Temperature:", getProcessorTemperature());
|
||||||
|
|
||||||
// Show hardware infos
|
// Show hardware infos
|
||||||
console.log(`\nBattery Level [${HARDWARE.battery.level.path}]:`, getBatteryLevel());
|
const unsupported = "unsupported";
|
||||||
console.log(`Display Status [${HARDWARE.display.status.path}]:`, getDisplayStatus());
|
console.log(
|
||||||
console.log(`Display Brightness [${HARDWARE.display.brightness.path}]:`, getDisplayBrightness(), "\n");
|
`\nBattery Level [${HARDWARE.battery.level.path || unsupported}]:`,
|
||||||
|
`${getBatteryLevel() || unsupported}`,
|
||||||
|
);
|
||||||
|
console.log(
|
||||||
|
`Display Status [${HARDWARE.display.status.path || unsupported}]:`,
|
||||||
|
`${getDisplayStatus() || unsupported} (${HARDWARE.display.status.command || unsupported})`,
|
||||||
|
);
|
||||||
|
console.log(
|
||||||
|
`Display Brightness [${HARDWARE.display.brightness.path || unsupported}]:`,
|
||||||
|
`${getDisplayBrightness() || unsupported}`,
|
||||||
|
);
|
||||||
|
console.log(
|
||||||
|
`Keyboard Visibility [${HARDWARE.support.keyboardVisibility ? "squeekboard" : unsupported}]:`,
|
||||||
|
`${getKeyboardVisibility() || unsupported}\n`,
|
||||||
|
);
|
||||||
|
|
||||||
// Check for keyboard visibility
|
// Check for keyboard visibility
|
||||||
setKeyboardVisibility("OFF", (reply, error) => {
|
setKeyboardVisibility("OFF", (reply, error) => {
|
||||||
@@ -134,15 +149,15 @@ const update = async () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verifies device compatibility by checking the presence of necessary sys paths.
|
* Verifies system compatibility by checking the presence of necessary sys paths.
|
||||||
*
|
*
|
||||||
* @returns {bool} Returns true if all paths exists.
|
* @returns {bool} Returns true if all paths exists.
|
||||||
*/
|
*/
|
||||||
const compatibleDevice = () => {
|
const compatibleSystem = () => {
|
||||||
if (os.platform() !== "linux") {
|
if (os.platform() !== "linux") {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const paths = ["/sys/class/drm", "/sys/class/backlight", "/sys/class/thermal"];
|
const paths = ["/sys/class/drm", "/sys/class/backlight", "/sys/class/power_supply", "/sys/class/thermal"];
|
||||||
return paths.every((path) => fs.existsSync(path));
|
return paths.every((path) => fs.existsSync(path));
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -187,6 +202,35 @@ const sessionType = () => {
|
|||||||
]);
|
]);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the desktop environment name by checking environment variables.
|
||||||
|
*
|
||||||
|
* @returns {string} Returns desktop environment name or 'unknown' if not detected.
|
||||||
|
*/
|
||||||
|
const sessionDesktop = () => {
|
||||||
|
const envs = ["XDG_CURRENT_DESKTOP", "XDG_DESKTOP_SESSION", "DESKTOP_SESSION"];
|
||||||
|
const names = envs.map((env) => process.env[env]).filter(Boolean);
|
||||||
|
return (names.join(":") || "unknown").toLowerCase();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks supported features based on global properties.
|
||||||
|
*
|
||||||
|
* @returns {Object} Returns support object with boolean values.
|
||||||
|
*/
|
||||||
|
const checkSupport = () => {
|
||||||
|
const battery = HARDWARE.battery.level;
|
||||||
|
const status = HARDWARE.display.status;
|
||||||
|
const brightness = HARDWARE.display.brightness;
|
||||||
|
const keyboard = processRuns("squeekboard");
|
||||||
|
return {
|
||||||
|
batteryLevel: battery.path !== null,
|
||||||
|
displayStatus: status.path !== null && status.command !== null,
|
||||||
|
displayBrightness: brightness.path !== null && brightness.max !== null,
|
||||||
|
keyboardVisibility: keyboard === true,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the model name using `/sys/firmware/devicetree/base/model` or `/sys/class/dmi/id/product_name`.
|
* Gets the model name using `/sys/firmware/devicetree/base/model` or `/sys/class/dmi/id/product_name`.
|
||||||
*
|
*
|
||||||
@@ -371,7 +415,31 @@ const getDisplayStatusPath = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the current display power status using `wlopm` or `xset`.
|
* Gets the available display status command checking for `wlopm`, `kscreen-doctor` and `xset`.
|
||||||
|
*
|
||||||
|
* @returns {string|null} The display status command or null if nothing was found.
|
||||||
|
*/
|
||||||
|
const getDisplayStatusCommand = () => {
|
||||||
|
const type = HARDWARE.session.type;
|
||||||
|
const desktop = HARDWARE.session.desktop;
|
||||||
|
const mapping = {
|
||||||
|
wayland: [
|
||||||
|
{ command: "wlopm", desktops: ["labwc", "wayfire"] },
|
||||||
|
{ command: "kscreen-doctor", desktops: ["kde", "plasma"] },
|
||||||
|
],
|
||||||
|
x11: [{ command: "xset", desktops: ["*"] }],
|
||||||
|
}[type];
|
||||||
|
for (const map of mapping || []) {
|
||||||
|
if (commandExists(map.command) && map.desktops.some((d) => d === "*" || desktop.includes(d))) {
|
||||||
|
return map.command;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.warn("No display command available");
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the current display power status using the available command.
|
||||||
*
|
*
|
||||||
* @returns {string|null} The display status as 'ON'/'OFF' or null if an error occurs.
|
* @returns {string|null} The display status as 'ON'/'OFF' or null if an error occurs.
|
||||||
*/
|
*/
|
||||||
@@ -379,23 +447,26 @@ const getDisplayStatus = () => {
|
|||||||
if (!HARDWARE.support.displayStatus) {
|
if (!HARDWARE.support.displayStatus) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
switch (HARDWARE.session.type) {
|
switch (HARDWARE.display.status.command) {
|
||||||
case "wayland":
|
case "wlopm":
|
||||||
if (commandExists("wlopm")) {
|
const wlopm = execSyncCommand("wlopm", []);
|
||||||
const status = execSyncCommand("wlopm", []);
|
if (wlopm !== null) {
|
||||||
if (status !== null) {
|
const out = wlopm.split("\n")[0].split(" ");
|
||||||
const out = status.split("\n")[0].split(" ");
|
return out.pop().toUpperCase();
|
||||||
return out.pop().toUpperCase();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "x11":
|
case "kscreen-doctor":
|
||||||
if (commandExists("xset")) {
|
const kdoc = execSyncCommand("kscreen-doctor", ["--dpms", "show"]);
|
||||||
const status = execSyncCommand("xset", ["-q"]);
|
if (kdoc !== null) {
|
||||||
if (status !== null) {
|
const out = kdoc.split("\n")[0].split(" ");
|
||||||
const on = /Monitor is On/.test(status);
|
return out.pop().toUpperCase();
|
||||||
return on ? "ON" : "OFF";
|
}
|
||||||
}
|
break;
|
||||||
|
case "xset":
|
||||||
|
const xset = execSyncCommand("xset", ["-q"]);
|
||||||
|
if (xset !== null) {
|
||||||
|
const on = /Monitor is On/.test(xset);
|
||||||
|
return on ? "ON" : "OFF";
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -403,7 +474,7 @@ const getDisplayStatus = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the display power status using `wlopm` or `xset`.
|
* Sets the display power status using the available command.
|
||||||
*
|
*
|
||||||
* This function takes a desired status ('ON' or 'OFF') and executes
|
* This function takes a desired status ('ON' or 'OFF') and executes
|
||||||
* the appropriate command to set the display status.
|
* the appropriate command to set the display status.
|
||||||
@@ -421,19 +492,16 @@ const setDisplayStatus = (status, callback = null) => {
|
|||||||
if (typeof callback === "function") callback(null, "Invalid status");
|
if (typeof callback === "function") callback(null, "Invalid status");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
switch (HARDWARE.session.type) {
|
switch (HARDWARE.display.status.command) {
|
||||||
case "wayland":
|
case "wlopm":
|
||||||
if (commandExists("wlopm")) {
|
execAsyncCommand("wlopm", [`--${status.toLowerCase()}`, "*"], callback);
|
||||||
execAsyncCommand("wlopm", [`--${status.toLowerCase()}`, "*"], callback);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case "x11":
|
case "kscreen-doctor":
|
||||||
if (commandExists("xset")) {
|
execAsyncCommand("kscreen-doctor", ["--dpms", status.toLowerCase()], callback);
|
||||||
execAsyncCommand("xset", ["dpms", "force", status.toLowerCase()], callback);
|
break;
|
||||||
}
|
case "xset":
|
||||||
|
execAsyncCommand("xset", ["dpms", "force", status.toLowerCase()], callback);
|
||||||
break;
|
break;
|
||||||
default:
|
|
||||||
if (typeof callback === "function") callback(null, "Invalid session type");
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -460,7 +528,7 @@ const getDisplayBrightnessPath = () => {
|
|||||||
* @returns {number|null} The brightness maximum value or null if an error occurs.
|
* @returns {number|null} The brightness maximum value or null if an error occurs.
|
||||||
*/
|
*/
|
||||||
const getDisplayBrightnessMax = () => {
|
const getDisplayBrightnessMax = () => {
|
||||||
if (!HARDWARE.support.displayBrightness) {
|
if (!HARDWARE.display.brightness.path) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const max = fs.readFileSync(`${HARDWARE.display.brightness.path}/max_brightness`, "utf8").trim();
|
const max = fs.readFileSync(`${HARDWARE.display.brightness.path}/max_brightness`, "utf8").trim();
|
||||||
@@ -506,7 +574,7 @@ const setDisplayBrightness = (brightness, callback = null) => {
|
|||||||
if (typeof callback === "function") callback(null, "Invalid brightness");
|
if (typeof callback === "function") callback(null, "Invalid brightness");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const max = HARDWARE.display.brightness.max;
|
const max = HARDWARE.display.brightness.max || 1;
|
||||||
const value = Math.max(1, Math.min(Math.round((brightness / 100) * max), max));
|
const value = Math.max(1, Math.min(Math.round((brightness / 100) * max), max));
|
||||||
const proc = execAsyncCommand("sudo", ["tee", `${HARDWARE.display.brightness.path}/brightness`], callback);
|
const proc = execAsyncCommand("sudo", ["tee", `${HARDWARE.display.brightness.path}/brightness`], callback);
|
||||||
proc.stdin.write(value.toString());
|
proc.stdin.write(value.toString());
|
||||||
@@ -686,9 +754,9 @@ const dbusCall = (path, method, values, callback = null) => {
|
|||||||
const dest = `${iface} ${path} ${iface}.${method} ${values.join(" ")}`;
|
const dest = `${iface} ${path} ${iface}.${method} ${values.join(" ")}`;
|
||||||
const args = ["--print-reply", "--type=method_call", `--dest=${dest}`];
|
const args = ["--print-reply", "--type=method_call", `--dest=${dest}`];
|
||||||
try {
|
try {
|
||||||
const output = cpr.execSync([cmd, ...args].join(" "), { encoding: "utf8" });
|
const output = cpr.execSync([cmd, ...args].join(" ").trim(), { encoding: "utf8" });
|
||||||
if (typeof callback === "function") {
|
if (typeof callback === "function") {
|
||||||
callback(output.trim().replace(/\0/g, ""), null);
|
callback(output.trim().replace(/\0/g, "").split("\n").slice(1).join("\n").trim(), null);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Call D-Bus:", error.message);
|
console.error("Call D-Bus:", error.message);
|
||||||
@@ -777,13 +845,9 @@ module.exports = {
|
|||||||
getMemoryUsage,
|
getMemoryUsage,
|
||||||
getProcessorUsage,
|
getProcessorUsage,
|
||||||
getProcessorTemperature,
|
getProcessorTemperature,
|
||||||
getBatteryLevelPath,
|
|
||||||
getBatteryLevel,
|
getBatteryLevel,
|
||||||
getDisplayStatusPath,
|
|
||||||
getDisplayStatus,
|
getDisplayStatus,
|
||||||
setDisplayStatus,
|
setDisplayStatus,
|
||||||
getDisplayBrightnessPath,
|
|
||||||
getDisplayBrightnessMax,
|
|
||||||
getDisplayBrightness,
|
getDisplayBrightness,
|
||||||
setDisplayBrightness,
|
setDisplayBrightness,
|
||||||
getKeyboardVisibility,
|
getKeyboardVisibility,
|
||||||
|
|||||||
+14
-4
@@ -337,13 +337,23 @@ const initDisplay = () => {
|
|||||||
if (topic === config.command_topic) {
|
if (topic === config.command_topic) {
|
||||||
const status = message.toString();
|
const status = message.toString();
|
||||||
console.log("Set Display Status:", status);
|
console.log("Set Display Status:", status);
|
||||||
hardware.setDisplayStatus(status);
|
hardware.setDisplayStatus(status, (reply, error) => {
|
||||||
hardware.update();
|
if (error) {
|
||||||
|
console.warn("Failed:", error);
|
||||||
|
} else {
|
||||||
|
hardware.update();
|
||||||
|
}
|
||||||
|
});
|
||||||
} else if (topic === config.brightness_command_topic) {
|
} else if (topic === config.brightness_command_topic) {
|
||||||
const brightness = parseInt(message, 10);
|
const brightness = parseInt(message, 10);
|
||||||
console.log("Set Display Brightness:", brightness);
|
console.log("Set Display Brightness:", brightness);
|
||||||
hardware.setDisplayBrightness(brightness);
|
hardware.setDisplayBrightness(brightness, (reply, error) => {
|
||||||
hardware.update();
|
if (error) {
|
||||||
|
console.warn("Failed:", error);
|
||||||
|
} else {
|
||||||
|
hardware.update();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.subscribe(config.command_topic)
|
.subscribe(config.command_topic)
|
||||||
|
|||||||
Reference in New Issue
Block a user