feat(ags pointers): add GUdev and update processes on added/removed
This commit is contained in:
parent
25a0cb5c5d
commit
e6cbee084f
3 changed files with 57 additions and 34 deletions
|
@ -1,6 +1,7 @@
|
||||||
{
|
{
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@girs/gtk-3.0": "^3.24.39-3.2.2",
|
"@girs/gtk-3.0": "^3.24.39-3.2.2",
|
||||||
|
"@girs/gudev-1.0": "^1.0.0-3.2.2",
|
||||||
"eslint": "^8.52.0",
|
"eslint": "^8.52.0",
|
||||||
"stylelint-config-standard-scss": "^11.0.0"
|
"stylelint-config-standard-scss": "^11.0.0"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,19 @@
|
||||||
// TODO: read /dev to recalculate devices and remake subprocess
|
|
||||||
|
|
||||||
import { Service, Utils } from '../imports.js';
|
import { Service, Utils } from '../imports.js';
|
||||||
|
import GUdev from 'gi://GUdev';
|
||||||
|
|
||||||
|
const UDEV_POINTERS = [
|
||||||
|
'ID_INPUT_MOUSE',
|
||||||
|
'ID_INPUT_POINTINGSTICK',
|
||||||
|
'ID_INPUT_TOUCHPAD',
|
||||||
|
'ID_INPUT_TOUCHSCREEN',
|
||||||
|
'ID_INPUT_TABLET',
|
||||||
|
];
|
||||||
|
const LIB_POINTERS = [
|
||||||
|
'BTN',
|
||||||
|
'released',
|
||||||
|
'TOUCH_UP',
|
||||||
|
'HOLD_END',
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
class Pointers extends Service {
|
class Pointers extends Service {
|
||||||
|
@ -15,7 +28,8 @@ class Pointers extends Service {
|
||||||
|
|
||||||
proc = undefined;
|
proc = undefined;
|
||||||
output = '';
|
output = '';
|
||||||
devices = new Map();
|
devices = [];
|
||||||
|
udevClient = GUdev.Client.new(['input']);
|
||||||
|
|
||||||
get process() { return this.proc; }
|
get process() { return this.proc; }
|
||||||
get lastLine() { return this.output; }
|
get lastLine() { return this.output; }
|
||||||
|
@ -23,32 +37,36 @@ class Pointers extends Service {
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
this.parseDevices();
|
this.initUdevConnection();
|
||||||
}
|
}
|
||||||
|
|
||||||
parseDevices() {
|
// FIXME: logitech mouse screws everything up on disconnect
|
||||||
Utils.execAsync(['libinput', 'list-devices']).then(out => {
|
getDevices() {
|
||||||
const lines = out.split('\n');
|
this.devices = [];
|
||||||
let device = null;
|
this.udevClient.query_by_subsystem('input').forEach(dev => {
|
||||||
const devices = new Map();
|
const isPointer = UDEV_POINTERS.some(p => dev.has_property(p));
|
||||||
|
if (isPointer) {
|
||||||
lines.forEach(line => {
|
const hasEventFile = dev.has_property('DEVNAME') &&
|
||||||
const parts = line.split(':');
|
dev.get_property('DEVNAME').includes('event');
|
||||||
|
if (hasEventFile)
|
||||||
if (parts[0] === 'Device') {
|
this.devices.push(dev.get_property('DEVNAME'));
|
||||||
device = {};
|
|
||||||
devices.set(parts[1].trim(), device);
|
|
||||||
}
|
|
||||||
else if (device && parts[1]) {
|
|
||||||
const key = parts[0].trim();
|
|
||||||
const value = parts[1].trim();
|
|
||||||
device[key] = value;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.devices = Array.from(devices).filter(dev => dev.Capabilities &&
|
|
||||||
dev.Capabilities.includes('pointer'));
|
|
||||||
this.emit('device-fetched', true);
|
this.emit('device-fetched', true);
|
||||||
}).catch(print);
|
}
|
||||||
|
|
||||||
|
initUdevConnection() {
|
||||||
|
this.getDevices();
|
||||||
|
this.udevClient.connect('uevent', (_, action) => {
|
||||||
|
if (action === 'add' || action === 'remove') {
|
||||||
|
this.getDevices();
|
||||||
|
if (this.proc) {
|
||||||
|
this.killProc();
|
||||||
|
this.startProc();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
startProc() {
|
startProc() {
|
||||||
|
@ -57,21 +75,19 @@ class Pointers extends Service {
|
||||||
|
|
||||||
const args = [];
|
const args = [];
|
||||||
this.devices.forEach(dev => {
|
this.devices.forEach(dev => {
|
||||||
if (dev.Kernel) {
|
|
||||||
args.push('--device');
|
args.push('--device');
|
||||||
args.push(dev.Kernel);
|
args.push(dev);
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.proc = Utils.subprocess(
|
this.proc = Utils.subprocess(
|
||||||
['libinput', 'debug-events', ...args],
|
['libinput', 'debug-events', ...args],
|
||||||
output => {
|
output => {
|
||||||
if (output.includes('BTN') && output.includes('released') ||
|
if (!output.includes('cancelled')) {
|
||||||
output.includes('TOUCH_UP') ||
|
if (LIB_POINTERS.some(p => output.includes(p))) {
|
||||||
output.includes('HOLD_END') && !output.includes('cancelled')) {
|
|
||||||
this.output = output;
|
this.output = output;
|
||||||
this.emit('new-line', output);
|
this.emit('new-line', output);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
err => logError(err),
|
err => logError(err),
|
||||||
);
|
);
|
||||||
|
|
|
@ -11,8 +11,14 @@ in {
|
||||||
|
|
||||||
programs.ags = {
|
programs.ags = {
|
||||||
enable = true;
|
enable = true;
|
||||||
package = ags.packages.x86_64-linux.default;
|
|
||||||
configDir = symlink "${configDir}/ags";
|
configDir = symlink "${configDir}/ags";
|
||||||
|
package = (ags.packages.x86_64-linux.default.overrideAttrs
|
||||||
|
(_: prev: {
|
||||||
|
buildInputs = with pkgs; prev.buildInputs ++ [
|
||||||
|
libgudev
|
||||||
|
];
|
||||||
|
})
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
wayland.windowManager.hyprland = {
|
wayland.windowManager.hyprland = {
|
||||||
|
|
Loading…
Reference in a new issue