2023-11-13 13:19:14 -05:00
|
|
|
import Hyprland from 'resource:///com/github/Aylur/ags/service/hyprland.js';
|
2023-11-04 13:35:09 -04:00
|
|
|
import Service from 'resource:///com/github/Aylur/ags/service.js';
|
2023-11-05 01:39:44 -05:00
|
|
|
import TouchGestures from './touch-gestures.js';
|
2023-11-04 13:35:09 -04:00
|
|
|
import { execAsync, subprocess } from 'resource:///com/github/Aylur/ags/utils.js';
|
|
|
|
import GUdev from 'gi://GUdev';
|
|
|
|
|
2023-11-21 01:29:46 -05:00
|
|
|
const ROTATION_MAP = {
|
2023-11-04 13:35:09 -04:00
|
|
|
'normal': 0,
|
|
|
|
'right-up': 3,
|
|
|
|
'bottom-up': 2,
|
|
|
|
'left-up': 1,
|
|
|
|
};
|
|
|
|
const SCREEN = 'desc:BOE 0x0964';
|
|
|
|
|
|
|
|
|
|
|
|
class Tablet extends Service {
|
|
|
|
static {
|
|
|
|
Service.register(this, {
|
|
|
|
'device-fetched': ['boolean'],
|
|
|
|
'autorotate-started': ['boolean'],
|
|
|
|
'autorotate-destroyed': ['boolean'],
|
|
|
|
'inputs-blocked': ['boolean'],
|
|
|
|
'inputs-unblocked': ['boolean'],
|
|
|
|
'laptop-mode': ['boolean'],
|
|
|
|
'tablet-mode': ['boolean'],
|
|
|
|
'mode-toggled': ['boolean'],
|
2023-11-04 18:51:59 -04:00
|
|
|
'osk-toggled': ['boolean'],
|
2023-11-04 13:35:09 -04:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2023-11-21 01:29:46 -05:00
|
|
|
#tabletMode = false;
|
|
|
|
#oskState = false;
|
|
|
|
#autorotate;
|
|
|
|
#blockedInputs;
|
|
|
|
#udevClient = GUdev.Client.new(['input']);
|
2023-11-04 13:35:09 -04:00
|
|
|
|
2023-11-21 01:29:46 -05:00
|
|
|
get tabletMode() {
|
|
|
|
return this.#tabletMode;
|
|
|
|
}
|
|
|
|
|
|
|
|
get oskState() {
|
|
|
|
return this.#oskState;
|
|
|
|
}
|
2023-11-04 13:35:09 -04:00
|
|
|
|
|
|
|
constructor() {
|
|
|
|
super();
|
2023-11-21 01:29:46 -05:00
|
|
|
this.#initUdevConnection();
|
|
|
|
this.#listenOskState();
|
2023-11-04 13:35:09 -04:00
|
|
|
}
|
|
|
|
|
2023-11-21 01:29:46 -05:00
|
|
|
#blockInputs() {
|
|
|
|
if (this.#blockedInputs) {
|
2023-11-04 13:35:09 -04:00
|
|
|
return;
|
2023-11-21 01:29:46 -05:00
|
|
|
}
|
2023-11-04 13:35:09 -04:00
|
|
|
|
2023-11-21 01:29:46 -05:00
|
|
|
this.#blockedInputs = subprocess(['libinput', 'debug-events', '--grab',
|
2023-11-04 13:35:09 -04:00
|
|
|
'--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',
|
2023-11-21 01:29:46 -05:00
|
|
|
'--device', '/dev/touchpad'],
|
|
|
|
() => { /**/ },
|
|
|
|
(err) => logError(err));
|
2023-11-04 13:35:09 -04:00
|
|
|
this.emit('inputs-blocked', true);
|
|
|
|
}
|
|
|
|
|
2023-11-21 01:29:46 -05:00
|
|
|
#unblockInputs() {
|
|
|
|
if (this.#blockedInputs) {
|
|
|
|
this.#blockedInputs.force_exit();
|
|
|
|
this.#blockedInputs = null;
|
2023-11-04 13:35:09 -04:00
|
|
|
this.emit('inputs-unblocked', true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
setTabletMode() {
|
|
|
|
execAsync(['gsettings', 'set', 'org.gnome.desktop.a11y.applications',
|
|
|
|
'screen-keyboard-enabled', 'true']).catch(print);
|
|
|
|
|
|
|
|
execAsync(['brightnessctl', '-d', 'tpacpi::kbd_backlight', 's', '0'])
|
|
|
|
.catch(print);
|
|
|
|
|
|
|
|
this.startAutorotate();
|
2023-11-21 01:29:46 -05:00
|
|
|
this.#blockInputs();
|
2023-11-04 13:35:09 -04:00
|
|
|
|
2023-11-21 01:29:46 -05:00
|
|
|
this.#tabletMode = true;
|
2023-11-04 13:35:09 -04:00
|
|
|
this.emit('tablet-mode', true);
|
|
|
|
this.emit('mode-toggled', true);
|
|
|
|
}
|
|
|
|
|
|
|
|
setLaptopMode() {
|
|
|
|
execAsync(['gsettings', 'set', 'org.gnome.desktop.a11y.applications',
|
|
|
|
'screen-keyboard-enabled', 'false']).catch(print);
|
|
|
|
|
|
|
|
execAsync(['brightnessctl', '-d', 'tpacpi::kbd_backlight', 's', '2'])
|
|
|
|
.catch(print);
|
|
|
|
|
|
|
|
this.killAutorotate();
|
2023-11-21 01:29:46 -05:00
|
|
|
this.#unblockInputs();
|
2023-11-04 13:35:09 -04:00
|
|
|
|
2023-11-21 01:29:46 -05:00
|
|
|
this.#tabletMode = false;
|
2023-11-04 13:35:09 -04:00
|
|
|
this.emit('laptop-mode', true);
|
|
|
|
this.emit('mode-toggled', true);
|
|
|
|
}
|
|
|
|
|
|
|
|
toggleMode() {
|
2023-11-21 01:29:46 -05:00
|
|
|
if (this.#tabletMode) {
|
2023-11-04 13:35:09 -04:00
|
|
|
this.setLaptopMode();
|
2023-11-21 01:29:46 -05:00
|
|
|
}
|
|
|
|
else {
|
2023-11-04 13:35:09 -04:00
|
|
|
this.setTabletMode();
|
2023-11-21 01:29:46 -05:00
|
|
|
}
|
2023-11-04 13:35:09 -04:00
|
|
|
|
|
|
|
this.emit('mode-toggled', true);
|
|
|
|
}
|
|
|
|
|
2023-11-21 01:29:46 -05:00
|
|
|
#initUdevConnection() {
|
|
|
|
this.#getDevices();
|
|
|
|
this.#udevClient.connect('uevent', (_, action) => {
|
|
|
|
if (action === 'add' || action === 'remove') {
|
|
|
|
this.#getDevices();
|
|
|
|
}
|
2023-11-04 13:35:09 -04:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2023-11-21 01:29:46 -05:00
|
|
|
#getDevices() {
|
2023-11-04 13:35:09 -04:00
|
|
|
this.devices = [];
|
2023-11-21 01:29:46 -05:00
|
|
|
Hyprland.sendMessage('j/devices').then((out) => {
|
2023-11-04 13:35:09 -04:00
|
|
|
const devices = JSON.parse(out);
|
2023-11-21 01:29:46 -05:00
|
|
|
|
|
|
|
devices.touch.forEach((dev) => {
|
2023-11-04 13:35:09 -04:00
|
|
|
this.devices.push(dev.name);
|
|
|
|
});
|
2023-11-21 01:29:46 -05:00
|
|
|
devices.tablets.forEach((dev) => {
|
2023-11-04 13:35:09 -04:00
|
|
|
this.devices.push(dev.name);
|
|
|
|
});
|
|
|
|
}).catch(print);
|
|
|
|
|
|
|
|
this.emit('device-fetched', true);
|
|
|
|
}
|
|
|
|
|
|
|
|
startAutorotate() {
|
2023-11-21 01:29:46 -05:00
|
|
|
if (this.#autorotate) {
|
2023-11-04 13:35:09 -04:00
|
|
|
return;
|
2023-11-21 01:29:46 -05:00
|
|
|
}
|
2023-11-04 13:35:09 -04:00
|
|
|
|
2023-11-21 01:29:46 -05:00
|
|
|
this.#autorotate = subprocess(
|
2023-11-04 13:35:09 -04:00
|
|
|
['monitor-sensor'],
|
2023-11-21 01:29:46 -05:00
|
|
|
(output) => {
|
2023-11-04 13:35:09 -04:00
|
|
|
if (output.includes('orientation changed')) {
|
2023-11-21 01:29:46 -05:00
|
|
|
const orientation = ROTATION_MAP[output.split(' ').at(-1)];
|
2023-11-04 13:35:09 -04:00
|
|
|
|
2023-11-21 01:29:46 -05:00
|
|
|
Hyprland.sendMessage(
|
|
|
|
`keyword monitor ${SCREEN},transform,${orientation}`,
|
|
|
|
).catch(print);
|
2023-11-04 13:35:09 -04:00
|
|
|
|
2023-11-21 01:29:46 -05:00
|
|
|
const batchRotate = this.devices.map((dev) =>
|
2023-11-13 13:19:14 -05:00
|
|
|
`keyword device:${dev}:transform ${orientation}; `);
|
2023-11-21 01:29:46 -05:00
|
|
|
|
2023-11-13 13:19:14 -05:00
|
|
|
Hyprland.sendMessage(`[[BATCH]] ${batchRotate.flat()}`);
|
2023-11-05 01:39:44 -05:00
|
|
|
|
|
|
|
if (TouchGestures.gestureDaemon) {
|
|
|
|
TouchGestures.killDaemon();
|
|
|
|
TouchGestures.startDaemon();
|
|
|
|
}
|
2023-11-04 13:35:09 -04:00
|
|
|
}
|
|
|
|
},
|
2023-11-21 01:29:46 -05:00
|
|
|
(err) => logError(err),
|
2023-11-04 13:35:09 -04:00
|
|
|
);
|
|
|
|
this.emit('autorotate-started', true);
|
|
|
|
}
|
|
|
|
|
|
|
|
killAutorotate() {
|
2023-11-21 01:29:46 -05:00
|
|
|
if (this.#autorotate) {
|
|
|
|
this.#autorotate.force_exit();
|
|
|
|
this.#autorotate = null;
|
2023-11-04 13:35:09 -04:00
|
|
|
this.emit('autorotate-destroyed', true);
|
|
|
|
}
|
|
|
|
}
|
2023-11-04 18:51:59 -04:00
|
|
|
|
2023-11-21 01:29:46 -05:00
|
|
|
#listenOskState() {
|
2023-11-04 18:51:59 -04:00
|
|
|
subprocess(
|
|
|
|
['bash', '-c', 'busctl monitor --user sm.puri.OSK0'],
|
2023-11-21 01:29:46 -05:00
|
|
|
(output) => {
|
2023-11-04 18:51:59 -04:00
|
|
|
if (output.includes('BOOLEAN')) {
|
2023-11-21 01:29:46 -05:00
|
|
|
this.#oskState = output.match('true|false')[0] === 'true';
|
|
|
|
this.emit('osk-toggled', this.#oskState);
|
2023-11-04 18:51:59 -04:00
|
|
|
}
|
|
|
|
},
|
2023-11-21 01:29:46 -05:00
|
|
|
(err) => logError(err),
|
2023-11-04 18:51:59 -04:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2023-11-21 01:29:46 -05:00
|
|
|
static openOsk() {
|
2023-11-04 18:51:59 -04:00
|
|
|
execAsync(['busctl', 'call', '--user',
|
|
|
|
'sm.puri.OSK0', '/sm/puri/OSK0', 'sm.puri.OSK0',
|
|
|
|
'SetVisible', 'b', 'true'])
|
|
|
|
.catch(print);
|
|
|
|
}
|
|
|
|
|
2023-11-21 01:29:46 -05:00
|
|
|
static closeOsk() {
|
2023-11-04 18:51:59 -04:00
|
|
|
execAsync(['busctl', 'call', '--user',
|
|
|
|
'sm.puri.OSK0', '/sm/puri/OSK0', 'sm.puri.OSK0',
|
|
|
|
'SetVisible', 'b', 'false'])
|
|
|
|
.catch(print);
|
|
|
|
}
|
|
|
|
|
|
|
|
toggleOsk() {
|
2023-11-21 01:29:46 -05:00
|
|
|
if (this.#oskState) {
|
|
|
|
Tablet.closeOsk();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
Tablet.openOsk();
|
|
|
|
}
|
2023-11-04 18:51:59 -04:00
|
|
|
}
|
2023-11-04 13:35:09 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
const tabletService = new Tablet();
|
2023-11-21 01:29:46 -05:00
|
|
|
|
2023-11-04 13:35:09 -04:00
|
|
|
export default tabletService;
|