Skip to content

Commit 321506a

Browse files
authored
osk: Restore control and Alt keys (#13337)
* Restore control, alt to virtual keyboard. Fixes linuxmint/mint22.3-beta#22. * osk: Destroy the keyboard (releasing any modifieres) before restart, re-use shift-key style classes (for now), fix modifier persistence between layers.
1 parent 7741ae1 commit 321506a

File tree

3 files changed

+133
-17
lines changed

3 files changed

+133
-17
lines changed

data/theme/cinnamon-sass/widgets/_keyboard.scss

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,20 @@ $shifted_key_color: $lightest_bg_color;
4444
&.shift-key-uppercase { background-color: $shifted_key_color }
4545
&.enter-key { background-color: $accent_bg_color }
4646

47+
// TODO: pseudo class latched works better for temporarily changing the color.
48+
49+
// &.modifier-key {
50+
// background-color: $non_alpha_key_color;
51+
52+
// &:focus { @include button(focus); }
53+
// &:hover, &:checked { @include button(hover); }
54+
// &:active { @include button(active); }
55+
56+
// &:latched {
57+
// background-color: $shifted_key_color;
58+
// }
59+
// }
60+
4761
StIcon { icon-size: 1.125em; }
4862
}
4963

js/ui/main.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1627,6 +1627,8 @@ function restartCinnamon(showOsd = false) {
16271627
return false;
16281628
});
16291629

1630+
virtualKeyboardManager.destroyKeyboard();
1631+
16301632
global.reexec_self();
16311633
}
16321634

js/ui/virtualKeyboard.js

Lines changed: 117 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ const KEYBOARD_POSITION_KEY = 'keyboard-position';
2929
const KEY_SIZE = 2;
3030

