[gnome-shell/wip/carlosg/osk-cldr: 22/43] keyboard: Rework OSK
- From: Carlos Garnacho <carlosg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-shell/wip/carlosg/osk-cldr: 22/43] keyboard: Rework OSK
- Date: Mon, 5 Feb 2018 13:58:44 +0000 (UTC)
commit fe1596caca5e90172860507e1baf5f64304ac366
Author: Carlos Garnacho <carlosg gnome org>
Date: Sat Aug 5 12:21:30 2017 +0200
keyboard: Rework OSK
Caribou is no longer used to load keyboard layouts,
gnome-shell uses the JSON files extracted from Unicode
CLDR instead.
data/theme/gnome-shell-high-contrast.css | 29 +-
data/theme/gnome-shell-sass | 2 +-
data/theme/gnome-shell.css | 29 +-
js/ui/keyboard.js | 512 ++++++++++++++++++++-----------
4 files changed, 352 insertions(+), 220 deletions(-)
---
diff --git a/data/theme/gnome-shell-high-contrast.css b/data/theme/gnome-shell-high-contrast.css
index ff0ebcabe..bab0101a7 100644
--- a/data/theme/gnome-shell-high-contrast.css
+++ b/data/theme/gnome-shell-high-contrast.css
@@ -1506,27 +1506,18 @@ StScrollBar {
#keyboard {
background-color: rgba(46, 52, 54, 0.7); }
-.keyboard-layout {
- spacing: 10px;
- padding: 10px; }
-
-.keyboard-row {
- spacing: 15px; }
+.key-container {
+ padding: 4px;
+ spacing: 4px; }
.keyboard-key {
- color: #eeeeec;
- 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;
+ background-color: #393f3f;
min-height: 2em;
min-width: 2em;
font-size: 14pt;
- font-weight: bold;
- border-radius: 5px;
- border: 1px solid black;
- color: white; }
+ border-radius: 3px;
+ border: 1px solid #464d4d;
+ color: #e5e5e5; }
.keyboard-key:focus {
color: #eeeeec;
text-shadow: 0 1px black;
@@ -1550,6 +1541,12 @@ StScrollBar {
background-color: #2e3436;
color: #eeeeec;
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 {
color: white;
diff --git a/data/theme/gnome-shell-sass b/data/theme/gnome-shell-sass
index 57a2e5bfe..08973e0e1 160000
--- a/data/theme/gnome-shell-sass
+++ b/data/theme/gnome-shell-sass
@@ -1 +1 @@
-Subproject commit 57a2e5bfe179d9db1e05c3edaffdcb3fee307be0
+Subproject commit 08973e0e16de468bc7a1cc1085f2e17153b74609
diff --git a/data/theme/gnome-shell.css b/data/theme/gnome-shell.css
index 61a78d379..9eb44a53d 100644
--- a/data/theme/gnome-shell.css
+++ b/data/theme/gnome-shell.css
@@ -1506,27 +1506,18 @@ StScrollBar {
#keyboard {
background-color: rgba(46, 52, 54, 0.7); }
-.keyboard-layout {
- spacing: 10px;
- padding: 10px; }
-
-.keyboard-row {
- spacing: 15px; }
+.key-container {
+ padding: 4px;
+ spacing: 4px; }
.keyboard-key {
- color: #eeeeec;
- 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;
+ background-color: #393f3f;
min-height: 2em;
min-width: 2em;
font-size: 14pt;
- font-weight: bold;
- border-radius: 5px;
- border: 1px solid #1c1f1f;
- color: white; }
+ border-radius: 3px;
+ border: 1px solid #464d4d;
+ color: #e5e5e5; }
.keyboard-key:focus {
color: #eeeeec;
text-shadow: 0 1px black;
@@ -1550,6 +1541,12 @@ StScrollBar {
background-color: #2e3436;
color: #eeeeec;
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 {
color: white;
diff --git a/js/ui/keyboard.js b/js/ui/keyboard.js
index 67e436f2c..a430b82e4 100644
--- a/js/ui/keyboard.js
+++ b/js/ui/keyboard.js
@@ -2,7 +2,6 @@
const FocusCaretTracker = imports.ui.focusCaretTracker;
const Atspi = imports.gi.Atspi;
-const Caribou = imports.gi.Caribou;
const Clutter = imports.gi.Clutter;
const Gdk = imports.gi.Gdk;
const Gio = imports.gi.Gio;
@@ -19,40 +18,54 @@ const Layout = imports.ui.layout;
const Main = imports.ui.main;
var KEYBOARD_REST_TIME = Layout.KEYBOARD_ANIMATION_TIME * 2 * 1000;
-
-const KEYBOARD_SCHEMA = 'org.gnome.shell.keyboard';
-const KEYBOARD_TYPE = 'keyboard-type';
+var KEY_LONG_PRESS_TIME = 250;
const A11Y_APPLICATIONS_SCHEMA = 'org.gnome.desktop.a11y.applications';
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({
Name: 'Key',
- _init : function(key) {
- this._key = key;
- this.actor = this._makeKey(key, GLib.markup_escape_text(key.label, -1));
- this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
+ _init : function(key, extendedKeys) {
+ this.key = key;
+ this.actor = this._makeKey(this.key);
- this._extended_keys = this._key.get_extended_keys();
- this._extended_keyboard = null;
+ /* 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));
- 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);
- }
+ this._extended_keys = extendedKeys;
+ this._extended_keyboard = null;
+ this._pressTimeoutId = 0;
},
_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,
style_class: 'keyboard-key' });
- button.key_width = this._key.width;
+ button.keyWidth = 1;
button.connect('button-press-event', Lang.bind(this,
function () {
- key.press();
+ this._press(key);
return Clutter.EVENT_PROPAGATE;
}));
button.connect('button-release-event', Lang.bind(this,
function () {
- key.release();
+ this._release(key);
return Clutter.EVENT_PROPAGATE;
}));
button.connect('touch-event', Lang.bind(this,
@@ -96,13 +163,13 @@ var Key = new Lang.Class({
event.type() == Clutter.EventType.TOUCH_BEGIN) {
device.sequence_grab(sequence, actor);
this._touchPressed = true;
- key.press();
+ this._press(key);
} else if (this._touchPressed &&
event.type() == Clutter.EventType.TOUCH_END &&
device.sequence_get_grabbed_actor(sequence) == actor) {
device.sequence_ungrab(sequence);
this._touchPressed = false;
- key.release();
+ this._release(key);
}
return Clutter.EVENT_PROPAGATE;
}));
@@ -110,26 +177,18 @@ var Key = new Lang.Class({
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 () {
- this._extended_keyboard = new St.BoxLayout({ style_class: 'keyboard-layout',
+ this._extended_keyboard = new St.BoxLayout({ style_class: 'key-container',
vertical: false });
for (let i = 0; i < this._extended_keys.length; ++i) {
- let extended_key = this._extended_keys[i];
- let label = this._getUnichar(extended_key);
- let key = this._makeKey(extended_key, label);
+ let extendedKey = this._extended_keys[i];
+ let key = this._makeKey(extendedKey);
- key.extended_key = extended_key;
+ key.extended_key = extendedKey;
this._extended_keyboard.add(key);
+
+ key.width = this.actor.width;
+ key.height = this.actor.height;
}
this._boxPointer.bin.add_actor(this._extended_keyboard);
},
@@ -138,19 +197,38 @@ var Key = new Lang.Class({
return this._boxPointer;
},
- _onShowSubkeysChanged: function () {
- if (this._key.show_subkeys) {
- 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');
+ setWidth: function (width) {
+ this.actor.keyWidth = width;
+ },
+});
+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);
}
});
-Signals.addSignalMethods(Key.prototype);
var Keyboard = new Lang.Class({
Name: 'Keyboard',
@@ -169,14 +247,10 @@ var Keyboard = new Lang.Class({
this._enableKeyboard = false; // a11y settings value
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.connect('changed', Lang.bind(this, this._syncEnabled));
this._lastDeviceId = null;
- Caribou.DisplayAdapter.set_default(new LocalAdapter());
-
Meta.get_backend().connect('last-device-changed', Lang.bind(this,
function (backend, deviceId) {
let manager = Clutter.DeviceManager.get_default();
@@ -187,7 +261,7 @@ var Keyboard = new Lang.Class({
this._syncEnabled();
}
}));
- this._sync();
+ this._syncEnabled();
this._showIdleId = 0;
this._subkeysBoxPointer = null;
@@ -309,33 +383,25 @@ var Keyboard = new Lang.Class({
let wasEnabled = this._enabled;
this._enableKeyboard = this._a11yApplicationsSettings.get_boolean(SHOW_KEYBOARD);
this._enabled = this._enableKeyboard || this._lastDeviceIsTouchscreen();
- if (!this._enabled && !this._keyboard)
+ if (!this._enabled && !this._keyboardController)
return;
this._setCaretTrackerEnabled(this._enabled);
- if (this._enabled && !this._keyboard)
+ if (this._enabled && !this._keyboardController)
this._setupKeyboard();
- if (!this._enabled && wasEnabled)
+ if (!this._enabled && wasEnabled) {
+ this._hideSubkeys();
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() {
if (this._keyboardNotifyId)
- this._keyboard.disconnect(this._keyboardNotifyId);
- if (this._keyboardGroupAddedId)
- this._keyboard.disconnect(this._keyboardGroupAddedId);
- if (this._keyboardGroupRemovedId)
- this._keyboard.disconnect(this._keyboardGroupRemovedId);
+ this._keyboardController.disconnect(this._keyboardNotifyId);
+ if (this._keyboardGroupsChangedId)
+ this._keyboardController.disconnect(this._keyboardGroupsChangedId);
if (this._focusNotifyId)
global.stage.disconnect(this._focusNotifyId);
this._keyboard = null;
@@ -348,7 +414,8 @@ var Keyboard = new Lang.Class({
Main.layoutManager.keyboardBox.add_actor(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._current_page = null;
@@ -358,14 +425,13 @@ var Keyboard = new Lang.Class({
this._addKeys();
- // Keys should be layout according to the group, not the
- // locale; as Caribou already provides the expected layout,
- // this means enforcing LTR for all locales.
+ // Keyboard models are defined in LTR, we must override
+ // the locale setting in order to avoid flipping the
+ // keyboard on RTL locales.
this.actor.text_direction = Clutter.TextDirection.LTR;
- this._keyboardNotifyId = this._keyboard.connect('notify::active-group', Lang.bind(this,
this._onGroupChanged));
- this._keyboardGroupAddedId = this._keyboard.connect('group-added', Lang.bind(this,
this._onGroupAdded));
- this._keyboardGroupRemovedId = this._keyboard.connect('group-removed', Lang.bind(this,
this._onGroupRemoved));
+ this._keyboardNotifyId = this._keyboardController.connect('active-group', Lang.bind(this,
this._onGroupChanged));
+ this._keyboardGroupsChangedId = this._keyboardController.connect('groups-changed', Lang.bind(this,
this._onKeyboardGroupsChanged));
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) {
- let group = this._keyboard.get_group(gname);
- group.connect('notify::active-level', Lang.bind(this, this._onLevelChanged));
+ _createLayersForGroup: function (groupName) {
+ let keyboardModel = new KeyboardModel(groupName);
let layers = {};
- let levels = group.get_levels();
- for (let j = 0; j < levels.length; ++j) {
- let lname = levels[j];
- let level = group.get_level(lname);
+ let levels = keyboardModel.getLevels();
+ for (let i = 0; i < levels.length; i++) {
+ let currentLevel = levels[i];
+ /* 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',
- vertical: true });
- this._loadRows(level, layout);
- layers[lname] = layout;
+ vertical: true });
+ this._loadRows(currentLevel, level, levels.length, layout);
+ layers[level] = layout;
this.actor.add(layout, { x_fill: false });
layout.hide();
@@ -415,19 +484,19 @@ var Keyboard = new Lang.Class({
},
_addKeys: function () {
- let groups = this._keyboard.get_groups();
+ let groups = this._keyboardController.getGroups();
for (let i = 0; i < groups.length; ++i) {
let gname = groups[i];
this._groups[gname] = this._createLayersForGroup(gname);
}
- this._setActiveLayer();
+ this._setActiveLayer(0);
},
_onCapturedEvent: function(actor, event) {
let type = event.type();
- let press = type == Clutter.EventType.BUTTON_PRESS;
- let release = type == Clutter.EventType.BUTTON_RELEASE;
+ let press = (type == Clutter.EventType.BUTTON_PRESS || type == Clutter.EventType.TOUCH_BEGIN);
+ let release = (type == Clutter.EventType.BUTTON_RELEASE || type == Clutter.EventType.TOUCH_END);
if (press)
this._capturedPress = true;
@@ -437,68 +506,140 @@ var Keyboard = new Lang.Class({
return Clutter.EVENT_STOP;
},
- _addRows : function (keys, layout) {
- let keyboard_row = new St.BoxLayout();
+ _addRowKeys : function (keys, keyboardRow) {
for (let i = 0; i < keys.length; ++i) {
- let children = keys[i].get_children();
- let left_box = new St.BoxLayout({ style_class: 'keyboard-row' });
- 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) {
- case 'right':
- right_box.add(button.actor);
- 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));
- }
+ let key = keys[i];
+ let button = new Key(key.shift(), key);
+
+ /* Space key gets special width, dependent on the number of surrounding keys */
+ if (button.key == ' ')
+ button.setWidth(keys.length <= 3 ? 5 : 3);
+
+ button.connect('show-subkeys', Lang.bind(this, function() {
+ if (this._subkeysBoxPointer)
+ this._subkeysBoxPointer.hide(BoxPointer.PopupAnimation.FULL);
+ this._subkeysBoxPointer = button.subkeys;
+ this._subkeysBoxPointer.show(BoxPointer.PopupAnimation.FULL);
+ if (!this._capturedEventId)
+ this._capturedEventId = this.actor.connect('captured-event',
+ Lang.bind(this, this._onCapturedEvent));
+ }));
+ button.connect('hide-subkeys', Lang.bind(this, function() {
+ 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 });
+ }
+ },
- button.connect('show-subkeys', Lang.bind(this, function() {
- if (this._subkeysBoxPointer)
- this._subkeysBoxPointer.hide(BoxPointer.PopupAnimation.FULL);
- this._subkeysBoxPointer = button.subkeys;
- this._subkeysBoxPointer.show(BoxPointer.PopupAnimation.FULL);
- if (!this._capturedEventId)
- this._capturedEventId = this.actor.connect('captured-event',
- Lang.bind(this, this._onCapturedEvent));
- }));
- button.connect('hide-subkeys', Lang.bind(this, function() {
- this._hideSubkeys();
- }));
+ _loadDefaultKeys: function(keys, rowActor, numLevels, numKeys) {
+ 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);
}
- 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) {
- let rows = level.get_rows();
+ _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) {
let row = rows[i];
if (this._numOfVertKeys == 0)
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 () {
- if (!this._enabled)
+ if (!this._enabled || !this._current_page)
return;
let monitor = Main.layoutManager.keyboardMonitor;
@@ -523,55 +664,48 @@ var Keyboard = new Lang.Class({
let rows = this._current_page.get_children();
for (let i = 0; i < rows.length; ++i) {
let keyboard_row = rows[i];
- let boxes = keyboard_row.get_children();
- for (let j = 0; j < boxes.length; ++j) {
- let keys = boxes[j].get_children();
- for (let k = 0; k < keys.length; ++k) {
- let child = keys[k];
- child.width = keySize * child.key_width;
- child.height = keySize;
- if (child._extended_keys) {
- let extended_keys = child._extended_keys.get_children();
- for (let n = 0; n < extended_keys.length; ++n) {
- let extended_key = extended_keys[n];
- extended_key.width = keySize;
- extended_key.height = keySize;
- }
+ let keys = keyboard_row.get_children();
+ for (let j = 0; j < keys.length; ++j) {
+ let child = keys[j];
+ let keyActor = child.get_children()[0];
+ child.width = keySize * keyActor.keyWidth;
+ child.height = keySize;
+ if (keyActor._extended_keys) {
+ let extended_keys = keyActor._extended_keys.get_children();
+ for (let n = 0; n < extended_keys.length; ++n) {
+ let extended_key = extended_keys[n];
+ extended_key.width = keySize;
+ extended_key.height = keySize;
}
}
}
}
},
- _onLevelChanged: function () {
- this._setActiveLayer();
+ _onLevelChanged: function (level) {
+ this._setActiveLayer(level);
this._redraw();
},
_onGroupChanged: function () {
- this._setActiveLayer();
+ this._setActiveLayer(0);
this._redraw();
},
- _onGroupAdded: function (keyboard, gname) {
- this._groups[gname] = this._createLayersForGroup(gname);
- },
-
- _onGroupRemoved: function (keyboard, gname) {
- delete this._groups[gname];
+ _onKeyboardGroupsChanged: function(keyboard) {
+ this._groups = [];
+ this._addKeys();
},
- _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];
+ _setActiveLayer: function (activeLevel) {
+ let activeGroupName = this._keyboardController.getCurrentGroup();
+ let layers = this._groups[activeGroupName];
if (this._current_page != null) {
this._current_page.hide();
}
- this._current_page = layers[active_level];
+ this._current_page = layers[activeLevel];
this._current_page.show();
},
@@ -700,9 +834,8 @@ var Keyboard = new Lang.Class({
},
});
-var LocalAdapter = new Lang.Class({
- Name: 'LocalAdapter',
- Extends: Caribou.XAdapter,
+var KeyboardController = new Lang.Class({
+ Name: 'KeyboardController',
_init: function () {
this.parent();
@@ -714,38 +847,43 @@ var LocalAdapter = new Lang.Class({
Lang.bind(this, this._onSourceChanged));
this._sourcesModifiedId = this._inputSourceManager.connect ('sources-changed',
Lang.bind(this,
this._onSourcesModified));
+ this._currentSource = this._inputSourceManager.currentSource;
},
_onSourcesModified: function () {
- this.emit('config-changed');
+ this.emit('groups-changed');
},
_onSourceChanged: function (inputSourceManager, oldSource) {
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 groups = []
- let variants = [];
for (let i in inputSources) {
let is = inputSources[i];
- groups[is.index] = is.id;
- variants[is.index] = '';
+ groups[is.index] = is.xkbId;
}
- return [groups, groups.length, variants, variants.length];
+ return groups;
+ },
+
+ getCurrentGroup: function () {
+ return this._currentSource.xkbId;
},
- vfunc_keyval_press: function(keyval) {
+ keyvalPress: function(keyval) {
this._virtualDevice.notify_keyval(Clutter.get_current_event_time(),
keyval, Clutter.KeyState.PRESSED);
},
- vfunc_keyval_release: function(keyval) {
+ keyvalRelease: function(keyval) {
this._virtualDevice.notify_keyval(Clutter.get_current_event_time(),
keyval, Clutter.KeyState.RELEASED);
},
});
+Signals.addSignalMethods(KeyboardController.prototype);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]