feat(ags pointers): add GUdev and update processes on added/removed

This commit is contained in:
matt1432 2023-10-24 14:21:33 -04:00
parent 25a0cb5c5d
commit e6cbee084f
3 changed files with 57 additions and 34 deletions

View file

@ -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"
} }

View file

@ -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) {
const hasEventFile = dev.has_property('DEVNAME') &&
dev.get_property('DEVNAME').includes('event');
if (hasEventFile)
this.devices.push(dev.get_property('DEVNAME'));
}
});
lines.forEach(line => { this.emit('device-fetched', true);
const parts = line.split(':'); }
if (parts[0] === 'Device') { initUdevConnection() {
device = {}; this.getDevices();
devices.set(parts[1].trim(), device); this.udevClient.connect('uevent', (_, action) => {
if (action === 'add' || action === 'remove') {
this.getDevices();
if (this.proc) {
this.killProc();
this.startProc();
} }
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);
}).catch(print);
} }
startProc() { startProc() {
@ -57,20 +75,18 @@ 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);
args.push(dev.Kernel);
}
}); });
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),

View file

@ -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 = {