extension.js 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261
  1. import Clutter from 'gi://Clutter';
  2. import Gio from 'gi://Gio';
  3. import GLib from 'gi://GLib';
  4. import GObject from 'gi://GObject';
  5. import St from 'gi://St';
  6. import * as Main from 'resource:///org/gnome/shell/ui/main.js';
  7. import * as PanelMenu from 'resource:///org/gnome/shell/ui/panelMenu.js';
  8. import * as PopupMenu from 'resource:///org/gnome/shell/ui/popupMenu.js';
  9. import * as QuickSettings from 'resource:///org/gnome/shell/ui/quickSettings.js';
  10. import * as KeyboardManager from 'resource:///org/gnome/shell/misc/keyboardManager.js';
  11. import { Dialog } from 'resource:///org/gnome/shell/ui/dialog.js';
  12. import { Extension, gettext as _ } from 'resource:///org/gnome/shell/extensions/extension.js';
  13. class KeyboardMenuToggle extends QuickSettings.QuickMenuToggle {
  14. static {
  15. GObject.registerClass(this);
  16. }
  17. constructor(extensionObject) {
  18. super({
  19. title: _('Screen Keyboard'),
  20. iconName: 'input-keyboard-symbolic',
  21. toggleMode: true,
  22. });
  23. this.extensionObject = extensionObject;
  24. this.settings = extensionObject.getSettings();
  25. this.menu.setHeader('input-keyboard-symbolic', _('Screen Keyboard'), _('Opening Mode'));
  26. this._itemsSection = new PopupMenu.PopupMenuSection();
  27. this._itemsSection.addMenuItem(new PopupMenu.PopupImageMenuItem(_('Never'), this.settings.get_int("enable-tap-gesture") == 0 ? 'emblem-ok-symbolic' : null));
  28. this._itemsSection.addMenuItem(new PopupMenu.PopupImageMenuItem(_("Only on Touch"), this.settings.get_int("enable-tap-gesture") == 1 ? 'emblem-ok-symbolic' : null));
  29. this._itemsSection.addMenuItem(new PopupMenu.PopupImageMenuItem(_("Always"), this.settings.get_int("enable-tap-gesture") == 2 ? 'emblem-ok-symbolic' : null));
  30. for (var i in this._itemsSection._getMenuItems()){
  31. const item = this._itemsSection._getMenuItems()[i]
  32. const num = i
  33. item.connect('activate', () => this.settings.set_int("enable-tap-gesture", num))
  34. }
  35. this.menu.addMenuItem(this._itemsSection);
  36. this.settings.bind('indicator-enabled',
  37. this, 'checked',
  38. Gio.SettingsBindFlags.DEFAULT);
  39. this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
  40. const settingsItem = this.menu.addAction(_('More Settings'),
  41. () => this.extensionObject.openPreferences());
  42. settingsItem.visible = Main.sessionMode.allowSettings;
  43. this.menu._settingsActions[this.extensionObject.uuid] = settingsItem;
  44. }
  45. _refresh() {
  46. for (var i in this._itemsSection._getMenuItems()){
  47. this._itemsSection._getMenuItems()[i].setIcon(this.settings.get_int("enable-tap-gesture") == i ? 'emblem-ok-symbolic' : null)
  48. }
  49. }
  50. };
  51. let keycodes;
  52. export default class GjsOskExtension extends Extension {
  53. _openKeyboard() {
  54. if (this.Keyboard.state == "closed") {
  55. this.Keyboard.opened = true;
  56. this.Keyboard.open();
  57. }
  58. }
  59. _closeKeyboard() {
  60. if (this.Keyboard.state == "opened") {
  61. this.Keyboard.opened = false;
  62. this.Keyboard.close();
  63. }
  64. }
  65. _toggleKeyboard() {
  66. if (!this.Keyboard.opened) {
  67. this._openKeyboard();
  68. this.Keyboard.openedFromButton = true;
  69. this.Keyboard.closedFromButton = false
  70. } else {
  71. this._closeKeyboard();
  72. this.Keyboard.openedFromButton = false;
  73. this.Keyboard.closedFromButton = true;
  74. }
  75. }
  76. open_interval() {
  77. global.stage.disconnect(this.tapConnect)
  78. if (this.openInterval !== null) {
  79. clearInterval(this.openInterval);
  80. this.openInterval = null;
  81. }
  82. this.openInterval = setInterval(() => {
  83. this.Keyboard.get_parent().set_child_at_index(this.Keyboard, this.Keyboard.get_parent().get_n_children() - 1);
  84. this.Keyboard.set_child_at_index(this.Keyboard.box, this.Keyboard.get_n_children() - 1);
  85. if (!this.Keyboard.openedFromButton && this.lastInputMethod) {
  86. if (Main.inputMethod.currentFocus != null && Main.inputMethod.currentFocus.is_focused() && !this.Keyboard.closedFromButton) {
  87. this._openKeyboard();
  88. } else if (!this.Keyboard.closedFromButton) {
  89. this._closeKeyboard();
  90. this.Keyboard.closedFromButton = false
  91. } else if (Main.inputMethod.currentFocus == null) {
  92. this.Keyboard.closedFromButton = false
  93. }
  94. }
  95. }, 300);
  96. this.tapConnect = global.stage.connect("event", (_actor, event) => {
  97. if (event.type() !== 4 && event.type() !== 5) {
  98. this.lastInputMethod = [false, event.type() >= 9 && event.type() <= 12, true][this.settings.get_int("enable-tap-gesture")]
  99. }
  100. })
  101. }
  102. enable() {
  103. this.settings = this.getSettings();
  104. this.openBit = this.settings.get_child("indicator");
  105. let [ok, contents] = GLib.file_get_contents(this.path + '/keycodes.json');
  106. if (ok) {
  107. keycodes = JSON.parse(contents)[['qwerty', 'azerty', 'dvorak', "qwertz"][this.settings.get_int("lang")]];
  108. }
  109. this.Keyboard = new Keyboard(this.settings);
  110. this._indicator = null;
  111. this.openInterval = null;
  112. if (this.settings.get_boolean("indicator-enabled")) {
  113. this._indicator = new PanelMenu.Button(0.0, "GJS OSK Indicator", false);
  114. let icon = new St.Icon({
  115. gicon: new Gio.ThemedIcon({
  116. name: 'input-keyboard-symbolic'
  117. }),
  118. style_class: 'system-status-icon'
  119. });
  120. this._indicator.add_child(icon);
  121. this._indicator.connect("button-press-event", () => this._toggleKeyboard());
  122. this._indicator.connect("touch-event", (_actor, event) => {
  123. if (event.type() == 11) this._toggleKeyboard()
  124. });
  125. Main.panel.addToStatusArea("GJS OSK Indicator", this._indicator);
  126. }
  127. this._toggle = new KeyboardMenuToggle(this);
  128. this._quick_settings_indicator = new QuickSettings.SystemIndicator();
  129. this._quick_settings_indicator.quickSettingsItems.push(this._toggle);
  130. Main.panel.statusArea.quickSettings.addExternalIndicator(this._quick_settings_indicator);
  131. if (this.settings.get_int("enable-tap-gesture") > 0) {
  132. this.open_interval();
  133. }
  134. this.openFromCommandHandler = this.openBit.connect("changed", () => {
  135. this.openBit.set_boolean("opened", false)
  136. this._toggleKeyboard();
  137. })
  138. this.settingsHandler = this.settings.connect("changed", key => {
  139. this.Keyboard.openedFromButton = false;
  140. let [ok, contents] = GLib.file_get_contents(this.path + '/keycodes.json');
  141. if (ok) {
  142. keycodes = JSON.parse(contents)[["qwerty", "azerty", "dvorak", "qwertz"][this.settings.get_int("lang")]];
  143. }
  144. this.Keyboard.refresh();
  145. this._toggle._refresh();
  146. if (this.settings.get_boolean("indicator-enabled")) {
  147. if (this._indicator != null) {
  148. this._indicator.destroy();
  149. this._indicator = null;
  150. }
  151. this._indicator = new PanelMenu.Button(0.0, "GJS OSK Indicator", false);
  152. let icon = new St.Icon({
  153. gicon: new Gio.ThemedIcon({
  154. name: 'input-keyboard-symbolic'
  155. }),
  156. style_class: 'system-status-icon'
  157. });
  158. this._indicator.add_child(icon);
  159. this._indicator.connect("button-press-event", () => this._toggleKeyboard());
  160. this._indicator.connect("touch-event", (_actor, event) => {
  161. if (event.type() == 11) this._toggleKeyboard()
  162. });
  163. Main.panel.addToStatusArea("GJS OSK Indicator", this._indicator);
  164. } else {
  165. if (this._indicator != null) {
  166. this._indicator.destroy();
  167. this._indicator = null;
  168. }
  169. }
  170. global.stage.disconnect(this.tapConnect)
  171. if (this.openInterval !== null) {
  172. clearInterval(this.openInterval);
  173. this.openInterval = null;
  174. }
  175. if (this.settings.get_int("enable-tap-gesture") > 0) {
  176. this.open_interval();
  177. }
  178. });
  179. }
  180. disable() {
  181. this._quick_settings_indicator.quickSettingsItems.forEach(item => item.destroy());
  182. this._quick_settings_indicator.destroy();
  183. this._quick_settings_indicator = null;
  184. if (this._indicator !== null) {
  185. this._indicator.destroy();
  186. this._indicator = null;
  187. }
  188. this.Keyboard.destroy();
  189. this.settings.disconnect(this.settingsHandler);
  190. this.settings = null;
  191. this.openBit.disconnect(this.openFromCommandHandler);
  192. this.openBit = null;
  193. global.stage.disconnect(this.tapConnect)
  194. if (this.openInterval !== null) {
  195. clearInterval(this.openInterval);
  196. this.openInterval = null;
  197. }
  198. this._toggle.destroy()
  199. this._toggle = null
  200. this.settings = null
  201. this.Keyboard = null
  202. keycodes = null
  203. }
  204. }
  205. class Keyboard extends Dialog {
  206. static [GObject.signals] = {
  207. 'drag-begin': {},
  208. 'drag-end': {}
  209. };
  210. static {
  211. GObject.registerClass(this);
  212. }
  213. _init(settings) {
  214. this.startupInterval = setInterval(() => {
  215. this.init = KeyboardManager.getKeyboardManager()._current.id;
  216. this.initLay = Object.keys(KeyboardManager.getKeyboardManager()._layoutInfos);
  217. if (this.initLay == undefined || this.init == undefined) {
  218. return;
  219. }
  220. this.settings = settings;
  221. let monitor = Main.layoutManager.primaryMonitor;
  222. super._init(Main.layoutManager.uiGroup, 'db-keyboard-content');
  223. this.box = new St.BoxLayout({
  224. vertical: true
  225. });
  226. this.widthPercent = (monitor.width > monitor.height) ? settings.get_int("landscape-width-percent") / 100 : settings.get_int("portrait-width-percent") / 100;
  227. this.heightPercent = (monitor.width > monitor.height) ? settings.get_int("landscape-height-percent") / 100 : settings.get_int("portrait-height-percent") / 100;
  228. this.buildUI();
  229. this.draggable = false;
  230. this.add_child(this.box);
  231. this.close();
  232. this.box.set_name("osk-gjs")
  233. this.mod = [];
  234. this.modBtns = [];
  235. this.capsL = false;
  236. this.shift = false;
  237. this.alt = false;
  238. this.box.add_style_class_name("boxLay");
  239. this.box.set_style("background-color: rgb(" + settings.get_double("background-r") + "," + settings.get_double("background-g") + "," + settings.get_double("background-b") + ");")
  240. this.opened = false;
  241. this.state = "closed";
  242. this.delta = [];
  243. this.checkMonitor();
  244. this._dragging = false;
  245. this.inputDevice = Clutter.get_default_backend().get_default_seat().create_virtual_device(Clutter.InputDeviceType.KEYBOARD_DEVICE);
  246. clearInterval(this.startupInterval);
  247. }, 200);
  248. }
  249. destroy() {
  250. if (this.startupInterval !== null) {
  251. clearInterval(this.startupInterval);
  252. this.startupInterval = null;
  253. }
  254. if (this.startupTimeout !== null) {
  255. clearInterval(this.startupTimeout);
  256. this.startupTimeout = null;
  257. }
  258. if (this.monitorChecker !== null) {
  259. clearInterval(this.monitorChecker);
  260. this.monitorChecker = null;
  261. }
  262. if (this.textboxChecker !== null) {
  263. clearInterval(this.textboxChecker);
  264. this.textboxChecker = null;
  265. }
  266. if (this.stateTimeout !== null ) {
  267. clearTimeout(this.stateTimeout);
  268. this.stateTimeout = null;
  269. }
  270. if (this.keyTimeout !== null) {
  271. clearTimeout(this.keyTimeout);
  272. this.keyTimeout = null;
  273. }
  274. super.destroy();
  275. }
  276. vfunc_button_press_event() {
  277. this.delta = [Clutter.get_current_event().get_coords()[0] - this.translation_x, Clutter.get_current_event().get_coords()[1] - this.translation_y];
  278. return this.startDragging(Clutter.get_current_event(), this.delta)
  279. }
  280. startDragging(event, delta) {
  281. if (this.draggable) {
  282. if (this._dragging)
  283. return Clutter.EVENT_PROPAGATE;
  284. this._dragging = true;
  285. this.box.set_opacity(255);
  286. this.box.ease({
  287. opacity: 200,
  288. duration: 100,
  289. mode: Clutter.AnimationMode.EASE_OUT_QUAD,
  290. onComplete: () => {}
  291. });
  292. let device = event.get_device();
  293. let sequence = event.get_event_sequence();
  294. this._grab = global.stage.grab(this);
  295. this._grabbedDevice = device;
  296. this._grabbedSequence = sequence;
  297. this.emit('drag-begin');
  298. let [absX, absY] = event.get_coords();
  299. this.snapMovement(absX - delta[0], absY - delta[1]);
  300. return Clutter.EVENT_STOP;
  301. } else {
  302. return Clutter.EVENT_PROPAGATE;
  303. }
  304. }
  305. vfunc_button_release_event() {
  306. if (this._dragging && !this._grabbedSequence) {
  307. return this.endDragging();
  308. }
  309. return Clutter.EVENT_PROPAGATE;
  310. }
  311. endDragging() {
  312. if (this.draggable) {
  313. if (this._dragging) {
  314. if (this._releaseId) {
  315. this.disconnect(this._releaseId);
  316. this._releaseId = 0;
  317. }
  318. if (this._grab) {
  319. this._grab.dismiss();
  320. this._grab = null;
  321. }
  322. this.box.set_opacity(200);
  323. this.box.ease({
  324. opacity: 255,
  325. duration: 100,
  326. mode: Clutter.AnimationMode.EASE_OUT_QUAD,
  327. onComplete: () => {}
  328. });
  329. this._grabbedSequence = null;
  330. this._grabbedDevice = null;
  331. this._dragging = false;
  332. this.delta = [];
  333. this.emit('drag-end');
  334. this._dragging = false;
  335. }
  336. return Clutter.EVENT_STOP;
  337. } else {
  338. return Clutter.EVENT_STOP;
  339. }
  340. }
  341. vfunc_motion_event() {
  342. let event = Clutter.get_current_event();
  343. if (this._dragging && !this._grabbedSequence) {
  344. this.motionEvent(event);
  345. }
  346. return Clutter.EVENT_PROPAGATE;
  347. }
  348. motionEvent(event) {
  349. if (this.draggable) {
  350. let [absX, absY] = event.get_coords();
  351. this.snapMovement(absX - this.delta[0], absY - this.delta[1]);
  352. return Clutter.EVENT_STOP
  353. } else {
  354. return Clutter.EVENT_STOP
  355. }
  356. }
  357. vfunc_touch_event() {
  358. let event = Clutter.get_current_event();
  359. let sequence = event.get_event_sequence();
  360. if (!this._dragging && event.type() == Clutter.EventType.TOUCH_BEGIN) {
  361. this.delta = [event.get_coords()[0] - this.translation_x, event.get_coords()[1] - this.translation_y];
  362. this.startDragging(event);
  363. return Clutter.EVENT_STOP;
  364. } else if (this._grabbedSequence && sequence.get_slot() === this._grabbedSequence.get_slot()) {
  365. if (event.type() == Clutter.EventType.TOUCH_UPDATE) {
  366. return this.motionEvent(event);
  367. } else if (event.type() == Clutter.EventType.TOUCH_END) {
  368. return this.endDragging();
  369. }
  370. }
  371. return Clutter.EVENT_PROPAGATE;
  372. }
  373. snapMovement(xPos, yPos) {
  374. let monitor = Main.layoutManager.primaryMonitor
  375. if (Math.abs(xPos - ((monitor.width * .5) - ((this.width * .5)))) <= 50) {
  376. xPos = ((monitor.width * .5) - ((this.width * .5)));
  377. } else if (Math.abs(xPos - 25) <= 50) {
  378. xPos = 25;
  379. } else if (Math.abs(xPos - (monitor.width - this.width - 25)) <= 50) {
  380. xPos = monitor.width - this.width - 25
  381. }
  382. if (Math.abs(yPos - (monitor.height - this.height - 25)) <= 50) {
  383. yPos = monitor.height - this.height - 25;
  384. } else if (Math.abs(yPos - 25) <= 50) {
  385. yPos = 25;
  386. } else if (Math.abs(yPos - ((monitor.height * .5) - (this.height * .5))) <= 50) {
  387. yPos = (monitor.height * .5) - (this.height * .5);
  388. }
  389. this.set_translation(xPos, yPos, 0);
  390. }
  391. checkMonitor() {
  392. let monitor = Main.layoutManager.primaryMonitor;
  393. let oldMonitorDimensions = [monitor.width, monitor.height];
  394. this.monitorChecker = setInterval(() => {
  395. monitor = Main.layoutManager.primaryMonitor;
  396. if (oldMonitorDimensions[0] != monitor.width || oldMonitorDimensions[1] != monitor.height) {
  397. this.refresh()
  398. oldMonitorDimensions = [monitor.width, monitor.height];
  399. }
  400. }, 200);
  401. }
  402. refresh() {
  403. let monitor = Main.layoutManager.primaryMonitor;
  404. this.box.remove_all_children();
  405. this.box.set_style_class_name("boxLay")
  406. this.widthPercent = (monitor.width > monitor.height) ? this.settings.get_int("landscape-width-percent") / 100 : this.settings.get_int("portrait-width-percent") / 100;
  407. this.heightPercent = (monitor.width > monitor.height) ? this.settings.get_int("landscape-height-percent") / 100 : this.settings.get_int("portrait-height-percent") / 100;
  408. this.buildUI();
  409. this.draggable = false;
  410. this.keys.forEach(keyholder => {
  411. if (!keyholder.has_style_class_name("move_btn")) {
  412. keyholder.set_opacity(0);
  413. keyholder.ease({
  414. opacity: 255,
  415. duration: 100,
  416. mode: Clutter.AnimationMode.EASE_OUT_QUAD,
  417. onComplete: () => {
  418. keyholder.set_z_position(0);
  419. this.box.remove_style_pseudo_class("dragging");
  420. }
  421. });
  422. }
  423. });
  424. if (this.startupTimeout !== null) {
  425. clearInterval(this.startupTimeout);
  426. this.startupTimeout = null;
  427. }
  428. this.startupTimeout = setTimeout(() => {
  429. this.init = KeyboardManager.getKeyboardManager()._current.id;
  430. this.initLay = Object.keys(KeyboardManager.getKeyboardManager()._layoutInfos);
  431. if (this.initLay == undefined || this.init == undefined) {
  432. this.refresh();
  433. return;
  434. }
  435. this.close();
  436. }, 200);
  437. this.mod = [];
  438. this.modBtns = [];
  439. this.capsL = false;
  440. this.shift = false;
  441. this.alt = false;
  442. this.box.set_style("background-color: rgb(" + this.settings.get_double("background-r") + "," + this.settings.get_double("background-g") + "," + this.settings.get_double("background-b") + ");")
  443. this.opened = false;
  444. this.state = "closed";
  445. this.delta = [];
  446. this.dragging = false;
  447. }
  448. open() {
  449. this.inputDevice = Clutter.get_default_backend().get_default_seat().create_virtual_device(Clutter.InputDeviceType.KEYBOARD_DEVICE);
  450. if (this.startupTimeout !== null) {
  451. clearInterval(this.startupTimeout);
  452. this.startupTimeout = null;
  453. }
  454. this.startupTimeout = setTimeout(() => {
  455. this.init = KeyboardManager.getKeyboardManager()._current.id;
  456. this.initLay = Object.keys(KeyboardManager.getKeyboardManager()._layoutInfos);
  457. if (this.initLay == undefined || this.init == undefined) {
  458. this.open();
  459. return;
  460. }
  461. let newLay = this.initLay;
  462. if (!newLay.includes(["us", "fr+azerty", "us+dvorak", "de+dsb_qwertz"][this.settings.get_int("lang")])) {
  463. newLay.push(["us", "fr+azerty", "us+dvorak", "de+dsb_qwertz"][this.settings.get_int("lang")]);
  464. KeyboardManager.getKeyboardManager().setUserLayouts(newLay);
  465. }
  466. KeyboardManager.getKeyboardManager().apply(["us", "fr+azerty", "us+dvorak", "de+dsb_qwertz"][this.settings.get_int("lang")]);
  467. KeyboardManager.getKeyboardManager().reapply();
  468. this.state = "opening"
  469. this.box.opacity = 0;
  470. this.show();
  471. this.box.ease({
  472. opacity: 255,
  473. duration: 100,
  474. mode: Clutter.AnimationMode.EASE_OUT_QUAD,
  475. onComplete: () => {
  476. if (this.stateTimeout !== null) {
  477. clearTimeout(this.stateTimeout);
  478. this.stateTimeout = null;
  479. }
  480. this.stateTimeout = setTimeout(() => {
  481. this.state = "opened"
  482. }, 500);
  483. let monitor = Main.layoutManager.primaryMonitor;
  484. let posX = [25, ((monitor.width * .5) - ((this.width * .5))), monitor.width - this.width - 25][(this.settings.get_int("default-snap") % 3)];
  485. let posY = [25, ((monitor.height * .5) - ((this.height * .5))), monitor.height - this.height - 25][Math.floor((this.settings.get_int("default-snap") / 3))];
  486. this.set_translation(posX, posY, 0);
  487. }
  488. });
  489. this.opened = true;
  490. }, 200);
  491. }
  492. close() {
  493. if (this.initLay !== undefined && this.init !== undefined) {
  494. KeyboardManager.getKeyboardManager().setUserLayouts(this.initLay);
  495. KeyboardManager.getKeyboardManager().apply(this.init);
  496. }
  497. let monitor = Main.layoutManager.primaryMonitor;
  498. let posX = [25, ((monitor.width * .5) - ((this.width * .5))), monitor.width - this.width - 25][(this.settings.get_int("default-snap") % 3)];
  499. let posY = [25, ((monitor.height * .5) - ((this.height * .5))), monitor.height - this.height - 25][Math.floor((this.settings.get_int("default-snap") / 3))];
  500. this.state = "closing"
  501. this.box.ease({
  502. opacity: 0,
  503. duration: 100,
  504. mode: Clutter.AnimationMode.EASE_OUT_QUAD,
  505. onComplete: () => {
  506. this.set_translation(0, 0, 0);
  507. this.set_translation(posX, posY, 0);
  508. this.opened = false;
  509. this.hide();
  510. if (this.stateTimeout !== null) {
  511. clearTimeout(this.stateTimeout);
  512. this.stateTimeout = null;
  513. }
  514. this.stateTimeout = setTimeout(() => {
  515. this.state = "closed"
  516. }, 500);
  517. },
  518. });
  519. this.openedFromButton = false
  520. }
  521. buildUI() {
  522. this.keys = [];
  523. let monitor = Main.layoutManager.primaryMonitor
  524. var topRowWidth = Math.round(((monitor.width - 90) * this.widthPercent) / 15);
  525. var topRowHeight = Math.round(((monitor.height - 190) * this.heightPercent) / 6);
  526. let row1 = new St.BoxLayout({
  527. pack_start: true
  528. });
  529. for (var num in keycodes.row1) {
  530. const i = keycodes.row1[num]
  531. var w = topRowWidth;
  532. row1.add_child(new St.Button({
  533. label: i.lowerName,
  534. height: topRowHeight,
  535. width: w
  536. }));
  537. var isMod = false;
  538. for (var j of [42, 54, 29, 125, 56, 100, 97, 58]) {
  539. if (i.code == j) {
  540. isMod = true;
  541. break;
  542. }
  543. }
  544. row1.get_children()[num].char = i;
  545. if (!isMod) {
  546. row1.get_children()[num].connect("clicked", () => this.decideMod(i))
  547. } else {
  548. const modButton = row1.get_children()[num];
  549. row1.get_children()[num].connect("clicked", () => this.decideMod(i, modButton))
  550. }
  551. }
  552. this.keys.push.apply(this.keys, row1.get_children());
  553. row1.add_style_class_name("keysHolder");
  554. let row2 = new St.BoxLayout({
  555. pack_start: true
  556. });
  557. for (var num in keycodes.row2) {
  558. const i = keycodes.row2[num]
  559. var w;
  560. if (num == 0) {
  561. w = ((row1.width - ((keycodes.row2.length - 2) * ((topRowWidth) + 5))) / 2) * 0.5;
  562. } else if (num == keycodes.row2.length - 1) {
  563. w = ((row1.width - ((keycodes.row2.length - 2) * ((topRowWidth) + 5))) / 2) * 1.5;
  564. } else {
  565. w = (topRowWidth) + 5;
  566. }
  567. row2.add_child(new St.Button({
  568. label: i.lowerName,
  569. height: topRowHeight + 20,
  570. width: w
  571. }));
  572. var isMod = false;
  573. for (var j of [42, 54, 29, 125, 56, 100, 97, 58]) {
  574. if (i.code == j) {
  575. isMod = true;
  576. break;
  577. }
  578. }
  579. row2.get_children()[num].char = i;
  580. if (!isMod) {
  581. row2.get_children()[num].connect("clicked", () => this.decideMod(i))
  582. } else {
  583. const modButton = row2.get_children()[num];
  584. row2.get_children()[num].connect("clicked", () => this.decideMod(i, modButton))
  585. }
  586. }
  587. this.keys.push.apply(this.keys, row2.get_children());
  588. row2.add_style_class_name("keysHolder");
  589. let row3 = new St.BoxLayout({
  590. pack_start: true
  591. });
  592. for (var num in keycodes.row3) {
  593. const i = keycodes.row3[num]
  594. var w;
  595. if (num == 0) {
  596. w = ((row1.width - ((keycodes.row3.length - 2) * ((topRowWidth) + 5))) / 2) * 1.1;
  597. } else if (num == keycodes.row3.length - 1) {
  598. w = ((row1.width - ((keycodes.row3.length - 2) * ((topRowWidth) + 5))) / 2) * 0.9;
  599. } else {
  600. w = (topRowWidth) + 5;
  601. }
  602. row3.add_child(new St.Button({
  603. label: i.lowerName,
  604. height: topRowHeight + 20,
  605. width: w
  606. }));
  607. var isMod = false;
  608. for (var j of [42, 54, 29, 125, 56, 100, 97, 58]) {
  609. if (i.code == j) {
  610. isMod = true;
  611. break;
  612. }
  613. }
  614. row3.get_children()[num].char = i;
  615. if (!isMod) {
  616. row3.get_children()[num].connect("clicked", () => this.decideMod(i))
  617. } else {
  618. const modButton = row3.get_children()[num];
  619. row3.get_children()[num].connect("clicked", () => this.decideMod(i, modButton))
  620. }
  621. }
  622. this.keys.push.apply(this.keys, row3.get_children());
  623. row3.add_style_class_name("keysHolder");
  624. let row4 = new St.BoxLayout({
  625. pack_start: true
  626. });
  627. for (var num in keycodes.row4) {
  628. const i = keycodes.row4[num]
  629. var w;
  630. if (num == 0 || num == keycodes.row4.length - 1) {
  631. w = ((row1.width - ((keycodes.row4.length - 2) * ((topRowWidth) + 5))) / 2);
  632. } else {
  633. w = (topRowWidth) + 5;
  634. }
  635. row4.add_child(new St.Button({
  636. label: i.lowerName,
  637. height: topRowHeight + 20,
  638. width: w
  639. }));
  640. var isMod = false;
  641. for (var j of [42, 54, 29, 125, 56, 100, 97, 58]) {
  642. if (i.code == j) {
  643. isMod = true;
  644. break;
  645. }
  646. }
  647. row4.get_children()[num].char = i;
  648. if (!isMod) {
  649. row4.get_children()[num].connect("clicked", () => this.decideMod(i))
  650. } else {
  651. const modButton = row4.get_children()[num];
  652. row4.get_children()[num].connect("clicked", () => this.decideMod(i, modButton))
  653. }
  654. }
  655. this.keys.push.apply(this.keys, row4.get_children());
  656. row4.add_style_class_name("keysHolder");
  657. let row5 = new St.BoxLayout({
  658. pack_start: true
  659. });
  660. for (var num in keycodes.row5) {
  661. const i = keycodes.row5[num]
  662. var w;
  663. if (num == 0 || num == keycodes.row5.length - 1) {
  664. w = ((row1.width - ((keycodes.row5.length - 2) * ((topRowWidth) + 5))) / 2);
  665. } else {
  666. w = (topRowWidth) + 5;
  667. }
  668. row5.add_child(new St.Button({
  669. label: i.lowerName,
  670. height: topRowHeight + 20,
  671. width: w
  672. }));
  673. var isMod = false;
  674. for (var j of [42, 54, 29, 125, 56, 100, 97, 58]) {
  675. if (i.code == j) {
  676. isMod = true;
  677. break;
  678. }
  679. }
  680. row5.get_children()[num].char = i;
  681. if (!isMod) {
  682. row5.get_children()[num].connect("clicked", () => this.decideMod(i))
  683. } else {
  684. const modButton = row5.get_children()[num];
  685. row5.get_children()[num].connect("clicked", () => this.decideMod(i, modButton))
  686. }
  687. }
  688. this.keys.push.apply(this.keys, row5.get_children());
  689. row5.add_style_class_name("keysHolder");
  690. let row6 = new St.BoxLayout({
  691. pack_start: true
  692. });
  693. for (var num in keycodes.row6) {
  694. const i = keycodes.row6[num]
  695. var w;
  696. if (num == 3) {
  697. w = ((row1.width - ((keycodes.row6.length + 1) * ((topRowWidth) + 5))));
  698. row6.add_child(new St.Button({
  699. label: i.lowerName,
  700. height: topRowHeight + 20,
  701. width: w
  702. }));
  703. var isMod = false;
  704. for (var j of [42, 54, 29, 125, 56, 100, 97, 58]) {
  705. if (i.code == j) {
  706. isMod = true;
  707. break;
  708. }
  709. }
  710. row6.get_children()[num].char = i;
  711. this.keys.push(row6.get_children()[num]);
  712. if (!isMod) {
  713. row6.get_children()[num].connect("clicked", () => this.decideMod(i))
  714. } else {
  715. const modButton = row6.get_children()[num];
  716. row6.get_children()[num].connect("clicked", () => this.decideMod(i, modButton))
  717. }
  718. } else if (num == keycodes.row6.length - 1) {
  719. var gbox = new St.BoxLayout({
  720. pack_start: true
  721. });
  722. var btn1 = new St.Button({
  723. label: (keycodes.row6[keycodes.row6.length - 1])[0].lowerName
  724. });
  725. gbox.add_child(btn1);
  726. var vbox = new St.BoxLayout({
  727. vertical: true
  728. });
  729. var btn2 = new St.Button({
  730. label: (keycodes.row6[keycodes.row6.length - 1])[1].lowerName
  731. });
  732. var btn3 = new St.Button({
  733. label: (keycodes.row6[keycodes.row6.length - 1])[2].lowerName
  734. });
  735. vbox.add_child(btn2);
  736. vbox.add_child(btn3);
  737. gbox.add_child(vbox);
  738. var btn4 = new St.Button({
  739. label: (keycodes.row6[keycodes.row6.length - 1])[3].lowerName
  740. });
  741. gbox.add_child(btn4);
  742. var btn5 = new St.Button();
  743. btn5.add_style_class_name("move_btn")
  744. var btn6 = new St.Button();
  745. btn6.add_style_class_name("close_btn")
  746. if (this.settings.get_boolean("enable-drag")) {
  747. gbox.add_child(btn5);
  748. }
  749. gbox.add_child(btn6);
  750. btn1.connect("clicked", () => this.decideMod((keycodes.row6[keycodes.row6.length - 1])[0]))
  751. btn2.connect("clicked", () => this.decideMod((keycodes.row6[keycodes.row6.length - 1])[1]))
  752. btn3.connect("clicked", () => this.decideMod((keycodes.row6[keycodes.row6.length - 1])[2]))
  753. btn4.connect("clicked", () => this.decideMod((keycodes.row6[keycodes.row6.length - 1])[3]))
  754. btn5.connect("clicked", () => {
  755. if (this.settings.get_boolean("enable-drag")) {
  756. this.draggable = !this.draggable;
  757. this.keys.forEach(keyholder => {
  758. if (!keyholder.has_style_class_name("move_btn")) {
  759. keyholder.set_opacity(this.draggable ? 255 : 0);
  760. keyholder.ease({
  761. opacity: this.draggable ? 0 : 255,
  762. duration: 100,
  763. mode: Clutter.AnimationMode.EASE_OUT_QUAD,
  764. onComplete: () => {
  765. keyholder.set_z_position(this.draggable ? -10000000000000000000000000000 : 0);
  766. if (this.draggable) {
  767. this.box.add_style_pseudo_class("dragging");
  768. } else {
  769. this.box.remove_style_pseudo_class("dragging");
  770. }
  771. }
  772. });
  773. }
  774. });
  775. btn5.ease({
  776. width: btn5.width * (this.draggable ? 2 : 0.5),
  777. duration: 100,
  778. mode: Clutter.AnimationMode.EASE_OUT_QUAD,
  779. onComplete: () => {}
  780. })
  781. btn6.ease({
  782. width: this.draggable ? 0 : btn5.width / 2,
  783. duration: 100,
  784. mode: Clutter.AnimationMode.EASE_OUT_QUAD,
  785. onComplete: () => {}
  786. })
  787. }
  788. })
  789. btn6.connect("clicked", () => { this.close(); this.closedFromButton = true; });
  790. btn1.char = (keycodes.row6[keycodes.row6.length - 1])[0]
  791. btn2.char = (keycodes.row6[keycodes.row6.length - 1])[1]
  792. btn3.char = (keycodes.row6[keycodes.row6.length - 1])[2]
  793. btn4.char = (keycodes.row6[keycodes.row6.length - 1])[3]
  794. btn1.width = Math.round((((topRowWidth) + 5)) * (2 / 3));
  795. btn1.height = topRowHeight + 20;
  796. btn2.width = Math.round((((topRowWidth) + 5)) * (2 / 3));
  797. btn3.width = Math.round((((topRowWidth) + 5)) * (2 / 3));
  798. btn4.width = Math.round((((topRowWidth) + 5)) * (2 / 3));
  799. btn4.height = topRowHeight + 20;
  800. btn2.height = (topRowHeight + 20) / 2;
  801. btn3.height = (topRowHeight + 20) / 2;
  802. btn5.width = Math.round((topRowWidth / 2) + 2);
  803. btn6.width = this.settings.get_boolean("enable-drag") ? Math.round((topRowWidth / 2) + 2) : Math.round((topRowWidth) + 4);
  804. btn5.height = topRowHeight + 20;
  805. btn6.height = topRowHeight + 20;
  806. btn1.add_style_class_name('dr-b');
  807. btn2.add_style_class_name('dr-b');
  808. btn3.add_style_class_name('dr-b');
  809. btn4.add_style_class_name('dr-b');
  810. btn5.add_style_class_name('dr-b');
  811. btn6.add_style_class_name('dr-b');
  812. this.keys.push.apply(this.keys, [btn1, btn2, btn3, btn4, btn5, btn6]);
  813. gbox.add_style_class_name('keyActionBtns');
  814. row6.add_child(gbox);
  815. } else {
  816. w = (topRowWidth) + 5;
  817. row6.add_child(new St.Button({
  818. label: i.lowerName,
  819. height: topRowHeight + 20,
  820. width: w
  821. }));
  822. var isMod = false;
  823. for (var j of [42, 54, 29, 125, 56, 100, 97, 58]) {
  824. if (i.code == j) {
  825. isMod = true;
  826. break;
  827. }
  828. }
  829. row6.get_children()[num].char = i;
  830. this.keys.push(row6.get_children()[num]);
  831. if (!isMod) {
  832. row6.get_children()[num].connect("clicked", () => this.decideMod(i))
  833. } else {
  834. const modButton = row6.get_children()[num];
  835. row6.get_children()[num].connect("clicked", () => this.decideMod(i, modButton))
  836. }
  837. }
  838. }
  839. row6.add_style_class_name("keysHolder");
  840. this.box.add_child(row1);
  841. this.box.add_child(row2);
  842. this.box.add_child(row3);
  843. this.box.add_child(row4);
  844. this.box.add_child(row5);
  845. this.box.add_child(row6);
  846. var containers_ = this.box.get_children();
  847. if (this.lightOrDark(this.settings.get_double("background-r"), this.settings.get_double("background-g"), this.settings.get_double("background-b"))) {
  848. this.box.add_style_class_name("inverted");
  849. } else {
  850. this.box.add_style_class_name("regular");
  851. }
  852. this.keys.forEach(item => {
  853. item.width -= this.settings.get_int("border-spacing-px") * 2;
  854. item.height -= this.settings.get_int("border-spacing-px") * 2;
  855. item.set_style("margin: " + this.settings.get_int("border-spacing-px") + "px; 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;");
  856. if (this.lightOrDark(this.settings.get_double("background-r"), this.settings.get_double("background-g"), this.settings.get_double("background-b"))) {
  857. item.add_style_class_name("inverted");
  858. } else {
  859. item.add_style_class_name("regular");
  860. }
  861. let isMod = false
  862. for (var j of [42, 54, 29, 125, 56, 100, 97, 58]) {
  863. try {
  864. if (item.char.code == j) {
  865. isMod = true;
  866. break;
  867. }
  868. } catch {
  869. print(item)
  870. }
  871. }
  872. item.set_pivot_point(0.5, 0.5)
  873. item.connect("destroy", () => {
  874. if (item.button_pressed !== null){
  875. clearTimeout(item.button_pressed)
  876. item.button_pressed == null
  877. }
  878. if (item.button_repeat !== null){
  879. clearInterval(item.button_repeat)
  880. item.button_repeat == null
  881. }
  882. if (item.tap_pressed !== null){
  883. clearTimeout(item.tap_pressed)
  884. item.tap_pressed == null
  885. }
  886. if (item.tap_repeat !== null){
  887. clearInterval(item.tap_repeat)
  888. item.tap_repeat == null
  889. }
  890. })
  891. item.connect("button-press-event", () => {
  892. item.set_scale(1.2, 1.2)
  893. let player
  894. if (this.settings.get_boolean("play-sound")) {
  895. player = global.display.get_sound_player();
  896. player.play_from_theme("dialog-information", "tap", null)
  897. }
  898. item.button_pressed = setTimeout(() => {
  899. if (!isMod) {
  900. const oldModBtns = this.modBtns
  901. item.button_repeat = setInterval(() => {
  902. if (this.settings.get_boolean("play-sound")) {
  903. player.play_from_theme("dialog-information", "tap", null)
  904. }
  905. this.decideMod(item.char)
  906. for (var i of oldModBtns) {
  907. this.decideMod(i.char, i)
  908. }
  909. }, 100);
  910. }
  911. }, 750);
  912. })
  913. item.connect("button-release-event", () => {
  914. item.ease({
  915. scale_x: 1,
  916. scale_y: 1,
  917. duration: 100,
  918. mode: Clutter.AnimationMode.EASE_OUT_QUAD,
  919. onComplete: () => {item.set_scale(1, 1)}
  920. })
  921. if (item.button_pressed !== null){
  922. clearTimeout(item.button_pressed)
  923. item.button_pressed == null
  924. }
  925. if (item.button_repeat !== null){
  926. clearInterval(item.button_repeat)
  927. item.button_repeat == null
  928. }
  929. })
  930. item.connect("touch-event", () => {
  931. if (Clutter.get_current_event().type() == Clutter.EventType.TOUCH_BEGIN) {
  932. item.set_scale(1.2, 1.2)
  933. let player
  934. if (this.settings.get_boolean("play-sound")) {
  935. player = global.display.get_sound_player();
  936. player.play_from_theme("dialog-information", "tap", null)
  937. }
  938. item.tap_pressed = setTimeout(() => {
  939. if (!isMod) {
  940. const oldModBtns = this.modBtns
  941. item.tap_repeat = setInterval(() => {
  942. if (this.settings.get_boolean("play-sound")) {
  943. player.play_from_theme("dialog-information", "tap", null)
  944. }
  945. this.decideMod(item.char)
  946. for (var i of oldModBtns) {
  947. this.decideMod(i.char, i)
  948. }
  949. }, 100);
  950. }
  951. }, 750);
  952. } else if (Clutter.get_current_event().type() == Clutter.EventType.TOUCH_END) {
  953. item.ease({
  954. scale_x: 1,
  955. scale_y: 1,
  956. duration: 100,
  957. mode: Clutter.AnimationMode.EASE_OUT_QUAD,
  958. onComplete: () => {item.set_scale(1, 1)}
  959. })
  960. if (item.tap_pressed !== null){
  961. clearTimeout(item.tap_pressed)
  962. item.tap_pressed == null
  963. }
  964. if (item.tap_repeat !== null){
  965. clearInterval(item.tap_repeat)
  966. item.tap_repeat == null
  967. }
  968. }
  969. })
  970. });
  971. }
  972. lightOrDark(r, g, b) {
  973. var hsp;
  974. hsp = Math.sqrt(
  975. 0.299 * (r * r) +
  976. 0.587 * (g * g) +
  977. 0.114 * (b * b)
  978. );
  979. if (hsp > 127.5) {
  980. return true;
  981. } else {
  982. return false;
  983. }
  984. }
  985. sendKey(keys) {
  986. try {
  987. for (var i = 0; i < keys.length; i++) {
  988. this.inputDevice.notify_key(Clutter.get_current_event_time(), keys[i], Clutter.KeyState.PRESSED);
  989. }
  990. if (this.keyTimeout !== null) {
  991. clearTimeout(this.keyTimeout);
  992. this.keyTimeout = null;
  993. }
  994. this.keyTimeout = setTimeout(() => {
  995. for (var j = keys.length - 1; j >= 0; j--) {
  996. this.inputDevice.notify_key(Clutter.get_current_event_time(), keys[j], Clutter.KeyState.RELEASED);
  997. }
  998. }, 100);
  999. } catch (err) {
  1000. let source = new imports.ui.messageTray.SystemNotificationSource();
  1001. source.connect('destroy', () => {
  1002. source = null;
  1003. })
  1004. Main.messageTray.add(source);
  1005. let notification = new imports.ui.messageTray.Notification(source, "GJS-OSK: An unknown error occured", "Please report this bug to the Issues page:\n\n" + err + "\n\nKeys Pressed: " + keys)
  1006. notification.setTransient(false);
  1007. notification.setResident(false);
  1008. source.showNotification(notification);
  1009. notification.connect("activated", () => {
  1010. sendCommand("xdg-open https://github.com/Vishram1123/gjs-osk/issues");
  1011. });
  1012. }
  1013. }
  1014. sendCommand(command_line) {
  1015. try {
  1016. let [success, argv] = GLib.shell_parse_argv(command_line);
  1017. trySpawn(argv);
  1018. } catch (err) {
  1019. let source = new imports.ui.messageTray.SystemNotificationSource();
  1020. source.connect('destroy', () => {
  1021. source = null;
  1022. })
  1023. Main.messageTray.add(source);
  1024. let notification = new imports.ui.messageTray.Notification(source, "GJS-OSK: An unknown error occured", "Please report this bug to the Issues page:\n\n" + err)
  1025. notification.setTransient(false);
  1026. notification.setResident(false);
  1027. source.showNotification(notification);
  1028. }
  1029. }
  1030. decideMod(i, mBtn) {
  1031. if (i.code == 29 || i.code == 97 || i.code == 125) {
  1032. this.setNormMod(mBtn);
  1033. } else if (i.code == 56 || i.code == 100) {
  1034. this.setAlt(mBtn);
  1035. } else if (i.code == 42 || i.code == 54) {
  1036. this.setShift(mBtn);
  1037. } else if (i.code == 58) {
  1038. this.setCapsLock(mBtn);
  1039. } else {
  1040. this.mod.push(i.code);
  1041. this.sendKey(this.mod);
  1042. this.mod = [];
  1043. this.modBtns.forEach(button => {
  1044. button.remove_style_class_name("selected");
  1045. });
  1046. this.resetAllMod();
  1047. this.modBtns = [];
  1048. }
  1049. }
  1050. setCapsLock(button) {
  1051. if (!this.capsL) {
  1052. button.add_style_class_name("selected");
  1053. this.capsL = true;
  1054. this.keys.forEach(key => {
  1055. if (this.shift && key.char != undefined) {
  1056. if (key.char.letter == "primary") {
  1057. key.label = key.label.toLowerCase();
  1058. } else if (key.char.letter == "pseudo") {
  1059. key.label = key.char.upperName;
  1060. } else if (key.char.letter == undefined) {
  1061. key.label = key.char.upperName;
  1062. }
  1063. } else if (key.char != undefined && key.char.letter != undefined) {
  1064. key.label = key.label.toUpperCase();
  1065. }
  1066. });
  1067. } else {
  1068. button.remove_style_class_name("selected");
  1069. this.capsL = false;
  1070. this.keys.forEach(key => {
  1071. if (this.shift && key.char != undefined) {
  1072. if (key.char.letter == "primary") {
  1073. key.label = key.label.toUpperCase();
  1074. } else if (key.char.letter == "pseudo") {
  1075. key.label = key.char.upperName;
  1076. } else if (key.char.letter == undefined) {
  1077. key.label = key.char.upperName;
  1078. }
  1079. } else if (key.char != undefined && key.char.letter != undefined) {
  1080. key.label = key.label.toLowerCase();
  1081. }
  1082. });
  1083. }
  1084. this.sendKey([button.char.code]);
  1085. }
  1086. setAlt(button) {
  1087. if (!this.alt) {
  1088. this.alt = true;
  1089. this.keys.forEach(key => {
  1090. if (!this.shift && key.char != undefined) {
  1091. if (key.char.altName != "") {
  1092. key.label = key.char.altName;
  1093. }
  1094. }
  1095. });
  1096. } else {
  1097. this.alt = false;
  1098. this.keys.forEach(key => {
  1099. if (!this.shift && key.char != undefined) {
  1100. if (key.char.altName != "" && this.capsL && (key.char.letter == "primary" || key.char.letter == "pseudo")) {
  1101. key.label = key.char.lowerName.toUpperCase();
  1102. } else if (key.char.altName != "" && this.capsL) {
  1103. key.label = key.char.lowerName;
  1104. } else if (key.char.altName != "" && !this.capsL) {
  1105. key.label = key.char.lowerName;
  1106. }
  1107. }
  1108. });
  1109. this.sendKey([button.char.code]);
  1110. }
  1111. this.setNormMod(button);
  1112. }
  1113. setShift(button) {
  1114. if (!this.shift) {
  1115. this.shift = true;
  1116. this.keys.forEach(key => {
  1117. if (this.capsL && key.char != undefined) {
  1118. if (key.char.letter == "primary") {
  1119. key.label = key.char.lowerName.toLowerCase();
  1120. } else if (key.char.letter == "pseudo" || key.char.letter == undefined) {
  1121. key.label = key.char.upperName;
  1122. }
  1123. } else if (key.char != undefined) {
  1124. key.label = key.char.upperName;
  1125. }
  1126. });
  1127. } else {
  1128. this.shift = false;
  1129. this.keys.forEach(key => {
  1130. if (this.capsL && key.char != undefined) {
  1131. if (this.alt && key.char.altName != "") {
  1132. key.label = key.char.altName;
  1133. } else if (key.char.letter != undefined) {
  1134. key.label = key.char.lowerName.toUpperCase();
  1135. } else if (key.char.letter == undefined) {
  1136. key.label = key.char.lowerName;
  1137. }
  1138. } else if (key.char != undefined) {
  1139. if (this.alt && key.char.altName != "") {
  1140. key.label = key.char.altName;
  1141. } else {
  1142. key.label = key.char.lowerName;
  1143. }
  1144. }
  1145. });
  1146. this.sendKey([button.char.code]);
  1147. }
  1148. this.setNormMod(button);
  1149. }
  1150. setNormMod(button) {
  1151. if (this.mod.includes(button.char.code)) {
  1152. this.mod.splice(this.mod.indexOf(button.char.code), this.mod.indexOf(button.char.code) + 1);
  1153. button.remove_style_class_name("selected");
  1154. this.modBtns.splice(this.modBtns.indexOf(button), this.modBtns.indexOf(button) + 1);
  1155. this.sendKey([button.char.code]);
  1156. } else {
  1157. button.add_style_class_name("selected");
  1158. this.mod.push(button.char.code);
  1159. this.modBtns.push(button);
  1160. }
  1161. }
  1162. resetAllMod() {
  1163. if (this.shift) {
  1164. this.shift = false;
  1165. this.keys.forEach(key => {
  1166. if (this.capsL && key.char != undefined) {
  1167. if (this.alt && key.char.altName != "") {
  1168. key.label = key.char.altName;
  1169. } else if (key.char.letter != undefined) {
  1170. key.label = key.char.lowerName.toUpperCase();
  1171. } else if (key.char.letter == undefined) {
  1172. key.label = key.char.lowerName;
  1173. }
  1174. } else if (key.char != undefined) {
  1175. if (this.alt && key.char.altName != "") {
  1176. key.label = key.char.altName;
  1177. } else {
  1178. key.label = key.char.lowerName;
  1179. }
  1180. }
  1181. });
  1182. }
  1183. if (this.alt) {
  1184. this.alt = false;
  1185. this.keys.forEach(key => {
  1186. if (!this.shift && key.char != undefined) {
  1187. if (key.char.altName != "" && this.capsL && (key.char.letter == "primary" || key.char.letter == "pseudo")) {
  1188. key.label = key.char.lowerName.toUpperCase();
  1189. } else if (key.char.altName != "" && this.capsL) {
  1190. key.label = key.char.lowerName;
  1191. } else if (key.char.altName != "" && !this.capsL) {
  1192. key.label = key.char.lowerName;
  1193. }
  1194. }
  1195. });
  1196. }
  1197. }
  1198. };