3131
const escape_key = { keyval: Clutter.KEY_Escape, label: "Esc", extraClassName: 'escape-key' };
32-
const tab_key = { keyval: Clutter.KEY_Tab, label: '⇥', extraClassName: 'non-alpha-key' };
32+
const tab_key = { width: 1.5, keyval: Clutter.KEY_Tab, label: '⇥', extraClassName: 'non-alpha-key' };
3333
const _123_key = { width: 1.5, level: 2, label: '?123', extraClassName: 'non-alpha-key' };
3434
const abc_key = { width: 1.5, level: 0, label: 'ABC', extraClassName: 'non-alpha-key' };
3535
const backsp_key = { width: 1.5, keyval: Clutter.KEY_BackSpace, icon: 'xsi-edit-clear-symbolic', extraClassName: 'non-alpha-key' };
@@ -40,12 +40,14 @@ const dir_keys = [{ keyval: Clutter.KEY_Left, label: '←',
4040
{ keyval: Clutter.KEY_Down, label: '↓', extraClassName: 'non-alpha-key'},
4141
{ keyval: Clutter.KEY_Right, label: '→', extraClassName: 'non-alpha-key' }];
4242
const layout_key = { action: 'next-layout', icon: 'xsi-input-keyboard-symbolic' };
43+
const ctrl_key = { keyval: Clutter.KEY_Control_L, label: 'Ctrl', width: 1.5, modifier: 'ctrl', extraClassName: 'non-alpha-key' };
44+
const alt_key = { keyval: Clutter.KEY_Alt_L, label: 'Alt', width: 1.5, modifier: 'alt', extraClassName: 'non-alpha-key' };
4345

4446
const defaultKeysPre = [
45-
[[escape_key], [tab_key], [{ width: 1.5, level: 1, extraClassName: 'shift-key-lowercase', icon: 'keyboard-shift-filled-symbolic' }], [layout_key, _123_key]],
46-
[[escape_key], [tab_key], [{ width: 1.5, level: 0, extraClassName: 'shift-key-uppercase', icon: 'keyboard-shift-filled-symbolic' }], [layout_key, _123_key]],
47-
[[escape_key], [tab_key], [{ label: '=/<', width: 1.5, level: 3, extraClassName: 'non-alpha-key' }], [abc_key]],
48-
[[escape_key], [tab_key], [{ label: '?123', width: 1.5, level: 2, extraClassName: 'non-alpha-key' }], [abc_key]],
47+
[[escape_key], [tab_key], [layout_key, { width: 1.5, level: 1, extraClassName: 'shift-key-lowercase', icon: 'keyboard-shift-filled-symbolic' }], [ctrl_key, _123_key, alt_key]],
48+
[[escape_key], [tab_key], [layout_key, { width: 1.5, level: 0, extraClassName: 'shift-key-uppercase', icon: 'keyboard-shift-filled-symbolic' }], [ctrl_key, _123_key, alt_key]],
49+
[[escape_key], [tab_key], [{ label: '=/<', width: 1.5, level: 3, extraClassName: 'non-alpha-key' }], [ctrl_key, abc_key, alt_key]],
50+
[[escape_key], [tab_key], [{ label: '?123', width: 1.5, level: 2, extraClassName: 'non-alpha-key' }], [ctrl_key, abc_key, alt_key]],
4951
];
5052

5153
const defaultKeysPost = [
@@ -137,6 +139,8 @@ class KeyContainer extends St.Widget {
137139

138140
this._currentRow = null;
139141
this._rows = [];
142+
this.shiftKeys = [];
143+
this.modifierKeys = {};
140144
}
141145

142146
appendRow() {
@@ -469,16 +473,25 @@ var Key = GObject.registerClass({
469473
this.keyButton.keyWidth = width;
470474
}
471475

472-
setLatched(latched) {
473-
if (!this._icon)
476+
setLatched(latched, modifierType = 'shift') {
477+
const is_shift = modifierType === 'shift';
478+
if (!this._icon && is_shift)
474479
return;
475480

476481
if (latched) {
477482
this.keyButton.add_style_pseudo_class('latched');
478-
this._icon.icon_name = 'keyboard-caps-lock-filled-symbolic';
483+
if (is_shift && this._icon) {
484+
this._icon.icon_name = 'keyboard-caps-lock-filled-symbolic';
485+
} else {
486+
this.keyButton.add_style_class_name('shift-key-uppercase');
487+
}
479488
} else {
480489
this.keyButton.remove_style_pseudo_class('latched');
481-
this._icon.icon_name = 'keyboard-shift-filled-symbolic';
490+
if (is_shift && this._icon) {
491+
this._icon.icon_name = 'keyboard-shift-filled-symbolic';
492+
} else {
493+
this.keyButton.remove_style_class_name('shift-key-uppercase');
494+
}
482495
}
483496
}
484497
});
@@ -712,7 +725,7 @@ var VirtualKeyboardManager = GObject.registerClass({
712725
}
713726

714727
_keyboardSettingsChanged() {
715-
this._destroyKeyboard();
728+
this.destroyKeyboard();
716729
this._syncEnabled();
717730
}
718731

@@ -730,11 +743,11 @@ var VirtualKeyboardManager = GObject.registerClass({
730743
if (enabled && !this._keyboard) {
731744
this._keyboard = new Keyboard(this._keyboardSettings.get_string(ACTIVATION_MODE_KEY) === "on-demand");
732745
} else if (!enabled && this._keyboard) {
733-
this._destroyKeyboard();
746+
this.destroyKeyboard();
734747
}
735748
}
736749

737-
_destroyKeyboard() {
750+
destroyKeyboard() {
738751
if (this._keyboard == null) {
739752
return;
740753
}
@@ -814,6 +827,16 @@ class Keyboard extends St.BoxLayout {
814827
this._currentFocusWindow = null;
815828

816829
this._latched = false; // current level is latched
830+
this._currentLevel = 0; // track current level for modifier handling
831+
832+
this._latchedModifiers = {
833+
ctrl: false,
834+
alt: false
835+
};
836+
this._pressedModifierKeyvals = {
837+
ctrl: 0,
838+
alt: 0
839+
};
817840

818841
this._suggestions = null;
819842

@@ -869,6 +892,7 @@ class Keyboard extends St.BoxLayout {
869892
delete this._connectionsIDs;
870893

871894
this._clearShowIdle();
895+
this._releaseAllModifiers();
872896

873897
this._keyboardController.destroy();
874898

@@ -971,8 +995,6 @@ class Keyboard extends St.BoxLayout {
971995
let level = i >= 1 && levels.length == 3 ? i + 1 : i;
972996

973997
let layout = new KeyContainer();
974-
layout.shiftKeys = [];
975-
976998
this._loadRows(currentLevel, level, levels.length, layout);
977999
layers[level] = layout;
9781000
this._aspectContainer.add_child(layout);
@@ -1014,6 +1036,8 @@ class Keyboard extends St.BoxLayout {
10141036
button._keyvalPress = false;
10151037
}
10161038

1039+
this._releaseAllModifiers();
1040+
10171041
if (!this._latched)
10181042
this._setActiveLayer(0);
10191043
});
@@ -1030,6 +1054,7 @@ class Keyboard extends St.BoxLayout {
10301054
let switchToLevel = key.level;
10311055
let action = key.action;
10321056
let icon = key.icon;
1057+
let modifier = key.modifier;
10331058

10341059
if (action === 'next-layout') {
10351060
let groups = this._keyboardController.getGroups();
@@ -1051,18 +1076,35 @@ class Keyboard extends St.BoxLayout {
10511076
let actor = extraButton.keyButton;
10521077

10531078
extraButton.connect('pressed', () => {
1079+
if (switchToLevel != null && (switchToLevel === 0 || switchToLevel === 1) &&
1080+
(this._currentLevel === 0 || this._currentLevel === 1) &&
1081+
(this._latchedModifiers.ctrl || this._latchedModifiers.alt)) {
1082+
this._keyboardController.keyvalPress(Clutter.KEY_Shift_L);
1083+
extraButton._shiftPressed = true;
1084+
return;
1085+
}
1086+
10541087
if (switchToLevel != null) {
10551088
this._setActiveLayer(switchToLevel);
1056-
// Shift only gets latched on long press
10571089
this._latched = switchToLevel != 1;
1090+
} else if (modifier != null) {
1091+
this._toggleModifier(modifier, keyval, extraButton);
10581092
} else if (keyval != null) {
10591093
this._keyboardController.keyvalPress(keyval);
10601094
}
10611095
});
10621096
extraButton.connect('released', () => {
1063-
if (keyval != null)
1097+
if (extraButton._shiftPressed) {
1098+
this._keyboardController.keyvalRelease(Clutter.KEY_Shift_L);
1099+
this._releaseAllModifiers();
1100+
extraButton._shiftPressed = false;
1101+
return;
1102+
}
1103+
1104+
if (keyval != null && modifier == null) {
10641105
this._keyboardController.keyvalRelease(keyval);
1065-
else if (action == 'hide')
1106+
this._releaseAllModifiers();
1107+
} else if (action == 'hide')
10661108
this.close();
10671109
else if (action == 'next-layout')
10681110
this._keyboardController.activateNextGroup();
@@ -1075,6 +1117,10 @@ class Keyboard extends St.BoxLayout {
10751117
this._latched = true;
10761118
this._setCurrentLevelLatched(this._currentPage, this._latched);
10771119
});
1120+
} else if (modifier != null) {
1121+
if (!layout.modifierKeys[modifier])
1122+
layout.modifierKeys[modifier] = [];
1123+
layout.modifierKeys[modifier].push(extraButton);
10781124
}
10791125

10801126
/* Fixup default keys based on the number of levels/keys */
@@ -1107,6 +1153,58 @@ class Keyboard extends St.BoxLayout {
11071153
}
11081154
}
11091155

1156+
_toggleModifier(modifier, keyval, keyButton) {
1157+
if (this._latchedModifiers[modifier]) {
1158+
this._releaseModifier(modifier);
1159+
} else {
1160+
this._latchedModifiers[modifier] = true;
1161+
this._pressedModifierKeyvals[modifier] = keyval;
1162+
this._keyboardController.keyvalPress(keyval);
1163+
this._setModifierLatchedAllLayers(modifier, true);
1164+
}
1165+
}
1166+
1167+
_setModifierLatched(layout, modifier, latched) {
1168+
if (!layout?.modifierKeys?.[modifier])
1169+
return;
1170+
1171+
for (let i = 0; i < layout.modifierKeys[modifier].length; i++) {
1172+
let key = layout.modifierKeys[modifier][i];
1173+
key.setLatched(latched, modifier);
1174+
}
1175+
}
1176+
1177+
_setModifierLatchedAllLayers(modifier, latched) {
1178+
let activeGroupName = this._keyboardController.getCurrentGroup();
1179+
let layers = this._groups[activeGroupName];
1180+
1181+
for (let level in layers) {
1182+
this._setModifierLatched(layers[level], modifier, latched);
1183+
}
1184+
}
1185+
1186+
_releaseModifier(modifier) {
1187+
if (!this._latchedModifiers[modifier])
1188+
return;
1189+
1190+
let keyval = this._pressedModifierKeyvals[modifier];
1191+
if (keyval != 0) {
1192+
this._keyboardController.keyvalRelease(keyval);
1193+
}
1194+
1195+
this._latchedModifiers[modifier] = false;
1196+
this._pressedModifierKeyvals[modifier] = 0;
1197+
this._setModifierLatchedAllLayers(modifier, false);
1198+
}
1199+
1200+
_releaseAllModifiers() {
1201+
for (let modifier in this._latchedModifiers) {
1202+
if (this._latchedModifiers[modifier]) {
1203+
this._releaseModifier(modifier);
1204+
}
1205+
}
1206+
}
1207+
11101208
_getDefaultKeysForRow(row, numRows, level) {
11111209
/* The first 2 rows in defaultKeysPre/Post belong together with
11121210
* the first 2 rows on each keymap. On keymaps that have more than
@@ -1255,6 +1353,7 @@ class Keyboard extends St.BoxLayout {
12551353
delete this._currentPage._destroyID;
12561354
}
12571355

1356+
this._currentLevel = activeLevel;
12581357
this._currentPage = currentPage;
12591358
this._currentPage._destroyID = this._currentPage.connect('destroy', () => {
12601359
this._currentPage = null;
@@ -1322,6 +1421,7 @@ class Keyboard extends St.BoxLayout {
13221421
_close() {
13231422
if (this._keyboardRequested)
13241423
return;
1424+
this._releaseAllModifiers();
13251425
Main.layoutManager.hideKeyboard();
13261426
}
13271427

0 commit comments

Comments
 (0)