nixos-configs/nixosModules/ags/config/services/tablet.ts
matt1432 24aa4b9842
All checks were successful
Discord / discord commits (push) Has been skipped
refactor: make modules independant and exposed in the flake for outside use
2024-08-02 22:32:29 -04:00

172 lines
4.6 KiB
TypeScript

const Hyprland = await Service.import('hyprland');
const { execAsync, subprocess } = Utils;
import TouchGestures from './touch-gestures.ts';
const ROTATION_MAP = {
'normal': 0,
'right-up': 3,
'bottom-up': 2,
'left-up': 1,
};
const SCREEN = 'desc:BOE 0x0964';
const DEVICES = [
'wacom-hid-52eb-finger',
'wacom-hid-52eb-pen',
];
// Types
import { Subprocess } from 'types/@girs/gio-2.0/gio-2.0.cjs';
class Tablet extends Service {
static {
Service.register(this, {
'device-fetched': ['boolean'],
'autorotate-started': ['boolean'],
'autorotate-destroyed': ['boolean'],
'autorotate-toggled': ['boolean'],
'inputs-blocked': ['boolean'],
'inputs-unblocked': ['boolean'],
'laptop-mode': ['boolean'],
'tablet-mode': ['boolean'],
'mode-toggled': ['boolean'],
'osk-toggled': ['boolean'],
});
}
#tabletMode = false;
#oskState = false;
#autorotate = null as Subprocess | null;
#blockedInputs = null as Subprocess | null;
get tabletMode() {
return this.#tabletMode;
}
get autorotateState() {
return this.#autorotate !== null;
}
get oskState() {
return this.#oskState;
}
set oskState(value: boolean) {
this.#oskState = value;
this.emit('osk-toggled', this.#oskState);
}
#blockInputs() {
if (this.#blockedInputs) {
return;
}
this.#blockedInputs = subprocess(['libinput', 'debug-events', '--grab',
'--device', '/dev/input/by-path/platform-i8042-serio-0-event-kbd',
'--device', '/dev/input/by-path/platform-i8042-serio-1-event-mouse',
'--device', '/dev/input/by-path/platform-AMDI0010:02-event-mouse',
'--device', '/dev/input/by-path/platform-thinkpad_acpi-event',
'--device', '/dev/video-bus'],
() => { /**/ });
this.emit('inputs-blocked', true);
}
#unblockInputs() {
if (this.#blockedInputs) {
this.#blockedInputs.force_exit();
this.#blockedInputs = null;
this.emit('inputs-unblocked', true);
}
}
setTabletMode() {
execAsync(['brightnessctl', '-d', 'tpacpi::kbd_backlight', 's', '0'])
.catch(print);
this.startAutorotate();
this.#blockInputs();
this.#tabletMode = true;
this.emit('tablet-mode', true);
this.emit('mode-toggled', true);
}
setLaptopMode() {
execAsync(['brightnessctl', '-d', 'tpacpi::kbd_backlight', 's', '2'])
.catch(print);
this.killAutorotate();
this.#unblockInputs();
this.#tabletMode = false;
this.emit('laptop-mode', true);
this.emit('mode-toggled', true);
}
toggleMode() {
if (this.#tabletMode) {
this.setLaptopMode();
}
else {
this.setTabletMode();
}
this.emit('mode-toggled', true);
}
startAutorotate() {
if (this.#autorotate) {
return;
}
this.#autorotate = subprocess(
['monitor-sensor'],
(output) => {
if (output.includes('orientation changed')) {
const index = output.split(' ').at(-1);
if (!index) {
return;
}
const orientation = ROTATION_MAP[index];
Hyprland.messageAsync(
`keyword monitor ${SCREEN},transform,${orientation}`,
).catch(print);
const batchRotate = DEVICES.map((dev) =>
`keyword device:${dev}:transform ${orientation}; `);
Hyprland.messageAsync(`[[BATCH]] ${batchRotate.flat()}`);
if (TouchGestures.gestureDaemon) {
TouchGestures.killDaemon();
TouchGestures.startDaemon();
}
}
},
);
this.emit('autorotate-started', true);
this.emit('autorotate-toggled', true);
}
killAutorotate() {
if (this.#autorotate) {
this.#autorotate.force_exit();
this.#autorotate = null;
this.emit('autorotate-destroyed', true);
this.emit('autorotate-toggled', false);
}
}
toggleOsk() {
this.#oskState = !this.#oskState;
this.emit('osk-toggled', this.#oskState);
}
}
const tabletService = new Tablet();
export default tabletService;