diff --git a/gnome/.local/share/gnome-shell/extensions/gjsosk@vishram1123.com/extension.js b/gnome/.local/share/gnome-shell/extensions/gjsosk@vishram1123.com/extension.js
index dbe70a7..9d858e4 100644
--- a/gnome/.local/share/gnome-shell/extensions/gjsosk@vishram1123.com/extension.js
+++ b/gnome/.local/share/gnome-shell/extensions/gjsosk@vishram1123.com/extension.js
@@ -6,7 +6,6 @@ import St from 'gi://St';
import Shell from 'gi://Shell';
-import * as EdgeDragAction from 'resource:///org/gnome/shell/ui/edgeDragAction.js';
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
import * as PanelMenu from 'resource:///org/gnome/shell/ui/panelMenu.js';
import * as PopupMenu from 'resource:///org/gnome/shell/ui/popupMenu.js';
@@ -17,7 +16,13 @@ import * as InputSourceManager from 'resource:///org/gnome/shell/ui/status/keybo
import * as Config from 'resource:///org/gnome/shell/misc/config.js'
const [major, minor] = Config.PACKAGE_VERSION.split('.').map(s => Number(s));
import { Dialog } from 'resource:///org/gnome/shell/ui/dialog.js';
-
+let EdgeDragAction = null;
+if (major < 49) {
+ try {
+ const edgedragimport = await import('resource:///org/gnome/shell/ui/edgeDragAction.js')
+ EdgeDragAction = edgedragimport ?? null
+ } catch { }
+}
import { Extension, gettext as _ } from 'resource:///org/gnome/shell/extensions/extension.js';
const State = {
@@ -82,12 +87,14 @@ export default class GjsOskExtension extends Extension {
_openKeyboard(instant) {
if (this.Keyboard.state == State.CLOSED) {
this.Keyboard.open(null, !instant ? null : true);
+ this.openBit.set_boolean('keyboard-visible', true);
}
}
_closeKeyboard(instant) {
if (this.Keyboard.state == State.OPENED) {
this.Keyboard.close(!instant ? null : true);
+ this.openBit.set_boolean('keyboard-visible', false);
}
}
@@ -104,7 +111,8 @@ export default class GjsOskExtension extends Extension {
}
open_interval() {
- global.stage.disconnect(this.tapConnect)
+ if (this.tapConnect && GObject.signal_handler_is_connected(global.stage, this.tapConnect))
+ global.stage.disconnect(this.tapConnect)
if (this.openInterval !== null) {
clearInterval(this.openInterval);
this.openInterval = null;
@@ -130,13 +138,26 @@ export default class GjsOskExtension extends Extension {
}, 300);
this.tapConnect = global.stage.connect("event", (_actor, event) => {
if (event.type() !== 4 && event.type() !== 5) {
- this.lastInputMethod = [false, event.type() >= 9 && event.type() <= 12, true][this.settings.get_int("enable-tap-gesture")]
+ this.lastInputMethod = [false, event.type() >= 9 && event.type() <= 12, true][this.settings.get_boolean("indicator-enabled") ? this.settings.get_int("enable-tap-gesture") : 0]
}
})
}
+ fail(error, method = null, instance = null) {
+ Main.notifyError("Error with extension GJS-OSK"
+ + (instance != null || method != null ? " in " : "")
+ + (instance != null ? instance + "." : "")
+ + (method != null ? method + "\n" : ""),
+ error.message
+ + "\n" + error.stack);
+ }
+
enable() {
this.settings = this.getSettings();
+ if (this.settings == null) {
+ return;
+ }
+ this.disableEdgeSwipeSettings = this.settings.get_boolean("disable-edge-swipe");
this.darkSchemeSettings = this.getSettings("org.gnome.desktop.interface");
this.inputLanguageSettings = InputSourceManager.getInputSourceManager();
this.gnomeKeyboardSettings = this.getSettings('org.gnome.desktop.a11y.applications');
@@ -158,44 +179,203 @@ export default class GjsOskExtension extends Extension {
}
let refresh = () => {
- // [insert handwriting 2]
- let currentMonitors = this.settings.get_string("default-monitor").split(";")
- let currentMonitorMap = {};
- let monitors = Main.layoutManager.monitors;
- for (var i of currentMonitors) {
- let tmp = i.split(":");
- currentMonitorMap[tmp[0]] = tmp[1] + "";
- }
- if (!Object.keys(currentMonitorMap).includes(monitors.length + "")) {
- let allConfigs = Object.keys(currentMonitorMap).map(Number.parseInt).sort();
- currentMonitorMap[monitors.length + ""] = allConfigs[allConfigs.length - 1];
- }
- try {
- currentMonitorId = global.backend.get_monitor_manager().get_monitor_for_connector(currentMonitorMap[monitors.length + ""]);
- if (currentMonitorId == -1) {
+ (async () => {
+ // [insert handwriting 2]
+ let prevOpenState = false;
+ if (this.Keyboard != null) {
+ prevOpenState = this.Keyboard.opened;
+ }
+ let currentMonitors = this.settings.get_string("default-monitor").split(";")
+ let currentMonitorMap = {};
+ let monitors = Main.layoutManager.monitors;
+ if (Main.layoutManager.primaryMonitor == null) {
+ this.waitRefresh = setTimeout(refresh, 1000)
+ return;
+ }
+ for (var i of currentMonitors) {
+ let tmp = i.split(":");
+ currentMonitorMap[tmp[0]] = tmp[1] + "";
+ }
+ if (!Object.keys(currentMonitorMap).includes(monitors.length + "")) {
+ let allConfigs = Object.keys(currentMonitorMap).map(Number.parseInt).sort();
+ currentMonitorMap[monitors.length + ""] = allConfigs[allConfigs.length - 1];
+ }
+ try {
+ currentMonitorId = global.backend.get_monitor_manager().get_monitor_for_connector(currentMonitorMap[monitors.length + ""]);
+ if (currentMonitorId == -1) {
+ currentMonitorId = 0;
+ }
+ } catch {
currentMonitorId = 0;
}
- } catch {
- currentMonitorId = 0;
- }
- if (!Gio.File.new_for_path(extract_dir).query_exists(null)) {
- Gio.File.new_for_path(extract_dir).make_directory(null);
- Gio.File.new_for_path(extract_dir + "/keycodes").make_directory(null);
- let [status, out, err, code] = GLib.spawn_command_line_sync("tar -Jxf " + this.path + "/keycodes.tar.xz -C " + extract_dir + "/keycodes")
- if (err != "" || code != 0) {
- throw new Error(err);
- }
- }
- if (this.Keyboard != null) {
- this.Keyboard.destroy();
- this.Keyboard = null;
- }
- let [ok, contents] = GLib.file_get_contents(extract_dir + "/keycodes/" + KeyboardManager.getKeyboardManager().currentLayout.id + '.json');
- if (ok) {
- keycodes = JSON.parse(contents);
- }
- this.Keyboard = new Keyboard(this.settings, this);
- this.Keyboard.refresh = refresh
+ const fileExists = async (file) => {
+ try {
+ return await new Promise((resolve) => {
+ file.query_info_async(
+ '*',
+ Gio.FileQueryInfoFlags.NONE,
+ GLib.PRIORITY_DEFAULT,
+ null,
+ (source, res) => {
+ try {
+ source.query_info_finish(res);
+ resolve(true);
+ } catch (e) {
+ resolve(false);
+ }
+ }
+ );
+ });
+ } catch (e) {
+ return false;
+ }
+ };
+
+ const ensureDirectory = async (dir) => {
+ try {
+ if (!(await fileExists(dir))) {
+ await new Promise((resolve, reject) => {
+ dir.make_directory_async(GLib.PRIORITY_DEFAULT, null, (source, res) => {
+ try {
+ source.make_directory_finish(res);
+ resolve();
+ } catch (e) {
+ if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.EXISTS)) {
+ reject(e);
+ } else {
+ resolve();
+ }
+ }
+ });
+ });
+ }
+ return true;
+ } catch (e) {
+ console.error(`Failed to create directory ${dir.get_path()}: ${e.message}`);
+ return false;
+ }
+ };
+
+ const runCommand = (argv) => {
+ return new Promise((resolve) => {
+ const proc = Gio.Subprocess.new(
+ argv,
+ Gio.SubprocessFlags.STDOUT_PIPE |
+ Gio.SubprocessFlags.STDERR_PIPE
+ );
+ proc.wait_check_async(null, (source, res) => {
+ try {
+ const success = source.wait_check_finish(res);
+ resolve(success);
+ } catch (e) {
+ console.error(`Command failed: ${argv.join(' ')}`);
+ resolve(false);
+ }
+ });
+ });
+ };
+
+ const extractKeycodes = async () => {
+ const baseDir = Gio.File.new_for_path(extract_dir);
+ const keycodesDir = Gio.File.new_for_path(extract_dir + "/keycodes");
+ const layoutId = KeyboardManager.getKeyboardManager().currentLayout?.id || "us";
+ const targetFile = Gio.File.new_for_path(`${extract_dir}/keycodes/${layoutId}.json`);
+
+ if (await fileExists(targetFile)) {
+ return true;
+ }
+
+ if (!(await ensureDirectory(baseDir))) {
+ console.error("Failed to create base directory");
+ return false;
+ }
+
+ if (!(await ensureDirectory(keycodesDir))) {
+ console.error("Failed to create keycodes directory");
+ return false;
+ }
+
+ try {
+ const success = await runCommand([
+ "tar",
+ "-Jxf",
+ this.path + "/keycodes.tar.xz",
+ "-C",
+ keycodesDir.get_path(),
+ "--strip-components=1"
+ ]);
+
+ if (!success) {
+ throw new Error("Failed to extract keycodes archive");
+ }
+
+ if (!(await fileExists(targetFile))) {
+ throw new Error("Keycodes file not found after extraction");
+ }
+
+ return true;
+ } catch (error) {
+ console.error(`Error extracting keycodes: ${error.message}`);
+ return false;
+ }
+ };
+
+ const initializeKeyboard = async () => {
+ const layoutId = KeyboardManager.getKeyboardManager().currentLayout?.id || "us";
+ const keycodesPath = GLib.build_filenamev([
+ extract_dir,
+ "keycodes",
+ `${layoutId}.json`
+ ]);
+
+ const [ok, contents] = GLib.file_get_contents(keycodesPath);
+ if (!ok) {
+ throw new Error(`Failed to read keycodes from ${keycodesPath}`);
+ }
+
+ keycodes = JSON.parse(contents);
+
+ if (this.Keyboard) {
+ this.Keyboard.destroy();
+ this.Keyboard = null;
+ }
+
+ if (this.settings == null) {
+ return;
+ }
+
+ function withErrorHandler(TargetClass, handler) {
+ return new Proxy(TargetClass, {
+ construct(Target, args) {
+ const instance = new Target(...args);
+ for (const key of Object.getOwnPropertyNames(Target.prototype)) {
+ const fn = instance[key];
+ if (typeof fn === "function" && key !== "constructor") {
+ instance[key] = async (...fnArgs) => {
+ try {
+ return await fn.apply(instance, fnArgs);
+ } catch (err) {
+ handler(err, key, instance);
+ }
+ };
+ }
+ }
+
+ return instance;
+ }
+ });
+ }
+ const SafeKeyboard = withErrorHandler(Keyboard, this.fail);
+ this.Keyboard = new SafeKeyboard(this.settings, this);
+ this.Keyboard.refresh = refresh;
+ if (prevOpenState) {
+ this.Keyboard.open(null, true);
+ this.openBit.set_boolean('keyboard-visible', true);
+ }
+ };
+ await extractKeycodes();
+ await initializeKeyboard();
+ })().catch(this.fail)
}
refresh()
@@ -226,21 +406,29 @@ export default class GjsOskExtension extends Extension {
this._quick_settings_indicator.quickSettingsItems.push(this._toggle);
Main.panel.statusArea.quickSettings.addExternalIndicator(this._quick_settings_indicator);
this.open_interval();
- this.openFromCommandHandler = this.openBit.connect("changed", () => {
- this.openBit.set_boolean("opened", false)
- this._toggleKeyboard();
- })
+
+ this.keyboardVisibilityHandler = this.openBit.connect('changed::keyboard-visible', () => {
+ const shouldBeVisible = this.openBit.get_boolean('keyboard-visible');
+ if (shouldBeVisible !== this.Keyboard?.opened) {
+ this._toggleKeyboard(true);
+ }
+ });
+
+ this.openFromCommandHandler = this.openBit.connect("changed::opened", () => {
+ if (this.openBit.get_boolean("opened")) {
+ this.openBit.set_boolean("opened", false);
+ this._toggleKeyboard();
+ }
+ });
+
+ if (this.openBit.get_boolean('keyboard-visible') && this.Keyboard) {
+ this._openKeyboard(true);
+ }
let settingsChanged = () => {
- let opened;
- if (this.Keyboard != null)
- opened = this.Keyboard.opened
- else
- opened = false
if (this.darkSchemeSettings.get_string("color-scheme") == "prefer-dark")
this.settings.scheme = "-dark"
else
this.settings.scheme = ""
- this.Keyboard.openedFromButton = false;
refresh()
this._toggle._refresh();
if (this.settings.get_boolean("indicator-enabled")) {
@@ -274,8 +462,24 @@ export default class GjsOskExtension extends Extension {
this.openInterval = null;
}
this.open_interval();
- if (opened) {
- this._toggleKeyboard(true);
+ let disableEdgeSwipe = this.settings.get_boolean("disable-edge-swipe");
+ if (this.disableEdgeSwipeSettings !== disableEdgeSwipe) {
+ this.disableEdgeSwipeSettings = disableEdgeSwipe;
+ if (disableEdgeSwipe) {
+ if (EdgeDragAction != null) {
+ global.stage.remove_action_by_name('osk');
+ } else {
+ global.stage.remove_action_by_name('GJS-OSK Edge Drag Action');
+ }
+ } else {
+ if (this.keyboard != null && this.keyboard.bottomDragAction != null) {
+ if (EdgeDragAction != null) {
+ global.stage.add_action_full('osk', Clutter.EventPhase.CAPTURE, this.keyboard.bottomDragAction);
+ } else {
+ global.stage.add_action(this.keyboard.bottomDragAction);
+ }
+ }
+ }
}
}
this.settingsHandlers = [
@@ -306,15 +510,24 @@ export default class GjsOskExtension extends Extension {
this.darkSchemeSettings = null;
this.inputLanguageSettings = null;
this.gnomeKeyboardSettings = null;
- this.openBit.disconnect(this.openFromCommandHandler);
+ if (this.keyboardVisibilityHandler) {
+ this.openBit.disconnect(this.keyboardVisibilityHandler);
+ this.keyboardVisibilityHandler = null;
+ }
+ if (this.openFromCommandHandler) {
+ this.openBit.disconnect(this.openFromCommandHandler);
+ this.openFromCommandHandler = null;
+ }
this.openBit = null;
global.stage.disconnect(this.tapConnect)
if (this.openInterval !== null) {
clearInterval(this.openInterval);
this.openInterval = null;
}
- this._toggle.destroy()
- this._toggle = null
+ if (this._toggle !== null) {
+ this._toggle.destroy()
+ this._toggle = null
+ }
this.settings = null
this.Keyboard = null
keycodes = null
@@ -341,14 +554,15 @@ class Keyboard extends Dialog {
this.settingsOpenFunction = extensionObject.openPrefs
this.inputDevice = Clutter.get_default_backend().get_default_seat().create_virtual_device(Clutter.InputDeviceType.KEYBOARD_DEVICE);
this.settings = settings;
- let monitor = Main.layoutManager.monitors[currentMonitorId];
- super._init(Main.layoutManager.modalDialogGroup, 'db-keyboard-content');
+ let monitor = Main.layoutManager.monitors[currentMonitorId] ?? Main.layoutManager.primaryMonitor;
+ super._init(Main.uiGroup, 'db-keyboard-content');
this.box = new St.Widget({
reactive: true,
layout_manager: new Clutter.GridLayout({
orientation: Clutter.Orientation.HORIZONTAL,
})
});
+ this.box.clear_actions();
this.widthPercent = (monitor.width > monitor.height) ? settings.get_int("landscape-width-percent") / 100 : settings.get_int("portrait-width-percent") / 100;
this.heightPercent = (monitor.width > monitor.height) ? settings.get_int("landscape-height-percent") / 100 : settings.get_int("portrait-height-percent") / 100;
this.nonDragBlocker = new Clutter.Actor();
@@ -367,7 +581,9 @@ class Keyboard extends Dialog {
this.state = State.CLOSED;
this.delta = [];
this.monitorChecker = global.backend.get_monitor_manager().connect('monitors-changed', () => {
- this.refresh()
+ if (Main.layoutManager.monitors.length > 0) {
+ this.refresh();
+ }
});
this._dragging = false;
let side = null;
@@ -389,41 +605,79 @@ class Keyboard extends Dialog {
side = St.Side.BOTTOM;
break;
}
- this.oldBottomDragAction = global.stage.get_action('osk');
+ this.oldBottomDragAction = global.stage.get_action(EdgeDragAction == null ? 'OSK show bottom drag' : 'osk');
if (this.oldBottomDragAction !== null && this.oldBottomDragAction instanceof Clutter.Action)
global.stage.remove_action(this.oldBottomDragAction);
if (side != null) {
const mode = Shell.ActionMode.ALL & ~Shell.ActionMode.LOCK_SCREEN;
- const bottomDragAction = new EdgeDragAction.EdgeDragAction(side, mode);
- bottomDragAction.connect('activated', () => {
- this.open(true);
- this.openedFromButton = true;
- this.closedFromButton = false;
- this.gestureInProgress = false;
- });
- bottomDragAction.connect('progress', (_action, progress) => {
- if (!this.gestureInProgress)
- this.open(false)
- this.setOpenState(Math.min(Math.max(0, (progress / (side % 2 == 0 ? this.box.height : this.box.width)) * 100), 100))
- this.gestureInProgress = true;
- });
- bottomDragAction.connect('gesture-cancel', () => {
- if (this.gestureInProgress) {
- this.close()
- this.openedFromButton = false;
- this.closedFromButton = true;
+ let oskEdgeDragAction;
+ if (EdgeDragAction != null) {
+ oskEdgeDragAction = new EdgeDragAction.EdgeDragAction(side, mode);
+ oskEdgeDragAction.connect('activated', () => {
+ this.open(true);
+ this.openedFromButton = true;
+ this.closedFromButton = false;
+ this.gestureInProgress = false;
+ });
+ oskEdgeDragAction.connect('gesture-cancel', () => {
+ if (this.gestureInProgress) {
+ this.close()
+ this.openedFromButton = false;
+ this.closedFromButton = true;
+ }
+ this.gestureInProgress = false;
+ return Clutter.EVENT_PROPAGATE;
+ });
+ oskEdgeDragAction.connect('progress', (_action, progress) => {
+ if (!this.gestureInProgress)
+ this.open(false)
+ this.setOpenState(Math.min(Math.max(0, (progress / (side % 2 == 0 ? this.box.height : this.box.width)) * 100), 100))
+ this.gestureInProgress = true;
+ });
+ if (!this.settings.get_boolean("disable-edge-swipe")) {
+ global.stage.add_action_full('osk', Clutter.EventPhase.CAPTURE, oskEdgeDragAction);
}
- this.gestureInProgress = false;
- return Clutter.EVENT_PROPAGATE;
- });
- global.stage.add_action_full('osk', Clutter.EventPhase.CAPTURE, bottomDragAction);
- this.bottomDragAction = bottomDragAction;
+ this.bottomDragAction = oskEdgeDragAction;
+ } else {
+ oskEdgeDragAction = new Shell.EdgeDragGesture({
+ name: 'GJS-OSK Edge Drag Action',
+ side
+ })
+ oskEdgeDragAction.connect('may-recognize', () => {
+ return Shell.ActionMode.ALL & ~Shell.ActionMode.LOCK_SCREEN & Main.actionMode;
+ })
+ oskEdgeDragAction.connect('end', () => {
+ this.open(true);
+ this.openedFromButton = true;
+ this.closedFromButton = false;
+ this.gestureInProgress = false;
+ });
+ oskEdgeDragAction.connect('cancel', () => {
+ if (this.gestureInProgress) {
+ this.close()
+ this.openedFromButton = false;
+ this.closedFromButton = true;
+ }
+ this.gestureInProgress = false;
+ return Clutter.EVENT_PROPAGATE;
+ });
+ oskEdgeDragAction.connect('progress', (_action, progress) => {
+ if (!this.gestureInProgress)
+ this.open(false)
+ this.setOpenState(Math.min(Math.max(0, (progress / (side % 2 == 0 ? this.box.height : this.box.width)) * 100), 100))
+ this.gestureInProgress = true;
+ });
+ if (!this.settings.get_boolean("disable-edge-swipe")) {
+ global.stage.add_action(oskEdgeDragAction);
+ }
+ this.bottomDragAction = oskEdgeDragAction;
+ }
} else {
this.bottomDragAction = null;
}
this._oldMaybeHandleEvent = Main.keyboard.maybeHandleEvent
Main.keyboard.maybeHandleEvent = (e) => {
- let lastInputMethod = [e.type() == 11, e.type() == 11, e.type() == 7 || e.type() == 11][this.settings.get_int("enable-tap-gesture")]
+ let lastInputMethod = [e.type() == 11, e.type() == 11, e.type() == 7 || e.type() == 11][this.settings.get_boolean("indicator-enabled") ? this.settings.get_int("enable-tap-gesture") : 0]
let ac = global.stage.get_event_actor(e)
if (this.contains(ac)) {
ac.event(e, true);
@@ -438,9 +692,14 @@ class Keyboard extends Dialog {
destroy() {
Main.keyboard.maybeHandleEvent = this._oldMaybeHandleEvent
- global.stage.remove_action_by_name('osk')
- if (this.oldBottomDragAction !== null && this.oldBottomDragAction instanceof Clutter.Action)
+ if (this.oldBottomDragAction !== null && this.oldBottomDragAction instanceof Clutter.Action && EdgeDragAction != null) {
+ global.stage.remove_action_by_name('osk')
global.stage.add_action_full('osk', Clutter.EventPhase.CAPTURE, this.oldBottomDragAction)
+ }
+ else if (this.oldBottomDragAction != null) {
+ global.stage.remove_action_by_name('GJS-OSK Edge Drag Action')
+ global.stage.add_action(this.oldBottomDragAction)
+ }
if (this.textboxChecker !== null) {
clearInterval(this.textboxChecker);
this.textboxChecker = null;
@@ -451,10 +710,16 @@ class Keyboard extends Dialog {
}
if (this.keyTimeout !== null) {
clearTimeout(this.keyTimeout);
+ if (typeof this.keyTimeoutFunc === 'function') {
+ this.keyTimeoutFunc();
+ }
this.keyTimeout = null;
+ this.keyTimeoutFunc = null;
}
- this.keymap.disconnect(this.capslockConnect);
- this.keymap.disconnect(this.numLockConnect);
+ if (this.capsLockConnect && GObject.signal_handler_is_connected(this.keymap, this.capsLockConnect))
+ this.keymap.disconnect(this.capsLockConnect);
+ if (this.numLockConnect && GObject.signal_handler_is_connected(this.keymap, this.numLockConnect))
+ this.keymap.disconnect(this.numLockConnect);
global.backend.get_monitor_manager().disconnect(this.monitorChecker)
super.destroy();
if (this.nonDragBlocker !== null) {
@@ -474,10 +739,8 @@ class Keyboard extends Dialog {
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onComplete: () => { }
});
- let device = event.get_device();
let sequence = event.get_event_sequence();
this._grab = global.stage.grab(this);
- this._grabbedDevice = device;
this._grabbedSequence = sequence;
this.emit('drag-begin');
let [absX, absY] = event.get_coords();
@@ -508,7 +771,6 @@ class Keyboard extends Dialog {
onComplete: () => { }
});
this._grabbedSequence = null;
- this._grabbedDevice = null;
this._dragging = false;
this.delta = [];
this.emit('drag-end');
@@ -532,7 +794,7 @@ class Keyboard extends Dialog {
}
snapMovement(xPos, yPos) {
- let monitor = Main.layoutManager.monitors[currentMonitorId]
+ let monitor = Main.layoutManager.monitors[currentMonitorId] ?? Main.layoutManager.primaryMonitor
if (xPos < monitor.x || yPos < monitor.y || xPos > monitor.x + monitor.width || yPos > monitor.y + monitor.width) {
this.set_translation(xPos, yPos, 0);
return;
@@ -558,7 +820,7 @@ class Keyboard extends Dialog {
}
setOpenState(percent) {
- let monitor = Main.layoutManager.monitors[currentMonitorId];
+ let monitor = Main.layoutManager.monitors[currentMonitorId] ?? Main.layoutManager.primaryMonitor;
let posX = [this.settings.get_int("snap-spacing-px"), ((monitor.width * .5) - ((this.width * .5))), monitor.width - this.width - this.settings.get_int("snap-spacing-px")][(this.settings.get_int("default-snap") % 3)];
let posY = [this.settings.get_int("snap-spacing-px"), ((monitor.height * .5) - ((this.height * .5))), monitor.height - this.height - this.settings.get_int("snap-spacing-px")][Math.floor((this.settings.get_int("default-snap") / 3))];
let mX = [-this.box.width, 0, this.box.width][(this.settings.get_int("default-snap") % 3)];
@@ -579,7 +841,7 @@ class Keyboard extends Dialog {
this.show();
}
if (noPrep == null || noPrep) {
- let monitor = Main.layoutManager.monitors[currentMonitorId];
+ let monitor = Main.layoutManager.monitors[currentMonitorId] ?? Main.layoutManager.primaryMonitor;
let posX = [this.settings.get_int("snap-spacing-px"), ((monitor.width * .5) - ((this.width * .5))), monitor.width - this.width - this.settings.get_int("snap-spacing-px")][(this.settings.get_int("default-snap") % 3)];
let posY = [this.settings.get_int("snap-spacing-px"), ((monitor.height * .5) - ((this.height * .5))), monitor.height - this.height - this.settings.get_int("snap-spacing-px")][Math.floor((this.settings.get_int("default-snap") / 3))];
if (noPrep == null) {
@@ -620,7 +882,7 @@ class Keyboard extends Dialog {
close(instant = null) {
this.prevKeyFocus = null;
- let monitor = Main.layoutManager.monitors[currentMonitorId];
+ let monitor = Main.layoutManager.monitors[currentMonitorId] ?? Main.layoutManager.primaryMonitor;
let posX = [this.settings.get_int("snap-spacing-px"), ((monitor.width * .5) - ((this.width * .5))), monitor.width - this.width - this.settings.get_int("snap-spacing-px")][(this.settings.get_int("default-snap") % 3)];
let posY = [this.settings.get_int("snap-spacing-px"), ((monitor.height * .5) - ((this.height * .5))), monitor.height - this.height - this.settings.get_int("snap-spacing-px")][Math.floor((this.settings.get_int("default-snap") / 3))];
let mX = [-this.box.width, 0, this.box.width][(this.settings.get_int("default-snap") % 3)];
@@ -679,6 +941,14 @@ class Keyboard extends Dialog {
return Clutter.EVENT_PROPAGATE;
}
+ vfunc_key_press_event() {
+ return Clutter.EVENT_PROPAGATE;
+ }
+
+ vfunc_key_release_event() {
+ return Clutter.EVENT_PROPAGATE;
+ }
+
vfunc_touch_event() {
let event = Clutter.get_current_event();
let sequence = event.get_event_sequence();
@@ -701,9 +971,17 @@ class Keyboard extends Dialog {
buildUI() {
this.box.set_opacity(0);
this.keys = [];
- let monitor = Main.layoutManager.monitors[currentMonitorId]
- let layoutName = Object.keys(layouts)[(monitor.width > monitor.height) ? this.settings.get_int("layout-landscape") : this.settings.get_int("layout-portrait")];
- this.box.width = Math.round((monitor.width - this.settings.get_int("snap-spacing-px") * 2) * (layoutName.includes("Split") ? 1 : this.widthPercent))
+ let monitor = Main.layoutManager.monitors[currentMonitorId] ?? Main.layoutManager.primaryMonitor
+ let layoutIdx = (monitor.width > monitor.height) ? this.settings.get_int("layout-landscape") : this.settings.get_int("layout-portrait")
+ let currentLayout;
+ if (layoutIdx < 10) {
+ let layoutName = Object.keys(layouts)[layoutIdx];
+ currentLayout = layouts[layoutName];
+ }
+ else {
+ currentLayout = JSON.parse(this.settings.get_string("custom-layout"))
+ }
+ this.box.width = Math.round((monitor.width - this.settings.get_int("snap-spacing-px") * 2) * (currentLayout[currentLayout.length - 1].split ? 1 : this.widthPercent))
this.box.height = Math.round((monitor.height - this.settings.get_int("snap-spacing-px") * 2) * this.heightPercent)
if (!this.settings.get_boolean("enable-drag")) {
@@ -749,7 +1027,7 @@ class Keyboard extends Dialog {
const grid = this.box.layout_manager
grid.set_row_homogeneous(true)
- grid.set_column_homogeneous(!layoutName.includes("Split"))
+ grid.set_column_homogeneous(!currentLayout[currentLayout.length - 1].split)
let gridLeft;
let gridRight;
@@ -758,7 +1036,7 @@ class Keyboard extends Dialog {
let right;
let topBtnWidth;
- if (layoutName.includes("Split")) {
+ if (currentLayout[currentLayout.length - 1].split) {
this.box.reactive = false;
left = new St.Widget({
reactive: true,
@@ -792,17 +1070,16 @@ class Keyboard extends Dialog {
this.shiftButtons = [];
// [insert handwriting 7]
- let currentLayout = layouts[layoutName];
let width = 0;
for (const c of currentLayout[0]) {
- width += (Object.hasOwn(c, "width") ? c.width : 1)
+ width += (("width" in c) ? c.width : 1)
}
let rowSize;
let halfSize;
let r = 0;
let c;
const doAddKey = (keydef) => {
- const i = Object.hasOwn(keydef, "key") ? keycodes[keydef.key] : Object.hasOwn(keydef, "split") ? "split" : "empty space";
+ const i = ("key" in keydef) ? keycodes[keydef.key] : ("split" in keydef) ? "split" : "empty space";
if (i != null && typeof i !== 'string') {
if (i.layers.default == null) {
for (var key of Object.keys(i.layers)) {
@@ -816,7 +1093,7 @@ class Keyboard extends Dialog {
let iconKeys = ["left", "up", "right", "down", "space"]
if (this.settings.get_boolean("show-icons")) {
- iconKeys = ["left", "up", "right", "down", "backspace", "tab", "capslock", "shift", "enter", "ctrl", "super", "alt", "space"]
+ iconKeys = ["left", "up", "right", "down", "backspace", "tab", "capslock", "shift", "enter", "ctrl", "super", "alt", "space", "menu"]
}
// [insert handwriting 8]
if (iconKeys.some(j => { return i.layers.default.toLowerCase() == j })) {
@@ -829,7 +1106,7 @@ class Keyboard extends Dialog {
params.label = i.layers.default
}
i.isMod = false
- if ([42, 54, 29, 125, 56, 100, 97, 58, 69].some(j => { return i.code == j })) {
+ if ([42, 54, 29, 125, 126, 56, 100, 97, 58, 69].some(j => { return i.code == j })) {
i.isMod = true;
}
const keyBtn = new St.Button(params)
@@ -837,7 +1114,7 @@ class Keyboard extends Dialog {
keyBtn.char = i
if (i.code == 58) {
this.keymap = Clutter.get_default_backend().get_default_seat().get_keymap()
- this.capslockConnect = this.keymap.connect("state-changed", (a, e) => {
+ this.capsLockConnect = this.keymap.connect("state-changed", (a, e) => {
this.setCapsLock(keyBtn, this.keymap.get_caps_lock_state())
})
this.updateCapsLock = () => this.setCapsLock(keyBtn, this.keymap.get_caps_lock_state())
@@ -850,13 +1127,13 @@ class Keyboard extends Dialog {
} else if (i.code == 42 || i.code == 54) {
this.shiftButtons.push(keyBtn)
}
- currentGrid.attach(keyBtn, c, 5 + r, (Object.hasOwn(keydef, "width") ? keydef.width : 1) * 2, r == 0 ? 3 : (Object.hasOwn(keydef, "height") ? keydef.height : 1) * 4)
+ currentGrid.attach(keyBtn, c, 5 + r, (("width" in keydef) ? keydef.width : 1) * 2, r == 0 ? 3 : (("height" in keydef) ? keydef.height : 1) * 4)
keyBtn.visible = true
- c += (Object.hasOwn(keydef, "width") ? keydef.width : 1) * 2
+ c += (("width" in keydef) ? keydef.width : 1) * 2
this.keys.push(keyBtn)
// [insert handwriting 9]
} else if (i == "empty space") {
- c += (Object.hasOwn(keydef, "width") ? keydef.width : 1) * 2
+ c += (("width" in keydef) ? keydef.width : 1) * 2
} else if (i == "split") {
currentGrid = gridRight
const size = c
@@ -864,21 +1141,21 @@ class Keyboard extends Dialog {
}
}
- for (const kRow of currentLayout) {
+ for (const kRow of currentLayout.slice(0, -1)) {
c = 0;
- if (layoutName.includes("Split")) {
+ if (currentLayout[currentLayout.length - 1].split) {
currentGrid = gridLeft;
}
for (const keydef of kRow) {
if (keydef instanceof Array) {
- keydef.forEach(i => { doAddKey(i); r += 2; c -= (Object.hasOwn(i, "width") ? i.width : 1) * 2 });
- c += (Object.hasOwn(keydef[0], "width") ? keydef[0].width : 1) * 2;
+ keydef.forEach(i => { doAddKey(i); r += 2; c -= (("width" in i) ? i.width : 1) * 2 });
+ c += (("width" in keydef[0]) ? keydef[0].width : 1) * 2;
r -= 4;
} else {
doAddKey(keydef)
}
}
- if (!topBtnWidth) topBtnWidth = ((Object.hasOwn(kRow[kRow.length - 1], "width") && (Object.hasOwn(kRow[kRow.length - 1], "key"))) ? kRow[kRow.length - 1].width : 1)
+ if (!topBtnWidth) topBtnWidth = ((("width" in kRow[kRow.length - 1]) && ("key" in kRow[kRow.length - 1])) ? kRow[kRow.length - 1].width : 1)
const size = c;
if (!rowSize) rowSize = size;
r += r == 0 ? 3 : 4
@@ -907,37 +1184,60 @@ class Keyboard extends Dialog {
left.add_style_class_name("regular");
right.add_style_class_name("regular");
}
- const settingsBtn = new St.Button({
- x_expand: true,
- y_expand: true
- })
- settingsBtn.add_style_class_name("settings_btn")
- settingsBtn.add_style_class_name("key")
- settingsBtn.connect("clicked", () => {
- this.settingsOpenFunction();
- })
- gridLeft.attach(settingsBtn, 0, 0, 2 * topBtnWidth, 3)
- this.keys.push(settingsBtn)
- const closeBtn = new St.Button({
- x_expand: true,
- y_expand: true
- })
- closeBtn.add_style_class_name("close_btn")
- closeBtn.add_style_class_name("key")
- closeBtn.connect("clicked", () => {
- this.close();
- this.closedFromButton = true;
- })
- gridRight.attach(closeBtn, (rowSize - 2 * topBtnWidth), 0, 2 * topBtnWidth, 3)
- this.keys.push(closeBtn)
+ let mvBtnStartLeft = 2 * topBtnWidth
+ let mvBtnEndRight = 2 * topBtnWidth
+
+ if (currentLayout[currentLayout.length - 1].settings) {
+ const settingsBtn = new St.Button({
+ x_expand: true,
+ y_expand: true
+ })
+ settingsBtn.add_style_class_name("settings_btn")
+ settingsBtn.add_style_class_name("key")
+ settingsBtn.connect("button-press-event", () => {
+ this.settingsOpenFunction();
+ })
+ settingsBtn.connect("touch-event", () => {
+ if (Clutter.get_current_event().type() == Clutter.EventType.TOUCH_BEGIN)
+ this.settingsOpenFunction();
+ })
+ this.keys.push(settingsBtn)
+ gridLeft.attach(settingsBtn, 0, 0, 2 * topBtnWidth, 3)
+ } else {
+ mvBtnStartLeft = 0
+ }
+
+ if (currentLayout[currentLayout.length - 1].close) {
+ const closeBtn = new St.Button({
+ x_expand: true,
+ y_expand: true
+ })
+ closeBtn.add_style_class_name("close_btn")
+ closeBtn.add_style_class_name("key")
+ closeBtn.connect("button-press-event", () => {
+ this.close();
+ this.closedFromButton = true;
+ })
+ closeBtn.connect("touch-event", () => {
+ if (Clutter.get_current_event().type() == Clutter.EventType.TOUCH_BEGIN) {
+ this.close();
+ this.closedFromButton = true;
+ }
+ })
+ gridRight.attach(closeBtn, (rowSize - 2 * topBtnWidth), 0, 2 * topBtnWidth, 3)
+ this.keys.push(closeBtn)
+ } else {
+ mvBtnEndRight = 0
+ }
let moveHandleLeft = new St.Button({
x_expand: true,
y_expand: true
})
+ moveHandleLeft.clear_actions()
moveHandleLeft.add_style_class_name("moveHandle")
- moveHandleLeft.set_style("font-size: " + this.settings.get_int("font-size-px") + "px; border-radius: " + (this.settings.get_boolean("round-key-corners") ? "5px;" : "0;") + "background-size: " + this.settings.get_int("font-size-px") + "px; font-weight: " + (this.settings.get_boolean("font-bold") ? "bold" : "normal") + "; border: " + this.settings.get_int("border-spacing-px") + "px solid transparent;");
+ moveHandleLeft.set_style("font-size: " + this.settings.get_int("font-size-px") + "px; border-radius: " + (this.settings.get_boolean("round-key-corners") ? "5px" : "0") + "; background-size: " + this.settings.get_int("font-size-px") + "px; font-weight: " + (this.settings.get_boolean("font-bold") ? "bold" : "normal") + "; border: " + this.settings.get_int("border-spacing-px") + "px solid transparent;");
if (this.lightOrDark()) {
moveHandleLeft.add_style_class_name("inverted");
} else {
@@ -950,14 +1250,15 @@ class Keyboard extends Dialog {
}
this.event(event, false)
})
- gridLeft.attach(moveHandleLeft, 2 * topBtnWidth, 0, (halfSize - 2 * topBtnWidth), 3)
+ gridLeft.attach(moveHandleLeft, mvBtnStartLeft, 0, (halfSize - mvBtnStartLeft), 3)
let moveHandleRight = new St.Button({
x_expand: true,
y_expand: true
})
+ moveHandleRight.clear_actions()
moveHandleRight.add_style_class_name("moveHandle")
- moveHandleRight.set_style("font-size: " + this.settings.get_int("font-size-px") + "px; border-radius: " + (this.settings.get_boolean("round-key-corners") ? "5px;" : "0;") + "background-size: " + this.settings.get_int("font-size-px") + "px; font-weight: " + (this.settings.get_boolean("font-bold") ? "bold" : "normal") + "; border: " + this.settings.get_int("border-spacing-px") + "px solid transparent;");
+ moveHandleRight.set_style("font-size: " + this.settings.get_int("font-size-px") + "px; border-radius: " + (this.settings.get_boolean("round-key-corners") ? "5px" : "0") + "; background-size: " + this.settings.get_int("font-size-px") + "px; font-weight: " + (this.settings.get_boolean("font-bold") ? "bold" : "normal") + "; border: " + this.settings.get_int("border-spacing-px") + "px solid transparent;");
if (this.lightOrDark()) {
moveHandleRight.add_style_class_name("inverted");
} else {
@@ -970,7 +1271,7 @@ class Keyboard extends Dialog {
}
this.event(event, false)
})
- gridRight.attach(moveHandleRight, halfSize, 0, (rowSize - halfSize - 2 * topBtnWidth), 3)
+ gridRight.attach(moveHandleRight, halfSize, 0, (rowSize - halfSize - mvBtnEndRight), 3)
gridLeft.attach(new St.Widget({ x_expand: true, y_expand: true }), 0, 3, halfSize, 1)
gridRight.attach(new St.Widget({ x_expand: true, y_expand: true }), halfSize, 3, (rowSize - halfSize), 1)
} else {
@@ -990,30 +1291,50 @@ class Keyboard extends Dialog {
this.box.add_style_class_name("regular");
}
- const settingsBtn = new St.Button({
- x_expand: true,
- y_expand: true
- })
- settingsBtn.add_style_class_name("settings_btn")
- settingsBtn.add_style_class_name("key")
- settingsBtn.connect("clicked", () => {
- this.settingsOpenFunction();
- })
- grid.attach(settingsBtn, 0, 0, 2 * topBtnWidth, 3)
- this.keys.push(settingsBtn)
+ let mvBtnStartLeft = 2 * topBtnWidth
+ let mvBtnEndRight = 2 * topBtnWidth
- const closeBtn = new St.Button({
- x_expand: true,
- y_expand: true
- })
- closeBtn.add_style_class_name("close_btn")
- closeBtn.add_style_class_name("key")
- closeBtn.connect("clicked", () => {
- this.close();
- this.closedFromButton = true;
- })
- grid.attach(closeBtn, (rowSize - 2 * topBtnWidth), 0, 2 * topBtnWidth, 3)
- this.keys.push(closeBtn)
+ if (currentLayout[currentLayout.length - 1].settings) {
+ const settingsBtn = new St.Button({
+ x_expand: true,
+ y_expand: true
+ })
+ settingsBtn.add_style_class_name("settings_btn")
+ settingsBtn.add_style_class_name("key")
+ settingsBtn.connect("button-press-event", () => {
+ this.settingsOpenFunction();
+ })
+ settingsBtn.connect("touch-event", () => {
+ if (Clutter.get_current_event().type() == Clutter.EventType.TOUCH_BEGIN)
+ this.settingsOpenFunction();
+ })
+ this.keys.push(settingsBtn)
+ grid.attach(settingsBtn, 0, 0, 2 * topBtnWidth, 3)
+ } else {
+ mvBtnStartLeft = 0
+ }
+ if (currentLayout[currentLayout.length - 1].close) {
+ const closeBtn = new St.Button({
+ x_expand: true,
+ y_expand: true
+ })
+ closeBtn.add_style_class_name("close_btn")
+ closeBtn.add_style_class_name("key")
+ closeBtn.connect("button-press-event", () => {
+ this.close();
+ this.closedFromButton = true;
+ })
+ closeBtn.connect("touch-event", () => {
+ if (Clutter.get_current_event().type() == Clutter.EventType.TOUCH_BEGIN) {
+ this.close();
+ this.closedFromButton = true;
+ }
+ })
+ grid.attach(closeBtn, (rowSize - 2 * topBtnWidth), 0, 2 * topBtnWidth, 3)
+ this.keys.push(closeBtn)
+ } else {
+ mvBtnEndRight = 0;
+ }
// [insert handwriting 10]
@@ -1021,8 +1342,9 @@ class Keyboard extends Dialog {
x_expand: true,
y_expand: true
})
+ moveHandle.clear_actions();
moveHandle.add_style_class_name("moveHandle")
- moveHandle.set_style("font-size: " + this.settings.get_int("font-size-px") + "px; border-radius: " + (this.settings.get_boolean("round-key-corners") ? "5px;" : "0;") + "background-size: " + this.settings.get_int("font-size-px") + "px; font-weight: " + (this.settings.get_boolean("font-bold") ? "bold" : "normal") + "; border: " + this.settings.get_int("border-spacing-px") + "px solid transparent;");
+ moveHandle.set_style("font-size: " + this.settings.get_int("font-size-px") + "px; border-radius: " + (this.settings.get_boolean("round-key-corners") ? "5px" : "0") + "; background-size: " + this.settings.get_int("font-size-px") + "px; font-weight: " + (this.settings.get_boolean("font-bold") ? "bold" : "normal") + "; border: " + this.settings.get_int("border-spacing-px") + "px solid transparent;");
if (this.lightOrDark()) {
moveHandle.add_style_class_name("inverted");
} else {
@@ -1035,12 +1357,12 @@ class Keyboard extends Dialog {
}
this.event(event, false)
})
- grid.attach(moveHandle, 2 * topBtnWidth, 0, (rowSize - 4 * topBtnWidth), 3) // [insert handwriting 11]
+ grid.attach(moveHandle, mvBtnStartLeft, 0, (rowSize - mvBtnStartLeft - mvBtnEndRight), 3) // [insert handwriting 11]
grid.attach(new St.Widget({ x_expand: true, y_expand: true }), 0, 3, rowSize, 1)
}
this.keys.forEach(item => {
- item.set_style("font-size: " + this.settings.get_int("font-size-px") + "px; border-radius: " + (this.settings.get_boolean("round-key-corners") ? (this.settings.get_int("border-spacing-px") + 5) + "px;" : "0;") + "background-size: " + this.settings.get_int("font-size-px") + "px; font-weight: " + (this.settings.get_boolean("font-bold") ? "bold" : "normal") + "; border: " + this.settings.get_int("border-spacing-px") + "px solid transparent;");
+ item.set_style("font-size: " + this.settings.get_int("font-size-px") + "px; border-radius: " + (this.settings.get_boolean("round-key-corners") ? (this.settings.get_int("border-spacing-px") + 5) + "px" : "0") + "; background-size: " + this.settings.get_int("font-size-px") + "px; font-weight: " + (this.settings.get_boolean("font-bold") ? "bold" : "normal") + "; border: " + this.settings.get_int("border-spacing-px") + "px solid transparent;");
if (this.lightOrDark()) {
item.add_style_class_name("inverted");
} else {
@@ -1070,17 +1392,26 @@ class Keyboard extends Dialog {
item.space_motion_handler = null
item.set_scale(1.2, 1.2)
item.add_style_pseudo_class("pressed")
- let player
+ let player = global.display.get_sound_player();
if (this.settings.get_boolean("play-sound")) {
- player = global.display.get_sound_player();
- player.play_from_theme("dialog-information", "tap", null)
+ if (this.settings.get_string("sound-file") != "") {
+ const sound_file = Gio.File.new_for_path(this.settings.get_string("sound-file"))
+ player.play_from_file(sound_file, "tap", null)
+ } else {
+ player.play_from_theme("dialog-information", "tap", null)
+ }
}
if (["delete_btn", "backspace_btn", "up_btn", "down_btn", "left_btn", "right_btn"].some(e => item.has_style_class_name(e))) {
item.button_pressed = setTimeout(() => {
const oldModBtns = this.modBtns
item.button_repeat = setInterval(() => {
if (this.settings.get_boolean("play-sound")) {
- player.play_from_theme("dialog-information", "tap", null)
+ if (this.settings.get_string("sound-file") != "") {
+ const sound_file = Gio.File.new_for_path(this.settings.get_string("sound-file"))
+ player.play_from_file(sound_file, "tap", null)
+ } else {
+ player.play_from_theme("dialog-information", "tap", null)
+ }
}
this.decideMod(item.char)
@@ -1159,6 +1490,7 @@ class Keyboard extends Dialog {
}
item.key_pressed = false;
}
+ item.clear_actions();
item.connect("button-press-event", () => pressEv("mouse"))
item.connect("button-release-event", releaseEv)
item.connect("touch-event", () => {
@@ -1189,25 +1521,6 @@ class Keyboard extends Dialog {
return hsp > 127.5
}
releaseAllKeys() {
- let instances = [];
-
- function traverse(obj) {
- for (let key in obj) {
- if (obj.hasOwnProperty(key)) {
- if (key === "code") {
- instances.push(obj[key]);
- } else if (typeof obj[key] === 'object' && obj[key] !== null) {
- traverse(obj[key]);
- }
- }
- }
- }
-
- traverse(keycodes);
- instances.forEach(i => {
- this.inputDevice.notify_key(Clutter.get_current_event_time(), i, Clutter.KeyState.RELEASED);
- })
-
this.keys.forEach(item => {
item.key_pressed = false;
if (item.button_pressed !== null) {
@@ -1218,7 +1531,7 @@ class Keyboard extends Dialog {
clearInterval(item.button_repeat)
item.button_repeat == null
}
- if (item.space_motion_handler !== null) {
+ if (item.space_motion_handler !== null && GObject.signal_handler_is_connected(item, item.space_motion_handler)) {
item.disconnect(item.space_motion_handler)
item.space_motion_handler = null;
}
@@ -1226,25 +1539,38 @@ class Keyboard extends Dialog {
}
sendKey(keys) {
try {
+ if (this.keyInProgress) {
+ return;
+ }
+ this.keyInProgress = true;
+ let event_time = Clutter.get_current_event_time() * 1000;
for (var i = 0; i < keys.length; i++) {
- this.inputDevice.notify_key(Clutter.get_current_event_time(), keys[i], Clutter.KeyState.PRESSED);
+ this.inputDevice.notify_key(event_time, keys[i], Clutter.KeyState.PRESSED);
}
if (this.keyTimeout !== null) {
clearTimeout(this.keyTimeout);
- this.keyTimeout = null;
- }
- this.keyTimeout = setTimeout(() => {
- for (var j = keys.length - 1; j >= 0; j--) {
- this.inputDevice.notify_key(Clutter.get_current_event_time(), keys[j], Clutter.KeyState.RELEASED);
+ if (typeof this.keyTimeoutFunc === 'function') {
+ this.keyTimeoutFunc();
}
- }, 100);
+ this.keyTimeout = null;
+ this.keyTimeoutFunc = null;
+ }
+ this.keyTimeoutFunc = () => {
+ const currKeys = keys
+ for (var j = currKeys.length - 1; j >= 0; j--) {
+ this.inputDevice.notify_key(event_time, currKeys[j], Clutter.KeyState.RELEASED);
+ }
+ this.keyInProgress = false;
+ }
+ this.keyTimeout = setTimeout(this.keyTimeoutFunc, 100);
} catch (err) {
+ this.keyInProgress = false;
throw new Error("GJS-OSK: An unknown error occured. Please report this bug to the Issues page (https://github.com/Vishram1123/gjs-osk/issues):\n\n" + err + "\n\nKeys Pressed: " + keys);
}
}
decideMod(i, mBtn) {
- if (i.code == 29 || i.code == 56 || i.code == 97 || i.code == 125) {
+ if (i.code == 29 || i.code == 56 || i.code == 97 || i.code == 125 || i.code == 126) {
this.setNormMod(mBtn);
} else if (i.code == 100) {
this.setAlt(mBtn);
@@ -1326,6 +1652,7 @@ class Keyboard extends Dialog {
button.remove_style_class_name("selected");
this.modBtns.splice(this.modBtns.indexOf(button), this.modBtns.indexOf(button) + 1);
this.inputDevice.notify_key(Clutter.get_current_event_time(), button.char.code, Clutter.KeyState.RELEASED);
+ this.sendKey([button.char.code])
} else {
if (!(button.char.code == 42) && !(button.char.code == 54))
button.add_style_class_name("selected");
diff --git a/gnome/.local/share/gnome-shell/extensions/gjsosk@vishram1123.com/keycodes.tar.xz b/gnome/.local/share/gnome-shell/extensions/gjsosk@vishram1123.com/keycodes.tar.xz
index a57820a..ce3fc1b 100644
Binary files a/gnome/.local/share/gnome-shell/extensions/gjsosk@vishram1123.com/keycodes.tar.xz and b/gnome/.local/share/gnome-shell/extensions/gjsosk@vishram1123.com/keycodes.tar.xz differ
diff --git a/gnome/.local/share/gnome-shell/extensions/gjsosk@vishram1123.com/metadata.json b/gnome/.local/share/gnome-shell/extensions/gjsosk@vishram1123.com/metadata.json
index 419a6f1..e43b080 100644
--- a/gnome/.local/share/gnome-shell/extensions/gjsosk@vishram1123.com/metadata.json
+++ b/gnome/.local/share/gnome-shell/extensions/gjsosk@vishram1123.com/metadata.json
@@ -7,9 +7,10 @@
"45",
"46",
"47",
- "48"
+ "48",
+ "49"
],
"url": "https://github.com/Vishram1123/gjs-osk",
"uuid": "gjsosk@vishram1123.com",
"version": 100000
-}
+}
\ No newline at end of file
diff --git a/gnome/.local/share/gnome-shell/extensions/gjsosk@vishram1123.com/physicalLayouts.json b/gnome/.local/share/gnome-shell/extensions/gjsosk@vishram1123.com/physicalLayouts.json
index 368bffe..1f10f32 100644
--- a/gnome/.local/share/gnome-shell/extensions/gjsosk@vishram1123.com/physicalLayouts.json
+++ b/gnome/.local/share/gnome-shell/extensions/gjsosk@vishram1123.com/physicalLayouts.json
@@ -5,7 +5,8 @@
[{"key":"TAB", "width":1.5}, {"key":"AD01"}, {"key":"AD02"}, {"key":"AD03"}, {"key":"AD04"}, {"key":"AD05"}, {"key":"AD06"}, {"key":"AD07"}, {"key":"AD08"}, {"key":"AD09"}, {"key":"AD10"}, {"key":"AD11"}, {"key":"AD12"}, {"key":"RTRN", "width":1.5, "height":2}, {"key":"DELE"}, {"key":"END"}, {"key":"PGDN"}, {"key":"KP7"}, {"key":"KP8"}, {"key":"KP9"}, {"key":"KPAD", "width":1, "height":2}],
[{"key":"CAPS", "width":2}, {"key":"AC01"}, {"key":"AC02"}, {"key":"AC03"}, {"key":"AC04"}, {"key":"AC05"}, {"key":"AC06"}, {"key":"AC07"}, {"key":"AC08"}, {"key":"AC09"}, {"key":"AC10"}, {"key":"AC11"}, {"key":"BKSL", "width":0.5}, {"width":1.5}, {"width":3}, {"key":"KP4"}, {"key":"KP5"}, {"key":"KP6"}, {"width":1}],
[{"key":"LFSH", "width":2}, {"key":"LSGT"}, {"key":"AB01"}, {"key":"AB02"}, {"key":"AB03"}, {"key":"AB04"}, {"key":"AB05"}, {"key":"AB06"}, {"key":"AB07"}, {"key":"AB08"}, {"key":"AB09"}, {"key":"AB10"}, {"key":"RTSH", "width":2}, {"width":1}, {"key":"UP"}, {"width":1}, {"key":"KP1"}, {"key":"KP2"}, {"key":"KP3"}, {"key":"KPEN", "height":2}],
- [{"key":"LCTL"}, {"key":"LWIN"}, {"key":"LALT"}, {"key":"SPCE", "width":10}, {"key":"RALT"}, {"key":"RCTL"}, {"key":"LEFT"}, {"key":"DOWN"}, {"key":"RGHT"}, {"key":"KP0", "width":2}, {"key":"KPDL"}, {"width":1}]
+ [{"key":"LCTL"}, {"key":"LWIN"}, {"key":"LALT"}, {"key":"SPCE", "width":10}, {"key":"RALT"}, {"key":"RCTL"}, {"key":"LEFT"}, {"key":"DOWN"}, {"key":"RGHT"}, {"key":"KP0", "width":2}, {"key":"KPDL"}, {"width":1}],
+ { "split": false, "settings": true, "close": true }
],
"Full Sized US":[
@@ -14,7 +15,8 @@
[{"key":"TAB", "width":1.5}, {"key":"AD01"}, {"key":"AD02"}, {"key":"AD03"}, {"key":"AD04"}, {"key":"AD05"}, {"key":"AD06"}, {"key":"AD07"}, {"key":"AD08"}, {"key":"AD09"}, {"key":"AD10"}, {"key":"AD11"}, {"key":"AD12"}, {"key":"BKSL", "width":1.5}, {"key":"DELE"}, {"key":"END"}, {"key":"PGDN"}, {"key":"KP7"}, {"key":"KP8"}, {"key":"KP9"}, {"key":"KPAD", "width":1, "height":2}],
[{"key":"CAPS", "width":2}, {"key":"AC01"}, {"key":"AC02"}, {"key":"AC03"}, {"key":"AC04"}, {"key":"AC05"}, {"key":"AC06"}, {"key":"AC07"}, {"key":"AC08"}, {"key":"AC09"}, {"key":"AC10"}, {"key":"AC11"}, {"key": "RTRN", "width": 2}, {"width":3}, {"key":"KP4"}, {"key":"KP5"}, {"key":"KP6"}, {"width":1}],
[{"key":"LFSH", "width":2}, {"key":"LSGT"}, {"key":"AB01"}, {"key":"AB02"}, {"key":"AB03"}, {"key":"AB04"}, {"key":"AB05"}, {"key":"AB06"}, {"key":"AB07"}, {"key":"AB08"}, {"key":"AB09"}, {"key":"AB10"}, {"key":"RTSH", "width":2}, {"width":1}, {"key":"UP"}, {"width":1}, {"key":"KP1"}, {"key":"KP2"}, {"key":"KP3"}, {"key":"KPEN", "height":2}],
- [{"key":"LCTL"}, {"key":"LWIN"}, {"key":"LALT"}, {"key":"SPCE", "width":10}, {"key":"RALT"}, {"key":"RCTL"}, {"key":"LEFT"}, {"key":"DOWN"}, {"key":"RGHT"}, {"key":"KP0", "width":2}, {"key":"KPDL"}, {"width":1}]
+ [{"key":"LCTL"}, {"key":"LWIN"}, {"key":"LALT"}, {"key":"SPCE", "width":10}, {"key":"RALT"}, {"key":"RCTL"}, {"key":"LEFT"}, {"key":"DOWN"}, {"key":"RGHT"}, {"key":"KP0", "width":2}, {"key":"KPDL"}, {"width":1}],
+ { "split": false, "settings": true, "close": true }
],
"Tenkeyless International":[
@@ -23,7 +25,8 @@
[{"key":"TAB", "width":1.5}, {"key":"AD01"}, {"key":"AD02"}, {"key":"AD03"}, {"key":"AD04"}, {"key":"AD05"}, {"key":"AD06"}, {"key":"AD07"}, {"key":"AD08"}, {"key":"AD09"}, {"key":"AD10"}, {"key":"AD11"}, {"key":"AD12"}, {"key":"RTRN", "width":1.5, "height":2}, {"key":"DELE"}, {"key":"END"}, {"key":"PGDN"}],
[{"key":"CAPS", "width":2}, {"key":"AC01"}, {"key":"AC02"}, {"key":"AC03"}, {"key":"AC04"}, {"key":"AC05"}, {"key":"AC06"}, {"key":"AC07"}, {"key":"AC08"}, {"key":"AC09"}, {"key":"AC10"}, {"key":"AC11"}, {"key":"BKSL", "width":0.5}, {"width":1.5}, {"width":3}],
[{"key":"LFSH", "width":2}, {"key":"LSGT"}, {"key":"AB01"}, {"key":"AB02"}, {"key":"AB03"}, {"key":"AB04"}, {"key":"AB05"}, {"key":"AB06"}, {"key":"AB07"}, {"key":"AB08"}, {"key":"AB09"}, {"key":"AB10"}, {"key":"RTSH", "width":2}, {"width":1}, {"key":"UP"}, {"width":1}],
- [{"key":"LCTL"}, {"key":"LWIN"}, {"key":"LALT"}, {"key":"SPCE", "width":10}, {"key":"RALT"}, {"key":"RCTL"}, {"key":"LEFT"}, {"key":"DOWN"}, {"key":"RGHT"}]
+ [{"key":"LCTL"}, {"key":"LWIN"}, {"key":"LALT"}, {"key":"SPCE", "width":10}, {"key":"RALT"}, {"key":"RCTL"}, {"key":"LEFT"}, {"key":"DOWN"}, {"key":"RGHT"}],
+ { "split": false, "settings": true, "close": true }
],
"Tenkeyless US":[
@@ -32,7 +35,8 @@
[{"key":"TAB", "width":1.5}, {"key":"AD01"}, {"key":"AD02"}, {"key":"AD03"}, {"key":"AD04"}, {"key":"AD05"}, {"key":"AD06"}, {"key":"AD07"}, {"key":"AD08"}, {"key":"AD09"}, {"key":"AD10"}, {"key":"AD11"}, {"key":"AD12"}, {"key":"BKSL", "width":1.5}, {"key":"DELE"}, {"key":"END"}, {"key":"PGDN"}],
[{"key":"CAPS", "width":2}, {"key":"AC01"}, {"key":"AC02"}, {"key":"AC03"}, {"key":"AC04"}, {"key":"AC05"}, {"key":"AC06"}, {"key":"AC07"}, {"key":"AC08"}, {"key":"AC09"}, {"key":"AC10"}, {"key":"AC11"}, {"key": "RTRN", "width": 2}, {"width":3}],
[{"key":"LFSH", "width":2}, {"key":"LSGT"}, {"key":"AB01"}, {"key":"AB02"}, {"key":"AB03"}, {"key":"AB04"}, {"key":"AB05"}, {"key":"AB06"}, {"key":"AB07"}, {"key":"AB08"}, {"key":"AB09"}, {"key":"AB10"}, {"key":"RTSH", "width":2}, {"width":1}, {"key":"UP"}, {"width":1}],
- [{"key":"LCTL"}, {"key":"LWIN"}, {"key":"LALT"}, {"key":"SPCE", "width":10}, {"key":"RALT"}, {"key":"RCTL"}, {"key":"LEFT"}, {"key":"DOWN"}, {"key":"RGHT"}]
+ [{"key":"LCTL"}, {"key":"LWIN"}, {"key":"LALT"}, {"key":"SPCE", "width":10}, {"key":"RALT"}, {"key":"RCTL"}, {"key":"LEFT"}, {"key":"DOWN"}, {"key":"RGHT"}],
+ { "split": false, "settings": true, "close": true }
],
"Compact International":[
@@ -41,7 +45,8 @@
[{"key":"TAB", "width":1.5}, {"key":"AD01"}, {"key":"AD02"}, {"key":"AD03"}, {"key":"AD04"}, {"key":"AD05"}, {"key":"AD06"}, {"key":"AD07"}, {"key":"AD08"}, {"key":"AD09"}, {"key":"AD10"}, {"key":"AD11"}, {"key":"AD12"}, {"key":"RTRN", "width":1.5, "height":2}],
[{"key":"CAPS", "width":2}, {"key":"AC01"}, {"key":"AC02"}, {"key":"AC03"}, {"key":"AC04"}, {"key":"AC05"}, {"key":"AC06"}, {"key":"AC07"}, {"key":"AC08"}, {"key":"AC09"}, {"key":"AC10"}, {"key":"AC11"}, {"key":"BKSL", "width":0.5}, {"width":1.5}],
[{"key":"LFSH", "width":2}, {"key":"LSGT"}, {"key":"AB01"}, {"key":"AB02"}, {"key":"AB03"}, {"key":"AB04"}, {"key":"AB05"}, {"key":"AB06"}, {"key":"AB07"}, {"key":"AB08"}, {"key":"AB09"}, {"key":"AB10"}, {"key":"RTSH", "width": 2}],
- [{"key":"LCTL"}, {"key":"LWIN"}, {"key":"LALT"}, {"key":"SPCE", "width":7}, {"key":"RALT"}, {"key":"RCTL"}, {"key":"LEFT"}, [{"key":"UP", "height": 0.5}, {"key":"DOWN", "height": 0.5}], {"key":"RGHT"}]
+ [{"key":"LCTL"}, {"key":"LWIN"}, {"key":"LALT"}, {"key":"SPCE", "width":7}, {"key":"RALT"}, {"key":"RCTL"}, {"key":"LEFT"}, [{"key":"UP", "height": 0.5}, {"key":"DOWN", "height": 0.5}], {"key":"RGHT"}],
+ { "split": false, "settings": true, "close": true }
],
"Compact US":[
@@ -50,7 +55,8 @@
[{"key":"TAB", "width":1.5}, {"key":"AD01"}, {"key":"AD02"}, {"key":"AD03"}, {"key":"AD04"}, {"key":"AD05"}, {"key":"AD06"}, {"key":"AD07"}, {"key":"AD08"}, {"key":"AD09"}, {"key":"AD10"}, {"key":"AD11"}, {"key":"AD12"}, {"key":"BKSL", "width":1.5}],
[{"key":"CAPS", "width":2}, {"key":"AC01"}, {"key":"AC02"}, {"key":"AC03"}, {"key":"AC04"}, {"key":"AC05"}, {"key":"AC06"}, {"key":"AC07"}, {"key":"AC08"}, {"key":"AC09"}, {"key":"AC10"}, {"key":"AC11"}, {"key": "RTRN", "width": 2}],
[{"key":"LFSH", "width":2}, {"key":"LSGT"}, {"key":"AB01"}, {"key":"AB02"}, {"key":"AB03"}, {"key":"AB04"}, {"key":"AB05"}, {"key":"AB06"}, {"key":"AB07"}, {"key":"AB08"}, {"key":"AB09"}, {"key":"AB10"}, {"key":"RTSH", "width": 2}],
- [{"key":"LCTL"}, {"key":"LWIN"}, {"key":"LALT"}, {"key":"SPCE", "width":7}, {"key":"RALT"}, {"key":"RCTL"}, {"key":"LEFT"}, [{"key":"UP", "height": 0.5}, {"key":"DOWN", "height": 0.5}], {"key":"RGHT"}]
+ [{"key":"LCTL"}, {"key":"LWIN"}, {"key":"LALT"}, {"key":"SPCE", "width":7}, {"key":"RALT"}, {"key":"RCTL"}, {"key":"LEFT"}, [{"key":"UP", "height": 0.5}, {"key":"DOWN", "height": 0.5}], {"key":"RGHT"}],
+ { "split": false, "settings": true, "close": true }
],
"Split International":[
@@ -59,7 +65,8 @@
[{"key":"TAB", "width":1.5}, {"key":"AD01"}, {"key":"AD02"}, {"key":"AD03"}, {"key":"AD04"}, {"key":"AD05"}, {"key":"AD06"}, {"split":true}, {"key":"AD07"}, {"key":"AD08"}, {"key":"AD09"}, {"key":"AD10"}, {"key":"AD11"}, {"key":"AD12"}, {"key":"RTRN", "height":2}],
[{"key":"CAPS", "width":2}, {"key":"AC01"}, {"key":"AC02"}, {"key":"AC03"}, {"key":"AC04"}, {"key":"AC05"}, {"split":true}, {"key":"AC06"}, {"key":"AC07"}, {"key":"AC08"}, {"key":"AC09"}, {"key":"AC10"}, {"key":"AC11"}, {"key":"BKSL", "width":0.5}, {"width":1}],
[{"key":"LFSH", "width":2}, {"key":"LSGT"}, {"key":"AB01"}, {"key":"AB02"}, {"key":"AB03"}, {"key":"AB04"}, {"split":true}, {"key":"AB05"}, {"key":"AB06"}, {"key":"AB07"}, {"key":"AB08"}, {"key":"AB09"}, {"key":"AB10"}, {"key":"RTSH", "width": 1.5}],
- [{"key":"LCTL"}, {"key":"LWIN"}, {"key":"LALT"}, {"key":"SPCE", "width":4}, {"split":true}, {"key":"SPCE", "width":2.5}, {"key":"RALT"}, {"key":"RCTL"}, {"key":"LEFT"}, [{"key":"UP", "height": 0.5}, {"key":"DOWN", "height": 0.5}], {"key":"RGHT"}]
+ [{"key":"LCTL"}, {"key":"LWIN"}, {"key":"LALT"}, {"key":"SPCE", "width":4}, {"split":true}, {"key":"SPCE", "width":2.5}, {"key":"RALT"}, {"key":"RCTL"}, {"key":"LEFT"}, [{"key":"UP", "height": 0.5}, {"key":"DOWN", "height": 0.5}], {"key":"RGHT"}],
+ { "split": true, "settings": true, "close": true }
],
"Split US":[
@@ -68,24 +75,27 @@
[{"key":"TAB", "width":1.5}, {"key":"AD01"}, {"key":"AD02"}, {"key":"AD03"}, {"key":"AD04"}, {"key":"AD05"}, {"key":"AD06"}, {"split":true}, {"key":"AD07"}, {"key":"AD08"}, {"key":"AD09"}, {"key":"AD10"}, {"key":"AD11"}, {"key":"AD12"}, {"key":"BKSL"}],
[{"key":"CAPS", "width":2}, {"key":"AC01"}, {"key":"AC02"}, {"key":"AC03"}, {"key":"AC04"}, {"key":"AC05"}, {"split":true}, {"key":"AC06"}, {"key":"AC07"}, {"key":"AC08"}, {"key":"AC09"}, {"key":"AC10"}, {"key":"AC11"}, {"key": "RTRN", "width": 1.5}],
[{"key":"LFSH", "width":2}, {"key":"LSGT"}, {"key":"AB01"}, {"key":"AB02"}, {"key":"AB03"}, {"key":"AB04"}, {"split":true}, {"key":"AB05"}, {"key":"AB06"}, {"key":"AB07"}, {"key":"AB08"}, {"key":"AB09"}, {"key":"AB10"}, {"key":"RTSH", "width": 1.5}],
- [{"key":"LCTL"}, {"key":"LWIN"}, {"key":"LALT"}, {"key":"SPCE", "width":4}, {"split":true}, {"key":"SPCE", "width":2.5}, {"key":"RALT"}, {"key":"RCTL"}, {"key":"LEFT"}, [{"key":"UP", "height": 0.5}, {"key":"DOWN", "height": 0.5}], {"key":"RGHT"}]
+ [{"key":"LCTL"}, {"key":"LWIN"}, {"key":"LALT"}, {"key":"SPCE", "width":4}, {"split":true}, {"key":"SPCE", "width":2.5}, {"key":"RALT"}, {"key":"RCTL"}, {"key":"LEFT"}, [{"key":"UP", "height": 0.5}, {"key":"DOWN", "height": 0.5}], {"key":"RGHT"}],
+ { "split": true, "settings": true, "close": true }
],
"Mobile": [
[{"key":"TLDE", "width": 2}, {"key":"TAB", "width": 2}, {"key":"ESC", "width": 2}, {"key":"FK01", "width": 2}, {"key":"FK02", "width": 2}, {"key":"FK03", "width": 2}, {"key":"FK04", "width": 2}, {"key":"FK05", "width": 2}, {"key":"FK06", "width": 2}, {"key":"FK07", "width": 2}, {"key":"FK08", "width": 2}, {"key":"FK09", "width": 2}, {"key":"FK10", "width": 2}, {"key":"FK11", "width": 2}, {"key":"FK12", "width": 2}, {"key":"PRSC", "width": 2}, {"key":"DELE", "width": 2}, {"key":"BKSL", "width": 2}],
[{"key":"AE11", "width": 3}, {"key":"AE01", "width": 3}, {"key":"AE02", "width": 3}, {"key":"AE03", "width": 3}, {"key":"AE04", "width": 3}, {"key":"AE05", "width": 3}, {"key":"AE06", "width": 3}, {"key":"AE07", "width": 3}, {"key":"AE08", "width": 3}, {"key":"AE09", "width": 3}, {"key":"AE10", "width": 3}, {"key":"AE12", "width": 3}],
[{"key":"AD11", "width": 3}, {"key":"AD01", "width": 3}, {"key":"AD02", "width": 3}, {"key":"AD03", "width": 3}, {"key":"AD04", "width": 3}, {"key":"AD05", "width": 3}, {"key":"AD06", "width": 3}, {"key":"AD07", "width": 3}, {"key":"AD08", "width": 3}, {"key":"AD09", "width": 3}, {"key":"AD10", "width": 3}, {"key":"AD12", "width": 3}],
- [{"width": 1.5}, {"key":"AC10", "width": 3}, {"key":"AC01", "width": 3}, {"key":"AC02", "width": 3}, {"key":"AC03", "width": 3}, {"key":"AC04", "width": 3}, {"key":"AC05", "width": 3}, {"key":"AC06", "width": 3}, {"key":"AC07", "width": 3}, {"key":"AC08", "width": 3}, {"key":"AC09", "width": 3}, {"key":"AC11", "width": 3}],
+ [{"width": 1.5}, {"key":"AC11", "width": 3}, {"key":"AC01", "width": 3}, {"key":"AC02", "width": 3}, {"key":"AC03", "width": 3}, {"key":"AC04", "width": 3}, {"key":"AC05", "width": 3}, {"key":"AC06", "width": 3}, {"key":"AC07", "width": 3}, {"key":"AC08", "width": 3}, {"key":"AC09", "width": 3}, {"key":"AC10", "width": 3}],
[{"key":"LFSH", "width": 2.5}, {"key":"LSGT", "width": 2}, {"key":"AB08", "width": 3}, {"key":"AB01", "width": 3}, {"key":"AB02", "width": 3}, {"key":"AB03", "width": 3}, {"key":"AB04", "width": 3}, {"key":"AB05", "width": 3}, {"key":"AB06", "width": 3}, {"key":"AB07", "width": 3}, {"key":"AB09", "width": 3}, {"key":"AB10", "width": 2}, {"key": "BKSP", "width": 2.5}],
- [{"key":"CAPS", "width": 2.5}, {"key":"LCTL", "width": 2.5}, {"key":"LWIN", "width": 2.5}, {"key":"LALT", "width": 2.5}, {"key":"SPCE", "width":10}, {"key":"RALT", "width": 2.5}, {"key":"RCTL", "width": 2.5}, {"key":"LEFT", "width": 2.5}, [{"key":"UP", "width": 2.5, "height": 0.5}, {"key":"DOWN", "width": 2.5, "height": 0.5}], {"key":"RGHT", "width": 2.5}, {"key":"RTRN", "width": 3.5}]
+ [{"key":"CAPS", "width": 2.5}, {"key":"LCTL", "width": 2.5}, {"key":"LWIN", "width": 2.5}, {"key":"LALT", "width": 2.5}, {"key":"SPCE", "width":10}, {"key":"RALT", "width": 2.5}, {"key":"RCTL", "width": 2.5}, {"key":"LEFT", "width": 2.5}, [{"key":"UP", "width": 2.5, "height": 0.5}, {"key":"DOWN", "width": 2.5, "height": 0.5}], {"key":"RGHT", "width": 2.5}, {"key":"RTRN", "width": 3.5}],
+ { "split": false, "settings": true, "close": true }
],
"Split Mobile": [
[{"key":"TLDE", "width": 2}, {"key":"TAB", "width": 2}, {"key":"ESC", "width": 2}, {"key":"FK01", "width": 2}, {"key":"FK02", "width": 2}, {"key":"FK03", "width": 2}, {"key":"FK04", "width": 2}, {"key":"FK05", "width": 2}, {"key":"FK06", "width": 2}, {"split":true}, {"key":"FK07", "width": 2}, {"key":"FK08", "width": 2}, {"key":"FK09", "width": 2}, {"key":"FK10", "width": 2}, {"key":"FK11", "width": 2}, {"key":"FK12", "width": 2}, {"key":"PRSC", "width": 2}, {"key":"DELE", "width": 3}, {"key":"BKSL", "width": 2.5}],
[{"key":"AE11", "width": 3}, {"key":"AE01", "width": 3}, {"key":"AE02", "width": 3}, {"key":"AE03", "width": 3}, {"key":"AE04", "width": 3}, {"key":"AE05", "width": 3}, {"split":true}, {"key":"AE06", "width": 3}, {"key":"AE07", "width": 3}, {"key":"AE08", "width": 3}, {"key":"AE09", "width": 3}, {"key":"AE10", "width": 3}, {"key":"AE12", "width": 4.5}],
[{"key":"AD11", "width": 3}, {"key":"AD01", "width": 3}, {"key":"AD02", "width": 3}, {"key":"AD03", "width": 3}, {"key":"AD04", "width": 3}, {"key":"AD05", "width": 3}, {"split":true}, {"key":"AD06", "width": 3}, {"key":"AD07", "width": 3}, {"key":"AD08", "width": 3}, {"key":"AD09", "width": 3}, {"key":"AD10", "width": 3}, {"key":"AD12", "width": 4.5}],
- [{"key":"AC10", "width": 3}, {"key":"AC01", "width": 3}, {"key":"AC02", "width": 3}, {"key":"AC03", "width": 3}, {"key":"AC04", "width": 3}, {"key":"AC05", "width": 3}, {"split":true}, {"key":"AC05", "width": 3}, {"key":"AC06", "width": 3}, {"key":"AC07", "width": 3}, {"key":"AC08", "width": 3}, {"key":"AC09", "width": 3}, {"key":"AC11", "width": 4.5}],
+ [{"key":"AC11", "width": 3}, {"key":"AC01", "width": 3}, {"key":"AC02", "width": 3}, {"key":"AC03", "width": 3}, {"key":"AC04", "width": 3}, {"key":"AC05", "width": 3}, {"split":true}, {"key":"AC05", "width": 3}, {"key":"AC06", "width": 3}, {"key":"AC07", "width": 3}, {"key":"AC08", "width": 3}, {"key":"AC09", "width": 3}, {"key":"AC10", "width": 3}, {"width": 1.5}],
[{"key":"LFSH", "width": 2}, {"key":"LSGT", "width": 2}, {"key":"AB08", "width": 2}, {"key":"AB01", "width": 3}, {"key":"AB02", "width": 3}, {"key":"AB03", "width": 3}, {"key":"AB04", "width": 3}, {"split":true}, {"key":"AB04", "width": 3}, {"key":"AB05", "width": 3}, {"key":"AB06", "width": 3}, {"key":"AB07", "width": 3}, {"key":"AB09", "width": 3}, {"key":"AB10", "width": 2}, {"key": "BKSP", "width": 2.5}],
- [{"key":"CAPS", "width": 2.5}, {"key":"LCTL", "width": 2.5}, {"key":"LWIN", "width": 2.5}, {"key":"LALT", "width": 2.5}, {"key":"SPCE", "width":8}, {"split":true}, {"key":"SPCE", "width":4}, {"key":"RALT", "width": 2.5}, {"key":"RCTL", "width": 2.5}, {"key":"LEFT", "width": 2.5}, [{"key":"UP", "width": 2.5, "height": 0.5}, {"key":"DOWN", "width": 2.5, "height": 0.5}], {"key":"RGHT", "width": 2.5}, {"key":"RTRN", "width": 3}]
+ [{"key":"CAPS", "width": 2.5}, {"key":"LCTL", "width": 2.5}, {"key":"LWIN", "width": 2.5}, {"key":"LALT", "width": 2.5}, {"key":"SPCE", "width":8}, {"split":true}, {"key":"SPCE", "width":4}, {"key":"RALT", "width": 2.5}, {"key":"RCTL", "width": 2.5}, {"key":"LEFT", "width": 2.5}, [{"key":"UP", "width": 2.5, "height": 0.5}, {"key":"DOWN", "width": 2.5, "height": 0.5}], {"key":"RGHT", "width": 2.5}, {"key":"RTRN", "width": 3}],
+ { "split": true, "settings": true, "close": true }
]
}
\ No newline at end of file
diff --git a/gnome/.local/share/gnome-shell/extensions/gjsosk@vishram1123.com/prefs.js b/gnome/.local/share/gnome-shell/extensions/gjsosk@vishram1123.com/prefs.js
index d9a83ac..8306afb 100644
--- a/gnome/.local/share/gnome-shell/extensions/gjsosk@vishram1123.com/prefs.js
+++ b/gnome/.local/share/gnome-shell/extensions/gjsosk@vishram1123.com/prefs.js
@@ -44,6 +44,7 @@ export default class GjsOskPreferences extends ExtensionPreferences {
}
let layoutList = Object.keys(layouts);
+ layoutList.push("Custom")
let layoutLandscapeDrop = Gtk.DropDown.new_from_strings(layoutList);
layoutLandscapeDrop.valign = Gtk.Align.CENTER;
layoutLandscapeDrop.selected = settings.get_int("layout-landscape");
@@ -63,6 +64,40 @@ export default class GjsOskPreferences extends ExtensionPreferences {
layoutPortraitRow.add_suffix(layoutPortraitDrop);
layoutPortraitRow.activatable_widget = layoutPortraitDrop;
+ const customLayoutRow = new Adw.EntryRow({
+ title: _('Custom Layout')
+ });
+ layoutRow.add_row(customLayoutRow);
+
+ customLayoutRow.set_text(settings.get_string("custom-layout"));
+ customLayoutRow.set_show_apply_button(true);
+
+ const createKeyboardLayoutRow = new Adw.ActionRow({
+ title: _('Create/edit a custom keyboard layout')
+ })
+ layoutRow.add_row(createKeyboardLayoutRow)
+
+ const layoutLink = new Gtk.LinkButton({
+ label: 'Keyboard Layout Editor',
+ uri: 'https://vishram1123.github.io/gjs-osk'
+ })
+
+ createKeyboardLayoutRow.add_suffix(layoutLink)
+ createKeyboardLayoutRow.activatable_widget = layoutLink
+
+ const disableEdgeSwipeRow = new Adw.ActionRow({
+ title: _('Disable Edge Swipe')
+ });
+ behaviorGroup.add(disableEdgeSwipeRow);
+
+ const disableEdgeSwipeDT = new Gtk.Switch({
+ active: settings.get_boolean('disable-edge-swipe'),
+ valign: Gtk.Align.CENTER,
+ });
+
+ disableEdgeSwipeRow.add_suffix(disableEdgeSwipeDT);
+ disableEdgeSwipeRow.activatable_widget = disableEdgeSwipeDT;
+
const enableDragRow = new Adw.ActionRow({
title: _('Enable Dragging')
});
@@ -217,18 +252,73 @@ export default class GjsOskPreferences extends ExtensionPreferences {
defaultPosition.add_suffix(snapDrop);
defaultPosition.activatable_widget = snapDrop;
- const soundPlayRow = new Adw.ActionRow({
- title: _('Play sound')
+ const soundPlayRow = new Adw.ExpanderRow({
+ title: _('Play sound'),
+ show_enable_switch: true
});
behaviorGroup.add(soundPlayRow);
+ soundPlayRow.enable_expansion = settings.get_boolean('play-sound')
- const soundPlayDT = new Gtk.Switch({
- active: settings.get_boolean('play-sound'),
+ const fileRow = new Adw.ActionRow({
+ title: _('Sound file'),
+ subtitle: settings.get_string('sound-file') || _('No file selected'),
+ activatable: false, // prevent clicking the whole row
+ });
+
+ const fileButton = new Gtk.Button({
+ label: settings.get_string('sound-file') ? _('Clear') : _('Choose'),
valign: Gtk.Align.CENTER,
});
- soundPlayRow.add_suffix(soundPlayDT);
- soundPlayRow.activatable_widget = soundPlayDT;
+ fileRow.add_suffix(fileButton);
+ fileRow.activatable_widget = fileButton;
+
+ fileButton.connect('clicked', () => {
+ const currentPath = settings.get_string('sound-file');
+ if (currentPath) {
+ settings.set_string('sound-file', '');
+ fileRow.subtitle = _('No file selected');
+ fileButton.label = _('Choose');
+ } else {
+ const fileChooser = new Gtk.FileChooserNative({
+ title: _('Select OGG File'),
+ transient_for: window,
+ action: Gtk.FileChooserAction.OPEN,
+ accept_label: _('Open'),
+ cancel_label: _('Cancel'),
+ });
+
+ const filter = new Gtk.FileFilter();
+ filter.add_mime_type('audio/ogg');
+ filter.set_name(_('OGG files'));
+ fileChooser.add_filter(filter);
+
+ fileChooser.connect('response', (dlg, response) => {
+ if (response === Gtk.ResponseType.ACCEPT) {
+ const file = dlg.get_file();
+ if (file) {
+ const path = file.get_path();
+ settings.set_string('sound-file', path);
+ fileRow.subtitle = path;
+ fileButton.label = _('Clear');
+
+ // Optionally play the file immediately
+ try {
+ let player = global.display.get_sound_player();
+ player.play_from_file(path, null);
+ } catch (e) {
+ logError(e, 'Failed to play sound file');
+ }
+ }
+ }
+ dlg.destroy();
+ });
+
+ fileChooser.show();
+ }
+ });
+
+ soundPlayRow.add_row(fileRow);
const appearanceGroup = new Adw.PreferencesGroup({
title: _("Appearance")
@@ -405,7 +495,7 @@ export default class GjsOskPreferences extends ExtensionPreferences {
context.add_class("title-1");
let another_label = new Gtk.Label({
- label: _("Autorelease ") + `776e35f`
+ label: _("Autorelease ") + `3f0ef02`
});
let links_pref_group = new Adw.PreferencesGroup();
@@ -447,6 +537,10 @@ export default class GjsOskPreferences extends ExtensionPreferences {
settings.bind("layout-landscape", layoutLandscapeDrop, "selected", 0);
settings.bind("layout-portrait", layoutPortraitDrop, "selected", 0);
+ customLayoutRow.connect("apply", () => {
+ settings.set_string("custom-layout", customLayoutRow.get_text());
+ });
+ settings.bind("disable-edge-swipe", disableEdgeSwipeDT, "active", 0);
settings.bind("enable-drag", dragEnableDT, "active", 0);
settings.bind("enable-tap-gesture", dragOpt, "selected", 0);
settings.bind("indicator-enabled", indEnabled, "active", 0);
@@ -472,7 +566,7 @@ export default class GjsOskPreferences extends ExtensionPreferences {
settings.bind("outer-spacing-px", numChanger_outer, "value", 0);
settings.bind("snap-spacing-px", numChanger_snap, "value", 0)
settings.bind("round-key-corners", roundKeyCDT, "active", 0);
- settings.bind("play-sound", soundPlayDT, "active", 0);
+ settings.bind("play-sound", soundPlayRow, "enable-expansion", 0);
settings.bind("show-icons", showIconDT, "active", 0)
settings.bind("default-snap", snapDrop, "selected", 0);
monitorDrop.connect("notify::selected", () => {
@@ -492,6 +586,8 @@ export default class GjsOskPreferences extends ExtensionPreferences {
window.connect("close-request", () => {
settings.set_int("layout-landscape", layoutLandscapeDrop.selected);
settings.set_int("layout-portrait", layoutPortraitDrop.selected);
+ settings.set_string("custom-layout", customLayoutRow.get_text());
+ settings.set_boolean("disable-edge-swipe", disableEdgeSwipeDT.active);
settings.set_boolean("enable-drag", dragEnableDT.active);
settings.set_int("enable-tap-gesture", dragOpt.selected);
settings.set_boolean("indicator-enabled", indEnabled.active);
@@ -513,7 +609,7 @@ export default class GjsOskPreferences extends ExtensionPreferences {
settings.set_int("outer-spacing-px", numChanger_outer.value);
settings.set_int("snap-spacing-px", numChanger_snap.value)
settings.set_boolean("round-key-corners", roundKeyCDT.active);
- settings.set_boolean("play-sound", soundPlayDT.active);
+ settings.set_boolean("play-sound", soundPlayRow.enable_expansion);
settings.set_boolean("show-icons", showIconDT.active)
settings.set_int("default-snap", snapDrop.selected);
currentMonitorMap[monitors.length + ""] = monitors.map(m => { return m.get_connector() })[monitorDrop.selected];
diff --git a/gnome/.local/share/gnome-shell/extensions/gjsosk@vishram1123.com/schemas/gschemas.compiled b/gnome/.local/share/gnome-shell/extensions/gjsosk@vishram1123.com/schemas/gschemas.compiled
index 6b8f5b6..07062d6 100644
Binary files a/gnome/.local/share/gnome-shell/extensions/gjsosk@vishram1123.com/schemas/gschemas.compiled and b/gnome/.local/share/gnome-shell/extensions/gjsosk@vishram1123.com/schemas/gschemas.compiled differ
diff --git a/gnome/.local/share/gnome-shell/extensions/gjsosk@vishram1123.com/schemas/org.gnome.shell.extensions.gjsosk.gschema.xml b/gnome/.local/share/gnome-shell/extensions/gjsosk@vishram1123.com/schemas/org.gnome.shell.extensions.gjsosk.gschema.xml
index d2ef8de..ab5beda 100644
--- a/gnome/.local/share/gnome-shell/extensions/gjsosk@vishram1123.com/schemas/org.gnome.shell.extensions.gjsosk.gschema.xml
+++ b/gnome/.local/share/gnome-shell/extensions/gjsosk@vishram1123.com/schemas/org.gnome.shell.extensions.gjsosk.gschema.xml
@@ -7,6 +7,9 @@
0
+
+ ""
+
100
@@ -19,6 +22,9 @@
30
+
+ false
+
true
@@ -82,8 +88,11 @@
true
+
+ ""
+
- true
+ true
@@ -92,5 +101,8 @@
false
+
+ false
+
diff --git a/gnome/.local/share/gnome-shell/extensions/gjsosk@vishram1123.com/stylesheet.css b/gnome/.local/share/gnome-shell/extensions/gjsosk@vishram1123.com/stylesheet.css
index f4e201c..60a1203 100644
--- a/gnome/.local/share/gnome-shell/extensions/gjsosk@vishram1123.com/stylesheet.css
+++ b/gnome/.local/share/gnome-shell/extensions/gjsosk@vishram1123.com/stylesheet.css
@@ -28,7 +28,6 @@
box-sizing: border-box;
background-image: url(ui/icons/hicolor/scalable/actions/transparent.svg);
background-repeat: no-repeat;
- background-position: center;
}
.dr-b {
@@ -55,7 +54,6 @@
.down_btn,
.right_btn {
background-repeat: no-repeat;
- background-position: center;
}
.close_btn.regular,
@@ -158,6 +156,16 @@
background-image: url(ui/icons/hicolor/scalable/actions/alt-dark.svg);
}
+.menu_btn.regular,
+.menu_btn.selected.inverted {
+ background-image: url(ui/icons/hicolor/scalable/actions/menu.svg);
+}
+
+.menu_btn.inverted,
+.menu_btn.selected.regular {
+ background-image: url(ui/icons/hicolor/scalable/actions/menu-dark.svg);
+}
+
.space_btn.regular,
.space_btn.selected.inverted {
background-image: url(ui/icons/hicolor/scalable/actions/space.svg);
diff --git a/gnome/.local/share/gnome-shell/extensions/gjsosk@vishram1123.com/ui/icons/hicolor/scalable/actions/menu-dark.svg b/gnome/.local/share/gnome-shell/extensions/gjsosk@vishram1123.com/ui/icons/hicolor/scalable/actions/menu-dark.svg
new file mode 100644
index 0000000..7d37fa2
--- /dev/null
+++ b/gnome/.local/share/gnome-shell/extensions/gjsosk@vishram1123.com/ui/icons/hicolor/scalable/actions/menu-dark.svg
@@ -0,0 +1,60 @@
+
+
diff --git a/gnome/.local/share/gnome-shell/extensions/gjsosk@vishram1123.com/ui/icons/hicolor/scalable/actions/menu.svg b/gnome/.local/share/gnome-shell/extensions/gjsosk@vishram1123.com/ui/icons/hicolor/scalable/actions/menu.svg
new file mode 100644
index 0000000..3b7f08f
--- /dev/null
+++ b/gnome/.local/share/gnome-shell/extensions/gjsosk@vishram1123.com/ui/icons/hicolor/scalable/actions/menu.svg
@@ -0,0 +1,61 @@
+
+