2014-02-14 15:11:28 +00:00
|
|
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
|
|
|
|
2023-07-10 09:53:00 +00:00
|
|
|
import GLib from 'gi://GLib';
|
|
|
|
import GnomeDesktop from 'gi://GnomeDesktop';
|
2014-02-14 15:11:28 +00:00
|
|
|
|
2023-07-10 09:53:00 +00:00
|
|
|
import * as Main from '../ui/main.js';
|
2014-02-14 15:11:28 +00:00
|
|
|
|
2023-07-10 09:53:00 +00:00
|
|
|
export const DEFAULT_LOCALE = 'en_US';
|
|
|
|
export const DEFAULT_LAYOUT = 'us';
|
|
|
|
export const DEFAULT_VARIANT = '';
|
2014-06-05 16:47:48 +00:00
|
|
|
|
2014-02-14 15:11:28 +00:00
|
|
|
let _xkbInfo = null;
|
|
|
|
|
2023-07-30 12:56:59 +00:00
|
|
|
/**
|
|
|
|
* @returns {GnomeDesktop.XkbInfo}
|
|
|
|
*/
|
2023-07-10 09:53:00 +00:00
|
|
|
export function getXkbInfo() {
|
2014-02-14 15:11:28 +00:00
|
|
|
if (_xkbInfo == null)
|
|
|
|
_xkbInfo = new GnomeDesktop.XkbInfo();
|
|
|
|
return _xkbInfo;
|
|
|
|
}
|
|
|
|
|
|
|
|
let _keyboardManager = null;
|
|
|
|
|
2023-07-30 12:56:59 +00:00
|
|
|
/**
|
|
|
|
* @returns {KeyboardManager}
|
|
|
|
*/
|
2023-07-10 09:53:00 +00:00
|
|
|
export function getKeyboardManager() {
|
2014-02-14 15:11:28 +00:00
|
|
|
if (_keyboardManager == null)
|
|
|
|
_keyboardManager = new KeyboardManager();
|
|
|
|
return _keyboardManager;
|
|
|
|
}
|
|
|
|
|
2023-07-10 09:53:00 +00:00
|
|
|
export function releaseKeyboard() {
|
2014-02-14 15:11:28 +00:00
|
|
|
if (Main.modalCount > 0)
|
|
|
|
global.display.unfreeze_keyboard(global.get_current_time());
|
|
|
|
else
|
|
|
|
global.display.ungrab_keyboard(global.get_current_time());
|
|
|
|
}
|
|
|
|
|
2023-07-10 09:53:00 +00:00
|
|
|
export function holdKeyboard() {
|
2014-10-13 04:52:56 +00:00
|
|
|
global.display.freeze_keyboard(global.get_current_time());
|
2014-02-14 15:11:28 +00:00
|
|
|
}
|
|
|
|
|
2023-07-10 09:53:00 +00:00
|
|
|
class KeyboardManager {
|
2017-10-31 01:19:44 +00:00
|
|
|
constructor() {
|
|
|
|
// The XKB protocol doesn't allow for more that 4 layouts in a
|
|
|
|
// keymap. Wayland doesn't impose this limit and libxkbcommon can
|
|
|
|
// handle up to 32 layouts but since we need to support X clients
|
|
|
|
// even as a Wayland compositor, we can't bump this.
|
|
|
|
this.MAX_LAYOUTS_PER_GROUP = 4;
|
2014-02-14 15:11:28 +00:00
|
|
|
|
2014-06-05 16:47:48 +00:00
|
|
|
this._xkbInfo = getXkbInfo();
|
|
|
|
this._current = null;
|
|
|
|
this._localeLayoutInfo = this._getLocaleLayout();
|
|
|
|
this._layoutInfos = {};
|
2018-10-22 22:06:36 +00:00
|
|
|
this._currentKeymap = null;
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2014-02-14 15:11:28 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_applyLayoutGroup(group) {
|
2014-06-05 16:47:48 +00:00
|
|
|
let options = this._buildOptionsString();
|
|
|
|
let [layouts, variants] = this._buildGroupStrings(group);
|
2018-10-22 22:06:36 +00:00
|
|
|
|
|
|
|
if (this._currentKeymap &&
|
|
|
|
this._currentKeymap.layouts == layouts &&
|
|
|
|
this._currentKeymap.variants == variants &&
|
|
|
|
this._currentKeymap.options == options)
|
|
|
|
return;
|
|
|
|
|
2019-01-29 01:27:05 +00:00
|
|
|
this._currentKeymap = { layouts, variants, options };
|
2020-04-21 16:04:56 +00:00
|
|
|
global.backend.set_keymap(layouts, variants, options);
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2014-02-14 15:11:28 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_applyLayoutGroupIndex(idx) {
|
2020-04-21 16:04:56 +00:00
|
|
|
global.backend.lock_layout_group(idx);
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2014-06-05 16:47:48 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
apply(id) {
|
2014-06-05 16:47:48 +00:00
|
|
|
let info = this._layoutInfos[id];
|
|
|
|
if (!info)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (this._current && this._current.group == info.group) {
|
|
|
|
if (this._current.groupIndex != info.groupIndex)
|
|
|
|
this._applyLayoutGroupIndex(info.groupIndex);
|
|
|
|
} else {
|
|
|
|
this._applyLayoutGroup(info.group);
|
|
|
|
this._applyLayoutGroupIndex(info.groupIndex);
|
|
|
|
}
|
|
|
|
|
|
|
|
this._current = info;
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2014-06-05 16:47:48 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
reapply() {
|
2014-06-05 16:47:48 +00:00
|
|
|
if (!this._current)
|
|
|
|
return;
|
|
|
|
|
|
|
|
this._applyLayoutGroup(this._current.group);
|
|
|
|
this._applyLayoutGroupIndex(this._current.groupIndex);
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2014-06-05 16:47:48 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
setUserLayouts(ids) {
|
2014-06-05 16:47:48 +00:00
|
|
|
this._current = null;
|
|
|
|
this._layoutInfos = {};
|
|
|
|
|
|
|
|
for (let i = 0; i < ids.length; ++i) {
|
|
|
|
let [found, , , _layout, _variant] = this._xkbInfo.get_layout_info(ids[i]);
|
|
|
|
if (found)
|
|
|
|
this._layoutInfos[ids[i]] = { id: ids[i], layout: _layout, variant: _variant };
|
|
|
|
}
|
|
|
|
|
|
|
|
let i = 0;
|
|
|
|
let group = [];
|
|
|
|
for (let id in this._layoutInfos) {
|
|
|
|
// We need to leave one slot on each group free so that we
|
|
|
|
// can add a layout containing the symbols for the
|
|
|
|
// language used in UI strings to ensure that toolkits can
|
|
|
|
// handle mnemonics like Alt+Ф even if the user is
|
|
|
|
// actually typing in a different layout.
|
|
|
|
let groupIndex = i % (this.MAX_LAYOUTS_PER_GROUP - 1);
|
|
|
|
if (groupIndex == 0)
|
|
|
|
group = [];
|
|
|
|
|
|
|
|
let info = this._layoutInfos[id];
|
|
|
|
group[groupIndex] = info;
|
|
|
|
info.group = group;
|
|
|
|
info.groupIndex = groupIndex;
|
|
|
|
|
|
|
|
i += 1;
|
|
|
|
}
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2014-06-05 16:47:48 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_getLocaleLayout() {
|
2014-06-05 16:47:48 +00:00
|
|
|
let locale = GLib.get_language_names()[0];
|
2018-07-14 20:56:22 +00:00
|
|
|
if (!locale.includes('_'))
|
2014-06-05 16:47:48 +00:00
|
|
|
locale = DEFAULT_LOCALE;
|
|
|
|
|
|
|
|
let [found, , id] = GnomeDesktop.get_input_source_from_locale(locale);
|
|
|
|
if (!found)
|
|
|
|
[, , id] = GnomeDesktop.get_input_source_from_locale(DEFAULT_LOCALE);
|
|
|
|
|
2017-02-10 02:12:59 +00:00
|
|
|
let _layout, _variant;
|
|
|
|
[found, , , _layout, _variant] = this._xkbInfo.get_layout_info(id);
|
2014-06-05 16:47:48 +00:00
|
|
|
if (found)
|
|
|
|
return { layout: _layout, variant: _variant };
|
|
|
|
else
|
|
|
|
return { layout: DEFAULT_LAYOUT, variant: DEFAULT_VARIANT };
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2014-06-05 16:47:48 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_buildGroupStrings(_group) {
|
2014-06-05 16:47:48 +00:00
|
|
|
let group = _group.concat(this._localeLayoutInfo);
|
2017-10-31 00:38:18 +00:00
|
|
|
let layouts = group.map(g => g.layout).join(',');
|
|
|
|
let variants = group.map(g => g.variant).join(',');
|
2014-06-05 16:47:48 +00:00
|
|
|
return [layouts, variants];
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2014-06-05 16:47:48 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
setKeyboardOptions(options) {
|
2014-06-05 16:47:48 +00:00
|
|
|
this._xkbOptions = options;
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2014-02-14 15:11:28 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_buildOptionsString() {
|
2014-06-05 16:47:48 +00:00
|
|
|
let options = this._xkbOptions.join(',');
|
|
|
|
return options;
|
2014-02-14 15:11:28 +00:00
|
|
|
}
|
2021-03-15 06:50:31 +00:00
|
|
|
|
|
|
|
get currentLayout() {
|
|
|
|
return this._current;
|
|
|
|
}
|
2023-07-10 09:53:00 +00:00
|
|
|
}
|