keyboard: Rework OSK
Caribou is no longer used to load keyboard layouts, gnome-shell uses the JSON files extracted from Unicode CLDR instead.
This commit is contained in:
parent
33c3ed68fd
commit
7fd8fa3478
@ -1506,27 +1506,18 @@ StScrollBar {
|
|||||||
#keyboard {
|
#keyboard {
|
||||||
background-color: rgba(46, 52, 54, 0.7); }
|
background-color: rgba(46, 52, 54, 0.7); }
|
||||||
|
|
||||||
.keyboard-layout {
|
.key-container {
|
||||||
spacing: 10px;
|
padding: 4px;
|
||||||
padding: 10px; }
|
spacing: 4px; }
|
||||||
|
|
||||||
.keyboard-row {
|
|
||||||
spacing: 15px; }
|
|
||||||
|
|
||||||
.keyboard-key {
|
.keyboard-key {
|
||||||
color: #eeeeec;
|
background-color: #393f3f;
|
||||||
background-color: #2e3436;
|
|
||||||
border-color: rgba(0, 0, 0, 0.7);
|
|
||||||
box-shadow: inset 0 1px #454f52;
|
|
||||||
text-shadow: 0 1px black;
|
|
||||||
icon-shadow: 0 1px black;
|
|
||||||
min-height: 2em;
|
min-height: 2em;
|
||||||
min-width: 2em;
|
min-width: 2em;
|
||||||
font-size: 14pt;
|
font-size: 14pt;
|
||||||
font-weight: bold;
|
border-radius: 3px;
|
||||||
border-radius: 5px;
|
border: 1px solid #464d4d;
|
||||||
border: 1px solid black;
|
color: #e5e5e5; }
|
||||||
color: white; }
|
|
||||||
.keyboard-key:focus {
|
.keyboard-key:focus {
|
||||||
color: #eeeeec;
|
color: #eeeeec;
|
||||||
text-shadow: 0 1px black;
|
text-shadow: 0 1px black;
|
||||||
@ -1550,6 +1541,12 @@ StScrollBar {
|
|||||||
background-color: #2e3436;
|
background-color: #2e3436;
|
||||||
color: #eeeeec;
|
color: #eeeeec;
|
||||||
border-color: rgba(0, 0, 0, 0.7); }
|
border-color: rgba(0, 0, 0, 0.7); }
|
||||||
|
.keyboard-key.default-key {
|
||||||
|
border-color: #2d3232;
|
||||||
|
background-color: #1d2020; }
|
||||||
|
.keyboard-key.enter-key {
|
||||||
|
border-color: #005684;
|
||||||
|
background-color: #006098; }
|
||||||
|
|
||||||
.keyboard-subkeys {
|
.keyboard-subkeys {
|
||||||
color: white;
|
color: white;
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit 57a2e5bfe179d9db1e05c3edaffdcb3fee307be0
|
Subproject commit 08973e0e16de468bc7a1cc1085f2e17153b74609
|
@ -1506,27 +1506,18 @@ StScrollBar {
|
|||||||
#keyboard {
|
#keyboard {
|
||||||
background-color: rgba(46, 52, 54, 0.7); }
|
background-color: rgba(46, 52, 54, 0.7); }
|
||||||
|
|
||||||
.keyboard-layout {
|
.key-container {
|
||||||
spacing: 10px;
|
padding: 4px;
|
||||||
padding: 10px; }
|
spacing: 4px; }
|
||||||
|
|
||||||
.keyboard-row {
|
|
||||||
spacing: 15px; }
|
|
||||||
|
|
||||||
.keyboard-key {
|
.keyboard-key {
|
||||||
color: #eeeeec;
|
background-color: #393f3f;
|
||||||
background-color: #2e3436;
|
|
||||||
border-color: rgba(0, 0, 0, 0.7);
|
|
||||||
box-shadow: inset 0 1px #454f52;
|
|
||||||
text-shadow: 0 1px black;
|
|
||||||
icon-shadow: 0 1px black;
|
|
||||||
min-height: 2em;
|
min-height: 2em;
|
||||||
min-width: 2em;
|
min-width: 2em;
|
||||||
font-size: 14pt;
|
font-size: 14pt;
|
||||||
font-weight: bold;
|
border-radius: 3px;
|
||||||
border-radius: 5px;
|
border: 1px solid #464d4d;
|
||||||
border: 1px solid #1c1f1f;
|
color: #e5e5e5; }
|
||||||
color: white; }
|
|
||||||
.keyboard-key:focus {
|
.keyboard-key:focus {
|
||||||
color: #eeeeec;
|
color: #eeeeec;
|
||||||
text-shadow: 0 1px black;
|
text-shadow: 0 1px black;
|
||||||
@ -1550,6 +1541,12 @@ StScrollBar {
|
|||||||
background-color: #2e3436;
|
background-color: #2e3436;
|
||||||
color: #eeeeec;
|
color: #eeeeec;
|
||||||
border-color: rgba(0, 0, 0, 0.7); }
|
border-color: rgba(0, 0, 0, 0.7); }
|
||||||
|
.keyboard-key.default-key {
|
||||||
|
border-color: #2d3232;
|
||||||
|
background-color: #1d2020; }
|
||||||
|
.keyboard-key.enter-key {
|
||||||
|
border-color: #005684;
|
||||||
|
background-color: #006098; }
|
||||||
|
|
||||||
.keyboard-subkeys {
|
.keyboard-subkeys {
|
||||||
color: white;
|
color: white;
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
const FocusCaretTracker = imports.ui.focusCaretTracker;
|
const FocusCaretTracker = imports.ui.focusCaretTracker;
|
||||||
const Atspi = imports.gi.Atspi;
|
const Atspi = imports.gi.Atspi;
|
||||||
const Caribou = imports.gi.Caribou;
|
|
||||||
const Clutter = imports.gi.Clutter;
|
const Clutter = imports.gi.Clutter;
|
||||||
const Gdk = imports.gi.Gdk;
|
const Gdk = imports.gi.Gdk;
|
||||||
const Gio = imports.gi.Gio;
|
const Gio = imports.gi.Gio;
|
||||||
@ -19,40 +18,54 @@ const Layout = imports.ui.layout;
|
|||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
|
|
||||||
var KEYBOARD_REST_TIME = Layout.KEYBOARD_ANIMATION_TIME * 2 * 1000;
|
var KEYBOARD_REST_TIME = Layout.KEYBOARD_ANIMATION_TIME * 2 * 1000;
|
||||||
|
var KEY_LONG_PRESS_TIME = 250;
|
||||||
const KEYBOARD_SCHEMA = 'org.gnome.shell.keyboard';
|
|
||||||
const KEYBOARD_TYPE = 'keyboard-type';
|
|
||||||
|
|
||||||
const A11Y_APPLICATIONS_SCHEMA = 'org.gnome.desktop.a11y.applications';
|
const A11Y_APPLICATIONS_SCHEMA = 'org.gnome.desktop.a11y.applications';
|
||||||
const SHOW_KEYBOARD = 'screen-keyboard-enabled';
|
const SHOW_KEYBOARD = 'screen-keyboard-enabled';
|
||||||
|
|
||||||
|
const defaultKeysPre = [
|
||||||
|
[ [], [], [{ label: '⇧', width: 1.5, level: 1 }], [{ label: '?123', width: 1.5, level: 2 }] ],
|
||||||
|
[ [], [], [{ label: '⇪', width: 1.5, level: 0 }], [{ label: '?123', width: 1.5, level: 2 }] ],
|
||||||
|
[ [], [], [{ label: '=/<', width: 1.5, level: 3 }], [{ label: 'ABC', width: 1.5, level: 0 }] ],
|
||||||
|
[ [], [], [{ label: '?123', width: 1.5, level: 2 }], [{ label: 'ABC', width: 1.5, level: 0 }] ],
|
||||||
|
];
|
||||||
|
|
||||||
|
const defaultKeysPost = [
|
||||||
|
[ [{ label: '⌫', width: 1.5, keyval: Clutter.KEY_BackSpace }],
|
||||||
|
[{ label: '⏎', width: 2, keyval: Clutter.KEY_Return, extraClassName: 'enter-key' }],
|
||||||
|
[{ label: '⇧', width: 3, level: 1, right: true }],
|
||||||
|
[{ label: '🌐', width: 1.5 }, { label: '⌨', width: 1.5, action: 'hide' }] ],
|
||||||
|
[ [{ label: '⌫', width: 1.5, keyval: Clutter.KEY_BackSpace }],
|
||||||
|
[{ label: '⏎', width: 2, keyval: Clutter.KEY_Return, extraClassName: 'enter-key' }],
|
||||||
|
[{ label: '⇪', width: 3, level: 0, right: true }],
|
||||||
|
[{ label: '🌐', width: 1.5 }, { label: '⌨', width: 1.5, action: 'hide' }] ],
|
||||||
|
[ [{ label: '⌫', width: 1.5, keyval: Clutter.KEY_BackSpace }],
|
||||||
|
[{ label: '⏎', width: 2, keyval: Clutter.KEY_Return, extraClassName: 'enter-key' }],
|
||||||
|
[{ label: '=/<', width: 3, level: 3, right: true }],
|
||||||
|
[{ label: '🌐', width: 1.5 }, { label: '⌨', width: 1.5, action: 'hide' }] ],
|
||||||
|
[ [{ label: '⌫', width: 1.5, keyval: Clutter.KEY_BackSpace }],
|
||||||
|
[{ label: '⏎', width: 2, keyval: Clutter.KEY_Return, extraClassName: 'enter-key' }],
|
||||||
|
[{ label: '?123', width: 3, level: 2, right: true }],
|
||||||
|
[{ label: '🌐', width: 1.5 }, { label: '⌨', width: 1.5, action: 'hide' }] ],
|
||||||
|
];
|
||||||
|
|
||||||
var Key = new Lang.Class({
|
var Key = new Lang.Class({
|
||||||
Name: 'Key',
|
Name: 'Key',
|
||||||
|
|
||||||
_init : function(key) {
|
_init : function(key, extendedKeys) {
|
||||||
this._key = key;
|
this.key = key;
|
||||||
this.actor = this._makeKey(key, GLib.markup_escape_text(key.label, -1));
|
this.actor = this._makeKey(this.key);
|
||||||
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
|
|
||||||
|
|
||||||
this._extended_keys = this._key.get_extended_keys();
|
/* Add the key in a container, so keys can be padded without losing
|
||||||
|
* logical proportions between those.
|
||||||
|
*/
|
||||||
|
this.container = new St.BoxLayout ({ style_class: 'key-container' });
|
||||||
|
this.container.add(this.actor, { expand: true, x_fill: true });
|
||||||
|
this.container.connect('destroy', Lang.bind(this, this._onDestroy));
|
||||||
|
|
||||||
|
this._extended_keys = extendedKeys;
|
||||||
this._extended_keyboard = null;
|
this._extended_keyboard = null;
|
||||||
|
this._pressTimeoutId = 0;
|
||||||
if (this._key.name == 'Control_L' || this._key.name == 'Alt_L')
|
|
||||||
this._key.latch = true;
|
|
||||||
|
|
||||||
if (this._extended_keys.length > 0) {
|
|
||||||
this._key.connect('notify::show-subkeys', Lang.bind(this, this._onShowSubkeysChanged));
|
|
||||||
this._boxPointer = new BoxPointer.BoxPointer(St.Side.BOTTOM,
|
|
||||||
{ x_fill: true,
|
|
||||||
y_fill: true,
|
|
||||||
x_align: St.Align.START });
|
|
||||||
// Adds style to existing keyboard style to avoid repetition
|
|
||||||
this._boxPointer.actor.add_style_class_name('keyboard-subkeys');
|
|
||||||
this._getExtendedKeys();
|
|
||||||
this.actor._extended_keys = this._extended_keyboard;
|
|
||||||
this._boxPointer.actor.hide();
|
|
||||||
Main.layoutManager.addChrome(this._boxPointer.actor);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_onDestroy: function() {
|
_onDestroy: function() {
|
||||||
@ -62,19 +75,73 @@ var Key = new Lang.Class({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_makeKey: function (key, label) {
|
_ensureExtendedKeysPopup: function() {
|
||||||
|
if (this._extended_keys.length == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this._boxPointer = new BoxPointer.BoxPointer(St.Side.BOTTOM,
|
||||||
|
{ x_fill: true,
|
||||||
|
y_fill: true,
|
||||||
|
x_align: St.Align.START });
|
||||||
|
this._boxPointer.actor.hide();
|
||||||
|
Main.layoutManager.addChrome(this._boxPointer.actor);
|
||||||
|
this._boxPointer.setPosition(this.actor, 0.5);
|
||||||
|
|
||||||
|
// Adds style to existing keyboard style to avoid repetition
|
||||||
|
this._boxPointer.actor.add_style_class_name('keyboard-subkeys');
|
||||||
|
this._getExtendedKeys();
|
||||||
|
this.actor._extended_keys = this._extended_keyboard;
|
||||||
|
},
|
||||||
|
|
||||||
|
_getKeyval: function(key) {
|
||||||
|
let unicode = String.charCodeAt(key, 0);
|
||||||
|
return Gdk.unicode_to_keyval(unicode);
|
||||||
|
},
|
||||||
|
|
||||||
|
_press: function(key) {
|
||||||
|
if (key != this.key || this._extended_keys.length == 0) {
|
||||||
|
this.emit('pressed', this._getKeyval(key));
|
||||||
|
} else if (key == this.key) {
|
||||||
|
this._pressTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT,
|
||||||
|
KEY_LONG_PRESS_TIME,
|
||||||
|
Lang.bind(this, function() {
|
||||||
|
this.actor.set_hover(false);
|
||||||
|
this.actor.fake_release();
|
||||||
|
this._pressTimeoutId = 0;
|
||||||
|
this._touchPressed = false;
|
||||||
|
this._ensureExtendedKeysPopup();
|
||||||
|
this.actor.fake_release();
|
||||||
|
this.actor.set_hover(false);
|
||||||
|
this.emit('show-subkeys');
|
||||||
|
return GLib.SOURCE_REMOVE;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_release: function(key) {
|
||||||
|
if (this._pressTimeoutId != 0) {
|
||||||
|
GLib.source_remove(this._pressTimeoutId);
|
||||||
|
this._pressTimeoutId = 0;
|
||||||
|
this.emit('pressed', this._getKeyval(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.emit('released', this._getKeyval(key));
|
||||||
|
},
|
||||||
|
|
||||||
|
_makeKey: function (key) {
|
||||||
|
let label = GLib.markup_escape_text(key, -1);
|
||||||
let button = new St.Button ({ label: label,
|
let button = new St.Button ({ label: label,
|
||||||
style_class: 'keyboard-key' });
|
style_class: 'keyboard-key' });
|
||||||
|
|
||||||
button.key_width = this._key.width;
|
button.keyWidth = 1;
|
||||||
button.connect('button-press-event', Lang.bind(this,
|
button.connect('button-press-event', Lang.bind(this,
|
||||||
function () {
|
function () {
|
||||||
key.press();
|
this._press(key);
|
||||||
return Clutter.EVENT_PROPAGATE;
|
return Clutter.EVENT_PROPAGATE;
|
||||||
}));
|
}));
|
||||||
button.connect('button-release-event', Lang.bind(this,
|
button.connect('button-release-event', Lang.bind(this,
|
||||||
function () {
|
function () {
|
||||||
key.release();
|
this._release(key);
|
||||||
return Clutter.EVENT_PROPAGATE;
|
return Clutter.EVENT_PROPAGATE;
|
||||||
}));
|
}));
|
||||||
button.connect('touch-event', Lang.bind(this,
|
button.connect('touch-event', Lang.bind(this,
|
||||||
@ -96,13 +163,13 @@ var Key = new Lang.Class({
|
|||||||
event.type() == Clutter.EventType.TOUCH_BEGIN) {
|
event.type() == Clutter.EventType.TOUCH_BEGIN) {
|
||||||
device.sequence_grab(sequence, actor);
|
device.sequence_grab(sequence, actor);
|
||||||
this._touchPressed = true;
|
this._touchPressed = true;
|
||||||
key.press();
|
this._press(key);
|
||||||
} else if (this._touchPressed &&
|
} else if (this._touchPressed &&
|
||||||
event.type() == Clutter.EventType.TOUCH_END &&
|
event.type() == Clutter.EventType.TOUCH_END &&
|
||||||
device.sequence_get_grabbed_actor(sequence) == actor) {
|
device.sequence_get_grabbed_actor(sequence) == actor) {
|
||||||
device.sequence_ungrab(sequence);
|
device.sequence_ungrab(sequence);
|
||||||
this._touchPressed = false;
|
this._touchPressed = false;
|
||||||
key.release();
|
this._release(key);
|
||||||
}
|
}
|
||||||
return Clutter.EVENT_PROPAGATE;
|
return Clutter.EVENT_PROPAGATE;
|
||||||
}));
|
}));
|
||||||
@ -110,26 +177,18 @@ var Key = new Lang.Class({
|
|||||||
return button;
|
return button;
|
||||||
},
|
},
|
||||||
|
|
||||||
_getUnichar: function(key) {
|
|
||||||
let keyval = key.keyval;
|
|
||||||
let unichar = Gdk.keyval_to_unicode(keyval);
|
|
||||||
if (unichar) {
|
|
||||||
return String.fromCharCode(unichar);
|
|
||||||
} else {
|
|
||||||
return key.name;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_getExtendedKeys: function () {
|
_getExtendedKeys: function () {
|
||||||
this._extended_keyboard = new St.BoxLayout({ style_class: 'keyboard-layout',
|
this._extended_keyboard = new St.BoxLayout({ style_class: 'key-container',
|
||||||
vertical: false });
|
vertical: false });
|
||||||
for (let i = 0; i < this._extended_keys.length; ++i) {
|
for (let i = 0; i < this._extended_keys.length; ++i) {
|
||||||
let extended_key = this._extended_keys[i];
|
let extendedKey = this._extended_keys[i];
|
||||||
let label = this._getUnichar(extended_key);
|
let key = this._makeKey(extendedKey);
|
||||||
let key = this._makeKey(extended_key, label);
|
|
||||||
|
|
||||||
key.extended_key = extended_key;
|
key.extended_key = extendedKey;
|
||||||
this._extended_keyboard.add(key);
|
this._extended_keyboard.add(key);
|
||||||
|
|
||||||
|
key.width = this.actor.width;
|
||||||
|
key.height = this.actor.height;
|
||||||
}
|
}
|
||||||
this._boxPointer.bin.add_actor(this._extended_keyboard);
|
this._boxPointer.bin.add_actor(this._extended_keyboard);
|
||||||
},
|
},
|
||||||
@ -138,20 +197,39 @@ var Key = new Lang.Class({
|
|||||||
return this._boxPointer;
|
return this._boxPointer;
|
||||||
},
|
},
|
||||||
|
|
||||||
_onShowSubkeysChanged: function () {
|
setWidth: function (width) {
|
||||||
if (this._key.show_subkeys) {
|
this.actor.keyWidth = width;
|
||||||
this._boxPointer.actor.raise_top();
|
},
|
||||||
this._boxPointer.setPosition(this.actor, 0.5);
|
|
||||||
this.emit('show-subkeys');
|
|
||||||
this.actor.fake_release();
|
|
||||||
this.actor.set_hover(false);
|
|
||||||
} else {
|
|
||||||
this.emit('hide-subkeys');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
Signals.addSignalMethods(Key.prototype);
|
Signals.addSignalMethods(Key.prototype);
|
||||||
|
|
||||||
|
var KeyboardModel = new Lang.Class({
|
||||||
|
Name: 'KeyboardModel',
|
||||||
|
|
||||||
|
_init: function (groupName) {
|
||||||
|
try {
|
||||||
|
this._model = this._loadModel(groupName);
|
||||||
|
} catch (e) {
|
||||||
|
this._model = this._loadModel('us');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_loadModel: function(groupName) {
|
||||||
|
let file = Gio.File.new_for_uri('resource:///org/gnome/shell/osk-layouts/%s.json'.format(groupName));
|
||||||
|
let [success, contents] = file.load_contents(null);
|
||||||
|
|
||||||
|
return JSON.parse(contents);
|
||||||
|
},
|
||||||
|
|
||||||
|
getLevels: function() {
|
||||||
|
return this._model.levels;
|
||||||
|
},
|
||||||
|
|
||||||
|
getKeysForLevel: function(levelName) {
|
||||||
|
return this._model.levels.find(level => level == levelName);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
var Keyboard = new Lang.Class({
|
var Keyboard = new Lang.Class({
|
||||||
Name: 'Keyboard',
|
Name: 'Keyboard',
|
||||||
|
|
||||||
@ -169,14 +247,10 @@ var Keyboard = new Lang.Class({
|
|||||||
this._enableKeyboard = false; // a11y settings value
|
this._enableKeyboard = false; // a11y settings value
|
||||||
this._enabled = false; // enabled state (by setting or device type)
|
this._enabled = false; // enabled state (by setting or device type)
|
||||||
|
|
||||||
this._keyboardSettings = new Gio.Settings({ schema_id: KEYBOARD_SCHEMA });
|
|
||||||
this._keyboardSettings.connect('changed', Lang.bind(this, this._sync));
|
|
||||||
this._a11yApplicationsSettings = new Gio.Settings({ schema_id: A11Y_APPLICATIONS_SCHEMA });
|
this._a11yApplicationsSettings = new Gio.Settings({ schema_id: A11Y_APPLICATIONS_SCHEMA });
|
||||||
this._a11yApplicationsSettings.connect('changed', Lang.bind(this, this._syncEnabled));
|
this._a11yApplicationsSettings.connect('changed', Lang.bind(this, this._syncEnabled));
|
||||||
this._lastDeviceId = null;
|
this._lastDeviceId = null;
|
||||||
|
|
||||||
Caribou.DisplayAdapter.set_default(new LocalAdapter());
|
|
||||||
|
|
||||||
Meta.get_backend().connect('last-device-changed', Lang.bind(this,
|
Meta.get_backend().connect('last-device-changed', Lang.bind(this,
|
||||||
function (backend, deviceId) {
|
function (backend, deviceId) {
|
||||||
let manager = Clutter.DeviceManager.get_default();
|
let manager = Clutter.DeviceManager.get_default();
|
||||||
@ -187,7 +261,7 @@ var Keyboard = new Lang.Class({
|
|||||||
this._syncEnabled();
|
this._syncEnabled();
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
this._sync();
|
this._syncEnabled();
|
||||||
|
|
||||||
this._showIdleId = 0;
|
this._showIdleId = 0;
|
||||||
this._subkeysBoxPointer = null;
|
this._subkeysBoxPointer = null;
|
||||||
@ -309,33 +383,25 @@ var Keyboard = new Lang.Class({
|
|||||||
let wasEnabled = this._enabled;
|
let wasEnabled = this._enabled;
|
||||||
this._enableKeyboard = this._a11yApplicationsSettings.get_boolean(SHOW_KEYBOARD);
|
this._enableKeyboard = this._a11yApplicationsSettings.get_boolean(SHOW_KEYBOARD);
|
||||||
this._enabled = this._enableKeyboard || this._lastDeviceIsTouchscreen();
|
this._enabled = this._enableKeyboard || this._lastDeviceIsTouchscreen();
|
||||||
if (!this._enabled && !this._keyboard)
|
if (!this._enabled && !this._keyboardController)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this._setCaretTrackerEnabled(this._enabled);
|
this._setCaretTrackerEnabled(this._enabled);
|
||||||
|
|
||||||
if (this._enabled && !this._keyboard)
|
if (this._enabled && !this._keyboardController)
|
||||||
this._setupKeyboard();
|
this._setupKeyboard();
|
||||||
|
|
||||||
if (!this._enabled && wasEnabled)
|
if (!this._enabled && wasEnabled) {
|
||||||
|
this._hideSubkeys();
|
||||||
Main.layoutManager.hideKeyboard(true);
|
Main.layoutManager.hideKeyboard(true);
|
||||||
},
|
}
|
||||||
|
|
||||||
_sync: function () {
|
|
||||||
if (this._keyboard &&
|
|
||||||
this._keyboard.keyboard_type != this._keyboardSettings.get_string(KEYBOARD_TYPE))
|
|
||||||
this._destroyKeyboard();
|
|
||||||
|
|
||||||
this._syncEnabled();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_destroyKeyboard: function() {
|
_destroyKeyboard: function() {
|
||||||
if (this._keyboardNotifyId)
|
if (this._keyboardNotifyId)
|
||||||
this._keyboard.disconnect(this._keyboardNotifyId);
|
this._keyboardController.disconnect(this._keyboardNotifyId);
|
||||||
if (this._keyboardGroupAddedId)
|
if (this._keyboardGroupsChangedId)
|
||||||
this._keyboard.disconnect(this._keyboardGroupAddedId);
|
this._keyboardController.disconnect(this._keyboardGroupsChangedId);
|
||||||
if (this._keyboardGroupRemovedId)
|
|
||||||
this._keyboard.disconnect(this._keyboardGroupRemovedId);
|
|
||||||
if (this._focusNotifyId)
|
if (this._focusNotifyId)
|
||||||
global.stage.disconnect(this._focusNotifyId);
|
global.stage.disconnect(this._focusNotifyId);
|
||||||
this._keyboard = null;
|
this._keyboard = null;
|
||||||
@ -348,7 +414,8 @@ var Keyboard = new Lang.Class({
|
|||||||
Main.layoutManager.keyboardBox.add_actor(this.actor);
|
Main.layoutManager.keyboardBox.add_actor(this.actor);
|
||||||
Main.layoutManager.trackChrome(this.actor);
|
Main.layoutManager.trackChrome(this.actor);
|
||||||
|
|
||||||
this._keyboard = new Caribou.KeyboardModel({ keyboard_type: this._keyboardSettings.get_string(KEYBOARD_TYPE) });
|
this._keyboardController = new KeyboardController();
|
||||||
|
|
||||||
this._groups = {};
|
this._groups = {};
|
||||||
this._current_page = null;
|
this._current_page = null;
|
||||||
|
|
||||||
@ -358,14 +425,13 @@ var Keyboard = new Lang.Class({
|
|||||||
|
|
||||||
this._addKeys();
|
this._addKeys();
|
||||||
|
|
||||||
// Keys should be layout according to the group, not the
|
// Keyboard models are defined in LTR, we must override
|
||||||
// locale; as Caribou already provides the expected layout,
|
// the locale setting in order to avoid flipping the
|
||||||
// this means enforcing LTR for all locales.
|
// keyboard on RTL locales.
|
||||||
this.actor.text_direction = Clutter.TextDirection.LTR;
|
this.actor.text_direction = Clutter.TextDirection.LTR;
|
||||||
|
|
||||||
this._keyboardNotifyId = this._keyboard.connect('notify::active-group', Lang.bind(this, this._onGroupChanged));
|
this._keyboardNotifyId = this._keyboardController.connect('active-group', Lang.bind(this, this._onGroupChanged));
|
||||||
this._keyboardGroupAddedId = this._keyboard.connect('group-added', Lang.bind(this, this._onGroupAdded));
|
this._keyboardGroupsChangedId = this._keyboardController.connect('groups-changed', Lang.bind(this, this._onKeyboardGroupsChanged));
|
||||||
this._keyboardGroupRemovedId = this._keyboard.connect('group-removed', Lang.bind(this, this._onGroupRemoved));
|
|
||||||
this._focusNotifyId = global.stage.connect('notify::key-focus', Lang.bind(this, this._onKeyFocusChanged));
|
this._focusNotifyId = global.stage.connect('notify::key-focus', Lang.bind(this, this._onKeyFocusChanged));
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -395,18 +461,21 @@ var Keyboard = new Lang.Class({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_createLayersForGroup: function (gname) {
|
_createLayersForGroup: function (groupName) {
|
||||||
let group = this._keyboard.get_group(gname);
|
let keyboardModel = new KeyboardModel(groupName);
|
||||||
group.connect('notify::active-level', Lang.bind(this, this._onLevelChanged));
|
|
||||||
let layers = {};
|
let layers = {};
|
||||||
let levels = group.get_levels();
|
let levels = keyboardModel.getLevels();
|
||||||
for (let j = 0; j < levels.length; ++j) {
|
for (let i = 0; i < levels.length; i++) {
|
||||||
let lname = levels[j];
|
let currentLevel = levels[i];
|
||||||
let level = group.get_level(lname);
|
/* There are keyboard maps which consist of 3 levels (no uppercase,
|
||||||
|
* basically). We however make things consistent by skipping that
|
||||||
|
* second level.
|
||||||
|
*/
|
||||||
|
let level = (i >= 1 && levels.length == 3) ? i + 1 : i;
|
||||||
let layout = new St.BoxLayout({ style_class: 'keyboard-layout',
|
let layout = new St.BoxLayout({ style_class: 'keyboard-layout',
|
||||||
vertical: true });
|
vertical: true });
|
||||||
this._loadRows(level, layout);
|
this._loadRows(currentLevel, level, levels.length, layout);
|
||||||
layers[lname] = layout;
|
layers[level] = layout;
|
||||||
this.actor.add(layout, { x_fill: false });
|
this.actor.add(layout, { x_fill: false });
|
||||||
|
|
||||||
layout.hide();
|
layout.hide();
|
||||||
@ -415,19 +484,19 @@ var Keyboard = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_addKeys: function () {
|
_addKeys: function () {
|
||||||
let groups = this._keyboard.get_groups();
|
let groups = this._keyboardController.getGroups();
|
||||||
for (let i = 0; i < groups.length; ++i) {
|
for (let i = 0; i < groups.length; ++i) {
|
||||||
let gname = groups[i];
|
let gname = groups[i];
|
||||||
this._groups[gname] = this._createLayersForGroup(gname);
|
this._groups[gname] = this._createLayersForGroup(gname);
|
||||||
}
|
}
|
||||||
|
|
||||||
this._setActiveLayer();
|
this._setActiveLayer(0);
|
||||||
},
|
},
|
||||||
|
|
||||||
_onCapturedEvent: function(actor, event) {
|
_onCapturedEvent: function(actor, event) {
|
||||||
let type = event.type();
|
let type = event.type();
|
||||||
let press = type == Clutter.EventType.BUTTON_PRESS;
|
let press = (type == Clutter.EventType.BUTTON_PRESS || type == Clutter.EventType.TOUCH_BEGIN);
|
||||||
let release = type == Clutter.EventType.BUTTON_RELEASE;
|
let release = (type == Clutter.EventType.BUTTON_RELEASE || type == Clutter.EventType.TOUCH_END);
|
||||||
|
|
||||||
if (press)
|
if (press)
|
||||||
this._capturedPress = true;
|
this._capturedPress = true;
|
||||||
@ -437,34 +506,14 @@ var Keyboard = new Lang.Class({
|
|||||||
return Clutter.EVENT_STOP;
|
return Clutter.EVENT_STOP;
|
||||||
},
|
},
|
||||||
|
|
||||||
_addRows : function (keys, layout) {
|
_addRowKeys : function (keys, keyboardRow) {
|
||||||
let keyboard_row = new St.BoxLayout();
|
|
||||||
for (let i = 0; i < keys.length; ++i) {
|
for (let i = 0; i < keys.length; ++i) {
|
||||||
let children = keys[i].get_children();
|
let key = keys[i];
|
||||||
let left_box = new St.BoxLayout({ style_class: 'keyboard-row' });
|
let button = new Key(key.shift(), key);
|
||||||
let center_box = new St.BoxLayout({ style_class: 'keyboard-row' });
|
|
||||||
let right_box = new St.BoxLayout({ style_class: 'keyboard-row' });
|
|
||||||
for (let j = 0; j < children.length; ++j) {
|
|
||||||
if (this._numOfHorizKeys == 0)
|
|
||||||
this._numOfHorizKeys = children.length;
|
|
||||||
let key = children[j];
|
|
||||||
let button = new Key(key);
|
|
||||||
|
|
||||||
switch (key.align) {
|
/* Space key gets special width, dependent on the number of surrounding keys */
|
||||||
case 'right':
|
if (button.key == ' ')
|
||||||
right_box.add(button.actor);
|
button.setWidth(keys.length <= 3 ? 5 : 3);
|
||||||
break;
|
|
||||||
case 'center':
|
|
||||||
center_box.add(button.actor);
|
|
||||||
break;
|
|
||||||
case 'left':
|
|
||||||
default:
|
|
||||||
left_box.add(button.actor);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (key.name == 'Caribou_Prefs') {
|
|
||||||
key.connect('key-released', Lang.bind(this, this.hide));
|
|
||||||
}
|
|
||||||
|
|
||||||
button.connect('show-subkeys', Lang.bind(this, function() {
|
button.connect('show-subkeys', Lang.bind(this, function() {
|
||||||
if (this._subkeysBoxPointer)
|
if (this._subkeysBoxPointer)
|
||||||
@ -478,27 +527,119 @@ var Keyboard = new Lang.Class({
|
|||||||
button.connect('hide-subkeys', Lang.bind(this, function() {
|
button.connect('hide-subkeys', Lang.bind(this, function() {
|
||||||
this._hideSubkeys();
|
this._hideSubkeys();
|
||||||
}));
|
}));
|
||||||
|
button.connect('pressed', Lang.bind(this, function(actor, keyval) {
|
||||||
|
this._hideSubkeys();
|
||||||
|
if (keyval != 0)
|
||||||
|
this._keyboardController.keyvalPress(keyval);
|
||||||
|
}));
|
||||||
|
button.connect('released', Lang.bind(this, function(actor, keyval) {
|
||||||
|
this._hideSubkeys();
|
||||||
|
if (keyval != 0)
|
||||||
|
this._keyboardController.keyvalRelease(keyval);
|
||||||
|
}));
|
||||||
|
|
||||||
|
keyboardRow.add(button.container, { expand: true, x_fill: false, x_align: St.Align.END });
|
||||||
}
|
}
|
||||||
keyboard_row.add(left_box, { expand: true, x_fill: false, x_align: St.Align.START });
|
|
||||||
keyboard_row.add(center_box, { expand: true, x_fill: false, x_align: St.Align.MIDDLE });
|
|
||||||
keyboard_row.add(right_box, { expand: true, x_fill: false, x_align: St.Align.END });
|
|
||||||
}
|
|
||||||
layout.add(keyboard_row);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_loadRows : function (level, layout) {
|
_loadDefaultKeys: function(keys, rowActor, numLevels, numKeys) {
|
||||||
let rows = level.get_rows();
|
let extraButton;
|
||||||
|
for (let i = 0; i < keys.length; i++) {
|
||||||
|
let key = keys[i];
|
||||||
|
let keyval = key.keyval;
|
||||||
|
let switchToLevel = key.level;
|
||||||
|
let action = key.action;
|
||||||
|
|
||||||
|
extraButton = new Key(key.label, []);
|
||||||
|
rowActor.add(extraButton.container);
|
||||||
|
|
||||||
|
extraButton.actor.add_style_class_name('default-key');
|
||||||
|
if (key.extraClassName != null)
|
||||||
|
extraButton.actor.add_style_class_name(key.extraClassName);
|
||||||
|
if (key.width != null)
|
||||||
|
extraButton.setWidth(key.width);
|
||||||
|
|
||||||
|
extraButton.connect('released', Lang.bind(this, function() {
|
||||||
|
if (switchToLevel != null)
|
||||||
|
this._onLevelChanged(switchToLevel);
|
||||||
|
else if (keyval != null)
|
||||||
|
this._keyboardController.keyvalPress(keyval);
|
||||||
|
}));
|
||||||
|
extraButton.connect('released', Lang.bind(this, function() {
|
||||||
|
if (keyval != null)
|
||||||
|
this._keyboardController.keyvalRelease(keyval);
|
||||||
|
else if (action == 'hide')
|
||||||
|
this.hide();
|
||||||
|
}));
|
||||||
|
|
||||||
|
/* Fixup default keys based on the number of levels/keys */
|
||||||
|
if (key.label == '⇧' && numLevels == 3) {
|
||||||
|
if (key.right) {
|
||||||
|
/* Only hide the key actor, so the container still takes space */
|
||||||
|
extraButton.actor.hide();
|
||||||
|
} else {
|
||||||
|
extraButton.container.hide();
|
||||||
|
}
|
||||||
|
extraButton.setWidth(1.5);
|
||||||
|
} else if (key.right && numKeys > 8) {
|
||||||
|
extraButton.setWidth(2);
|
||||||
|
} else if (key.label == '⏎' && numKeys > 9) {
|
||||||
|
extraButton.setWidth(1.5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_getDefaultKeysForRow: function(row, numRows, level) {
|
||||||
|
let pre, post;
|
||||||
|
|
||||||
|
/* The first 2 rows in defaultKeysPre/Post belong together with
|
||||||
|
* the first 2 rows on each keymap. On keymaps that have more than
|
||||||
|
* 4 rows, the last 2 default key rows must be respectively
|
||||||
|
* assigned to the 2 last keymap ones.
|
||||||
|
*/
|
||||||
|
if (row < 2) {
|
||||||
|
return [defaultKeysPre[level][row], defaultKeysPost[level][row]];
|
||||||
|
} else if (row >= numRows - 2) {
|
||||||
|
let defaultRow = row - (numRows - 2) + 2;
|
||||||
|
return [defaultKeysPre[level][defaultRow], defaultKeysPost[level][defaultRow]];
|
||||||
|
} else {
|
||||||
|
return [null, null];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_mergeRowKeys: function (keyboardRow, pre, row, post, numLevels) {
|
||||||
|
if (pre != null)
|
||||||
|
this._loadDefaultKeys(pre, keyboardRow, numLevels, row.length);
|
||||||
|
|
||||||
|
this._addRowKeys(row, keyboardRow);
|
||||||
|
|
||||||
|
if (post != null)
|
||||||
|
this._loadDefaultKeys(post, keyboardRow, numLevels, row.length);
|
||||||
|
},
|
||||||
|
|
||||||
|
_loadRows : function (model, level, numLevels, layout) {
|
||||||
|
let rows = model.rows;
|
||||||
for (let i = 0; i < rows.length; ++i) {
|
for (let i = 0; i < rows.length; ++i) {
|
||||||
let row = rows[i];
|
let row = rows[i];
|
||||||
if (this._numOfVertKeys == 0)
|
if (this._numOfVertKeys == 0)
|
||||||
this._numOfVertKeys = rows.length;
|
this._numOfVertKeys = rows.length;
|
||||||
this._addRows(row.get_columns(), layout);
|
|
||||||
|
let keyboardRow = new St.BoxLayout({ style_class: 'keyboard-row',
|
||||||
|
x_expand: false,
|
||||||
|
x_align: Clutter.ActorAlign.END });
|
||||||
|
layout.add(keyboardRow);
|
||||||
|
|
||||||
|
let [pre, post] = this._getDefaultKeysForRow(i, rows.length, level);
|
||||||
|
this._mergeRowKeys (keyboardRow, pre, row, post, numLevels);
|
||||||
|
|
||||||
|
this._numOfHorizKeys = Math.max(this._numOfHorizKeys, keyboardRow.get_n_children());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._numOfVertKeys = Math.max(this._numOfVertKeys, rows.length);
|
||||||
},
|
},
|
||||||
|
|
||||||
_redraw: function () {
|
_redraw: function () {
|
||||||
if (!this._enabled)
|
if (!this._enabled || !this._current_page)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
let monitor = Main.layoutManager.keyboardMonitor;
|
let monitor = Main.layoutManager.keyboardMonitor;
|
||||||
@ -523,15 +664,14 @@ var Keyboard = new Lang.Class({
|
|||||||
let rows = this._current_page.get_children();
|
let rows = this._current_page.get_children();
|
||||||
for (let i = 0; i < rows.length; ++i) {
|
for (let i = 0; i < rows.length; ++i) {
|
||||||
let keyboard_row = rows[i];
|
let keyboard_row = rows[i];
|
||||||
let boxes = keyboard_row.get_children();
|
let keys = keyboard_row.get_children();
|
||||||
for (let j = 0; j < boxes.length; ++j) {
|
for (let j = 0; j < keys.length; ++j) {
|
||||||
let keys = boxes[j].get_children();
|
let child = keys[j];
|
||||||
for (let k = 0; k < keys.length; ++k) {
|
let keyActor = child.get_children()[0];
|
||||||
let child = keys[k];
|
child.width = keySize * keyActor.keyWidth;
|
||||||
child.width = keySize * child.key_width;
|
|
||||||
child.height = keySize;
|
child.height = keySize;
|
||||||
if (child._extended_keys) {
|
if (keyActor._extended_keys) {
|
||||||
let extended_keys = child._extended_keys.get_children();
|
let extended_keys = keyActor._extended_keys.get_children();
|
||||||
for (let n = 0; n < extended_keys.length; ++n) {
|
for (let n = 0; n < extended_keys.length; ++n) {
|
||||||
let extended_key = extended_keys[n];
|
let extended_key = extended_keys[n];
|
||||||
extended_key.width = keySize;
|
extended_key.width = keySize;
|
||||||
@ -540,38 +680,32 @@ var Keyboard = new Lang.Class({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_onLevelChanged: function () {
|
_onLevelChanged: function (level) {
|
||||||
this._setActiveLayer();
|
this._setActiveLayer(level);
|
||||||
this._redraw();
|
this._redraw();
|
||||||
},
|
},
|
||||||
|
|
||||||
_onGroupChanged: function () {
|
_onGroupChanged: function () {
|
||||||
this._setActiveLayer();
|
this._setActiveLayer(0);
|
||||||
this._redraw();
|
this._redraw();
|
||||||
},
|
},
|
||||||
|
|
||||||
_onGroupAdded: function (keyboard, gname) {
|
_onKeyboardGroupsChanged: function(keyboard) {
|
||||||
this._groups[gname] = this._createLayersForGroup(gname);
|
this._groups = [];
|
||||||
|
this._addKeys();
|
||||||
},
|
},
|
||||||
|
|
||||||
_onGroupRemoved: function (keyboard, gname) {
|
_setActiveLayer: function (activeLevel) {
|
||||||
delete this._groups[gname];
|
let activeGroupName = this._keyboardController.getCurrentGroup();
|
||||||
},
|
let layers = this._groups[activeGroupName];
|
||||||
|
|
||||||
_setActiveLayer: function () {
|
|
||||||
let active_group_name = this._keyboard.active_group;
|
|
||||||
let active_group = this._keyboard.get_group(active_group_name);
|
|
||||||
let active_level = active_group.active_level;
|
|
||||||
let layers = this._groups[active_group_name];
|
|
||||||
|
|
||||||
if (this._current_page != null) {
|
if (this._current_page != null) {
|
||||||
this._current_page.hide();
|
this._current_page.hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
this._current_page = layers[active_level];
|
this._current_page = layers[activeLevel];
|
||||||
this._current_page.show();
|
this._current_page.show();
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -700,9 +834,8 @@ var Keyboard = new Lang.Class({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
var LocalAdapter = new Lang.Class({
|
var KeyboardController = new Lang.Class({
|
||||||
Name: 'LocalAdapter',
|
Name: 'KeyboardController',
|
||||||
Extends: Caribou.XAdapter,
|
|
||||||
|
|
||||||
_init: function () {
|
_init: function () {
|
||||||
this.parent();
|
this.parent();
|
||||||
@ -714,38 +847,43 @@ var LocalAdapter = new Lang.Class({
|
|||||||
Lang.bind(this, this._onSourceChanged));
|
Lang.bind(this, this._onSourceChanged));
|
||||||
this._sourcesModifiedId = this._inputSourceManager.connect ('sources-changed',
|
this._sourcesModifiedId = this._inputSourceManager.connect ('sources-changed',
|
||||||
Lang.bind(this, this._onSourcesModified));
|
Lang.bind(this, this._onSourcesModified));
|
||||||
|
this._currentSource = this._inputSourceManager.currentSource;
|
||||||
},
|
},
|
||||||
|
|
||||||
_onSourcesModified: function () {
|
_onSourcesModified: function () {
|
||||||
this.emit('config-changed');
|
this.emit('groups-changed');
|
||||||
},
|
},
|
||||||
|
|
||||||
_onSourceChanged: function (inputSourceManager, oldSource) {
|
_onSourceChanged: function (inputSourceManager, oldSource) {
|
||||||
let source = inputSourceManager.currentSource;
|
let source = inputSourceManager.currentSource;
|
||||||
this.emit('group-changed', source.index, source.id, '');
|
this._currentSource = source;
|
||||||
|
this.emit('active-group', source.id);
|
||||||
},
|
},
|
||||||
|
|
||||||
vfunc_get_groups: function () {
|
getGroups: function () {
|
||||||
let inputSources = this._inputSourceManager.inputSources;
|
let inputSources = this._inputSourceManager.inputSources;
|
||||||
let groups = []
|
let groups = []
|
||||||
let variants = [];
|
|
||||||
|
|
||||||
for (let i in inputSources) {
|
for (let i in inputSources) {
|
||||||
let is = inputSources[i];
|
let is = inputSources[i];
|
||||||
groups[is.index] = is.id;
|
groups[is.index] = is.xkbId;
|
||||||
variants[is.index] = '';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return [groups, groups.length, variants, variants.length];
|
return groups;
|
||||||
},
|
},
|
||||||
|
|
||||||
vfunc_keyval_press: function(keyval) {
|
getCurrentGroup: function () {
|
||||||
|
return this._currentSource.xkbId;
|
||||||
|
},
|
||||||
|
|
||||||
|
keyvalPress: function(keyval) {
|
||||||
this._virtualDevice.notify_keyval(Clutter.get_current_event_time(),
|
this._virtualDevice.notify_keyval(Clutter.get_current_event_time(),
|
||||||
keyval, Clutter.KeyState.PRESSED);
|
keyval, Clutter.KeyState.PRESSED);
|
||||||
},
|
},
|
||||||
|
|
||||||
vfunc_keyval_release: function(keyval) {
|
keyvalRelease: function(keyval) {
|
||||||
this._virtualDevice.notify_keyval(Clutter.get_current_event_time(),
|
this._virtualDevice.notify_keyval(Clutter.get_current_event_time(),
|
||||||
keyval, Clutter.KeyState.RELEASED);
|
keyval, Clutter.KeyState.RELEASED);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
Signals.addSignalMethods(KeyboardController.prototype);
|
||||||
|
Loading…
Reference in New Issue
Block a user