@@ -29,7 +29,7 @@ const KEYBOARD_POSITION_KEY = 'keyboard-position';
2929const KEY_SIZE = 2 ;
3030
3131const 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' } ;
3333const _123_key = { width : 1.5 , level : 2 , label : '?123' , extraClassName : 'non-alpha-key' } ;
3434const abc_key = { width : 1.5 , level : 0 , label : 'ABC' , extraClassName : 'non-alpha-key' } ;
3535const 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' } ] ;
4242const 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
4446const 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
5153const 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