dot/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/components/atspi.js

300 lines
8.8 KiB
JavaScript
Raw Normal View History

2020-05-11 09:16:27 +00:00
'use strict';
imports.gi.versions.Atspi = '2.0';
const Atspi = imports.gi.Atspi;
const Gdk = imports.gi.Gdk;
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const GObject = imports.gi.GObject;
const Gtk = imports.gi.Gtk;
/**
* Printable ASCII range
*/
const _ASCII = /[\x20-\x7E]/;
/**
* Modifier Keycode Defaults
*/
const XKeycode = {
Alt_L: 0x40,
Control_L: 0x25,
Shift_L: 0x32,
Super_L: 0x85
};
var Controller = class {
constructor() {
// Atspi.init() return 2 on fail, but still marks itself as inited. We
// uninit before throwing an error otherwise any future call to init()
// will appear successful and other calls will cause GSConnect to exit.
// See: https://gitlab.gnome.org/GNOME/at-spi2-core/blob/master/atspi/atspi-misc.c
if (Atspi.init() === 2) {
this.destroy();
throw new Error('Failed to start AT-SPI');
}
try {
this._display = Gdk.Display.get_default();
this._seat = this._display.get_default_seat();
this._pointer = this._seat.get_pointer();
} catch (e) {
this.destroy();
throw e;
}
// Try to read modifier keycodes from Gdk
try {
let keymap = Gdk.Keymap.get_for_display(this._display);
let modifier;
modifier = keymap.get_entries_for_keyval(Gdk.KEY_Alt_L)[1][0];
XKeycode.Alt_L = modifier.keycode;
modifier = keymap.get_entries_for_keyval(Gdk.KEY_Control_L)[1][0];
XKeycode.Control_L = modifier.keycode;
modifier = keymap.get_entries_for_keyval(Gdk.KEY_Shift_L)[1][0];
XKeycode.Shift_L = modifier.keycode;
modifier = keymap.get_entries_for_keyval(Gdk.KEY_Super_L)[1][0];
XKeycode.Super_L = modifier.keycode;
} catch (e) {
debug('using default modifier keycodes');
}
}
/**
* Pointer events
*/
clickPointer(button) {
try {
let [, x, y] = this._pointer.get_position();
let monitor = this._display.get_monitor_at_point(x, y);
let scale = monitor.get_scale_factor();
Atspi.generate_mouse_event(scale * x, scale * y, `b${button}c`);
} catch (e) {
logError(e);
}
}
doubleclickPointer(button) {
try {
let [, x, y] = this._pointer.get_position();
let monitor = this._display.get_monitor_at_point(x, y);
let scale = monitor.get_scale_factor();
Atspi.generate_mouse_event(scale * x, scale * y, `b${button}d`);
} catch (e) {
logError(e);
}
}
movePointer(dx, dy) {
try {
let [, x, y] = this._pointer.get_position();
let monitor = this._display.get_monitor_at_point(x, y);
let scale = monitor.get_scale_factor();
Atspi.generate_mouse_event(scale * dx, scale * dy, 'rel');
} catch (e) {
logError(e);
}
}
pressPointer(button) {
try {
let [, x, y] = this._pointer.get_position();
let monitor = this._display.get_monitor_at_point(x, y);
let scale = monitor.get_scale_factor();
Atspi.generate_mouse_event(scale * x, scale * y, `b${button}p`);
} catch (e) {
logError(e);
}
}
releasePointer(button) {
try {
let [, x, y] = this._pointer.get_position();
let monitor = this._display.get_monitor_at_point(x, y);
let scale = monitor.get_scale_factor();
Atspi.generate_mouse_event(scale * x, scale * y, `b${button}r`);
} catch (e) {
logError(e);
}
}
scrollPointer(dx, dy) {
if (dy > 0) {
this.clickPointer(4);
} else if (dy < 0) {
this.clickPointer(5);
}
}
/**
* Phony virtual keyboard helpers
*/
_modeLock(keycode) {
Atspi.generate_keyboard_event(
keycode,
null,
Atspi.KeySynthType.PRESS
);
}
_modeUnlock(keycode) {
Atspi.generate_keyboard_event(
keycode,
null,
Atspi.KeySynthType.RELEASE
);
}
/**
* Simulate a printable-ASCII character.
*
*/
_pressASCII(key, modifiers) {
try {
// Press Modifiers
if (modifiers & Gdk.ModifierType.MOD1_MASK) this._modeLock(XKeycode.Alt_L);
if (modifiers & Gdk.ModifierType.CONTROL_MASK) this._modeLock(XKeycode.Control_L);
if (modifiers & Gdk.ModifierType.SHIFT_MASK) this._modeLock(XKeycode.Shift_L);
if (modifiers & Gdk.ModifierType.SUPER_MASK) this._modeLock(XKeycode.Super_L);
Atspi.generate_keyboard_event(
0,
key,
Atspi.KeySynthType.STRING
);
// Release Modifiers
if (modifiers & Gdk.ModifierType.MOD1_MASK) this._modeUnlock(XKeycode.Alt_L);
if (modifiers & Gdk.ModifierType.CONTROL_MASK) this._modeUnlock(XKeycode.Control_L);
if (modifiers & Gdk.ModifierType.SHIFT_MASK) this._modeUnlock(XKeycode.Shift_L);
if (modifiers & Gdk.ModifierType.SUPER_MASK) this._modeUnlock(XKeycode.Super_L);
} catch (e) {
logError(e);
}
}
_pressKeysym(keysym, modifiers) {
try {
// Press Modifiers
if (modifiers & Gdk.ModifierType.MOD1_MASK) this._modeLock(XKeycode.Alt_L);
if (modifiers & Gdk.ModifierType.CONTROL_MASK) this._modeLock(XKeycode.Control_L);
if (modifiers & Gdk.ModifierType.SHIFT_MASK) this._modeLock(XKeycode.Shift_L);
if (modifiers & Gdk.ModifierType.SUPER_MASK) this._modeLock(XKeycode.Super_L);
Atspi.generate_keyboard_event(
keysym,
null,
Atspi.KeySynthType.PRESSRELEASE | Atspi.KeySynthType.SYM
);
// Release Modifiers
if (modifiers & Gdk.ModifierType.MOD1_MASK) this._modeUnlock(XKeycode.Alt_L);
if (modifiers & Gdk.ModifierType.CONTROL_MASK) this._modeUnlock(XKeycode.Control_L);
if (modifiers & Gdk.ModifierType.SHIFT_MASK) this._modeUnlock(XKeycode.Shift_L);
if (modifiers & Gdk.ModifierType.SUPER_MASK) this._modeUnlock(XKeycode.Super_L);
} catch (e) {
logError(e);
}
}
/**
* Simulate the composition of a unicode character with:
* Control+Shift+u, [hex], Return
*
* @param {object} input - 'body' of a 'kdeconnect.mousepad.request' packet
*/
_pressUnicode(key, modifiers) {
try {
if (modifiers > 0) {
log('GSConnect: ignoring modifiers for unicode keyboard event');
}
// TODO: Using Control and Shift keysym is not working (it triggers
// key release). Probably using LOCKMODIFIERS will not work either
// as unlocking the modifier will not trigger a release
// Activate compose sequence
this._modeLock(XKeycode.Control_L);
this._modeLock(XKeycode.Shift_L);
this.pressreleaseKeysym(Gdk.KEY_U);
this._modeUnlock(XKeycode.Control_L);
this._modeUnlock(XKeycode.Shift_L);
// Enter the unicode sequence
let ucode = key.charCodeAt(0).toString(16);
let keysym;
for (let h = 0, len = ucode.length; h < len; h++) {
keysym = Gdk.unicode_to_keyval(ucode.charAt(h).codePointAt(0));
this.pressreleaseKeysym(keysym);
}
// Finish the compose sequence
this.pressreleaseKeysym(Gdk.KEY_Return);
} catch (e) {
logError(e);
}
}
/**
* Keyboard Events
*/
pressKeysym(keysym) {
Atspi.generate_keyboard_event(
keysym,
null,
Atspi.KeySynthType.PRESS | Atspi.KeySynthType.SYM
);
}
releaseKeysym(keysym) {
Atspi.generate_keyboard_event(
keysym,
null,
Atspi.KeySynthType.RELEASE | Atspi.KeySynthType.SYM
);
}
pressreleaseKeysym(keysym) {
Atspi.generate_keyboard_event(
keysym,
null,
Atspi.KeySynthType.PRESSRELEASE | Atspi.KeySynthType.SYM
);
}
pressKey(input, modifiers) {
// We were passed a keysym
if (typeof input === 'number') {
this._pressKeysym(input, modifiers);
// Regular ASCII
} else if (_ASCII.test(input)) {
this._pressASCII(input, modifiers);
// Unicode
} else {
this._pressUnicode(input, modifiers);
}
}
destroy() {
try {
Atspi.exit();
} catch (e) {
// Silence errors
}
}
};