nixos-configs/modules/ags/config/services/tablet.ts

214 lines
5.2 KiB
TypeScript
Raw Permalink Normal View History

2024-11-25 12:09:03 -05:00
import { execAsync, subprocess } from 'astal';
import GObject, { register, property, signal } from 'astal/gobject';
import { hyprMessage } from '../lib';
/* Types */
import AstalIO from 'gi://AstalIO';
type RotationName = 'normal' | 'right-up' | 'bottom-up' | 'left-up';
const ROTATION_MAP: Record<RotationName, 0 | 1 | 2 | 3> = {
'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',
];
@register()
export default class Tablet extends GObject.Object {
@signal(Boolean)
declare autorotateChanged: (running: boolean) => void;
@signal(Boolean)
declare inputsChanged: (blocked: boolean) => void;
2024-12-14 19:36:54 -05:00
private _currentMode: 'laptop' | 'tablet' = 'laptop';
2024-11-25 12:09:03 -05:00
@property(String)
get currentMode() {
return this._currentMode;
}
set currentMode(val) {
this._currentMode = val;
if (this._currentMode === 'tablet') {
2024-12-14 19:36:54 -05:00
execAsync(['brightnessctl', '-d', 'tpacpi::kbd_backlight', 's', '0']).catch(print);
2024-11-25 12:09:03 -05:00
this.startAutorotate();
this._blockInputs();
2024-12-14 19:36:54 -05:00
this._startInputDetection();
2024-11-25 12:09:03 -05:00
}
else if (this._currentMode === 'laptop') {
2024-12-14 19:36:54 -05:00
execAsync(['brightnessctl', '-d', 'tpacpi::kbd_backlight', 's', '2']).catch(print);
2024-11-25 12:09:03 -05:00
this.killAutorotate();
this._unblockInputs();
2024-12-14 19:36:54 -05:00
this._stopInputDetection();
this.oskState = false;
2024-11-25 12:09:03 -05:00
}
this.notify('current-mode');
}
private _oskState = false;
@property(Boolean)
get oskState() {
return this._oskState;
}
set oskState(val) {
this._oskState = val;
2024-12-14 19:36:54 -05:00
// this is set to true after this setter in the request.
this.oskAutoChanged = false;
2024-11-25 12:09:03 -05:00
this.notify('osk-state');
}
public toggleOsk() {
this.oskState = !this.oskState;
}
2024-12-14 19:36:54 -05:00
private _oskAutoChanged = false;
@property(Boolean)
get oskAutoChanged() {
return this._oskAutoChanged;
}
set oskAutoChanged(val) {
this._oskAutoChanged = val;
}
private _inputDetection = null as AstalIO.Process | null;
private _startInputDetection() {
if (this._inputDetection) {
return;
}
this._inputDetection = subprocess([
'fcitx5',
'--disable', 'all',
'--enable', 'keyboard,virtualkeyboardadapter,wayland,waylandim',
]);
}
private _stopInputDetection() {
if (this._inputDetection) {
this._inputDetection.kill();
this._inputDetection = null;
}
}
2024-11-25 12:09:03 -05:00
private _autorotate = null as AstalIO.Process | null;
get autorotateState() {
return this._autorotate !== null;
}
private _blockedInputs = null as AstalIO.Process | null;
private _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-changed', true);
}
private _unblockInputs() {
if (this._blockedInputs) {
this._blockedInputs.kill();
this._blockedInputs = null;
this.emit('inputs-changed', false);
}
}
public toggleMode() {
if (this.currentMode === 'laptop') {
this.currentMode = 'tablet';
}
else if (this.currentMode === 'tablet') {
this.currentMode = 'laptop';
}
}
public startAutorotate() {
if (this._autorotate) {
return;
}
this._autorotate = subprocess(
['monitor-sensor'],
(output) => {
if (output.includes('orientation changed')) {
const index = output.split(' ').at(-1) as RotationName | undefined;
if (!index) {
return;
}
const orientation = ROTATION_MAP[index];
hyprMessage(
`keyword monitor ${SCREEN},transform,${orientation}`,
).catch(print);
const batchRotate = DEVICES.map((dev) =>
`keyword device:${dev}:transform ${orientation}; `);
hyprMessage(`[[BATCH]] ${batchRotate.flat()}`);
}
},
);
this.emit('autorotate-changed', true);
}
public killAutorotate() {
if (this._autorotate) {
this._autorotate.kill();
this._autorotate = null;
this.emit('autorotate-changed', false);
}
}
private static _default: InstanceType<typeof Tablet> | undefined;
public static get_default() {
if (!Tablet._default) {
Tablet._default = new Tablet();
}
return Tablet._default;
}
}