diff --git a/packages/ckeditor5-engine/src/view/observer/keyobserver.js b/packages/ckeditor5-engine/src/view/observer/keyobserver.js
index 36a3f9d5de9..8b9e0111e01 100644
--- a/packages/ckeditor5-engine/src/view/observer/keyobserver.js
+++ b/packages/ckeditor5-engine/src/view/observer/keyobserver.js
@@ -29,8 +29,9 @@ export default class KeyObserver extends DomEventObserver {
keyCode: domEvt.keyCode,
altKey: domEvt.altKey,
- ctrlKey: domEvt.ctrlKey || domEvt.metaKey,
+ ctrlKey: domEvt.ctrlKey,
shiftKey: domEvt.shiftKey,
+ metaKey: domEvt.metaKey,
get keystroke() {
return getCode( this );
diff --git a/packages/ckeditor5-engine/tests/view/observer/keyobserver.js b/packages/ckeditor5-engine/tests/view/observer/keyobserver.js
index 89345a84a86..8c3923f4d1f 100644
--- a/packages/ckeditor5-engine/tests/view/observer/keyobserver.js
+++ b/packages/ckeditor5-engine/tests/view/observer/keyobserver.js
@@ -84,17 +84,28 @@ describe( 'KeyObserver', () => {
expect( getCode( data ) ).to.be.greaterThan( 111 );
} );
- it( 'should fire keydown ctrlKey set to true one meta (cmd) was pressed', () => {
+ it( 'should fire keydown with ctrlKey set to true once ctrl was pressed', () => {
const spy = sinon.spy();
viewDocument.on( 'keydown', spy );
- observer.onDomEvent( { type: 'keydown', target: document.body, keyCode: 111, metaKey: true } );
+ observer.onDomEvent( { type: 'keydown', target: document.body, keyCode: 111, ctrlKey: true } );
const data = spy.args[ 0 ][ 1 ];
expect( data ).to.have.property( 'ctrlKey', true );
} );
+ it( 'should fire keydown with metaKey set to true once meta (cmd) was pressed', () => {
+ const spy = sinon.spy();
+
+ viewDocument.on( 'keydown', spy );
+
+ observer.onDomEvent( { type: 'keydown', target: document.body, keyCode: 111, metaKey: true } );
+
+ const data = spy.args[ 0 ][ 1 ];
+ expect( data ).to.have.property( 'metaKey', true );
+ } );
+
it( 'should fire keyup with the target and key info', () => {
const spy = sinon.spy();
diff --git a/packages/ckeditor5-list/docs/features/todo-lists.md b/packages/ckeditor5-list/docs/features/todo-lists.md
index 6a7cceae5ce..92a0b45c499 100644
--- a/packages/ckeditor5-list/docs/features/todo-lists.md
+++ b/packages/ckeditor5-list/docs/features/todo-lists.md
@@ -16,7 +16,7 @@ To-do lists can be introduced using the dedicated toolbar button. Thanks to the
## Keyboard support
-You can check and uncheck a list item by using the Ctrl + Space shortcut when the selection is in that item.
+You can check and uncheck a list item by using the Ctrl + Enter (⌘ + Enter on Mac) shortcut when the selection is in that item.
## Installation
diff --git a/packages/ckeditor5-list/src/todolistediting.js b/packages/ckeditor5-list/src/todolistediting.js
index ccc6fb1dbad..a0a6d568cf8 100644
--- a/packages/ckeditor5-list/src/todolistediting.js
+++ b/packages/ckeditor5-list/src/todolistediting.js
@@ -8,7 +8,11 @@
*/
import { Plugin } from 'ckeditor5/src/core';
-import { getLocalizedArrowKeyCodeDirection } from 'ckeditor5/src/utils';
+import {
+ getCode,
+ parseKeystroke,
+ getLocalizedArrowKeyCodeDirection
+} from 'ckeditor5/src/utils';
import ListCommand from './listcommand';
import ListEditing from './listediting';
@@ -22,6 +26,8 @@ import {
modelViewInsertion
} from './todolistconverters';
+const ITEM_TOGGLE_KEYSTROKE = parseKeystroke( 'Ctrl+Enter' );
+
/**
* The engine of the to-do list feature. It handles creating, editing and removing to-do lists and their items.
*
@@ -113,7 +119,12 @@ export default class TodoListEditing extends Plugin {
this.listenTo( editing.view.document, 'keydown', jumpOverCheckmarkOnSideArrowKeyPress( model, editor.locale ) );
// Toggle check state of selected to-do list items on keystroke.
- editor.keystrokes.set( 'Ctrl+space', () => editor.execute( 'checkTodoList' ) );
+ this.listenTo( editing.view.document, 'keydown', ( evt, data ) => {
+ if ( getCode( data ) === ITEM_TOGGLE_KEYSTROKE ) {
+ editor.execute( 'checkTodoList' );
+ evt.stop();
+ }
+ }, { priority: 'high' } );
// Remove `todoListChecked` attribute when a host element is no longer a to-do list item.
const listItemsToFix = new Set();
diff --git a/packages/ckeditor5-list/tests/todolistediting.js b/packages/ckeditor5-list/tests/todolistediting.js
index e56df30fa23..0147faf5396 100644
--- a/packages/ckeditor5-list/tests/todolistediting.js
+++ b/packages/ckeditor5-list/tests/todolistediting.js
@@ -23,12 +23,16 @@ import { getData as getViewData } from '@ckeditor/ckeditor5-engine/src/dev-utils
import { getCode } from '@ckeditor/ckeditor5-utils/src/keyboard';
import { assertEqualMarkup } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';
+import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils';
+import { env } from '@ckeditor/ckeditor5-utils';
/* global Event, document */
describe( 'TodoListEditing', () => {
let editor, model, modelDoc, modelRoot, view, viewDoc;
+ testUtils.createSinonSandbox();
+
beforeEach( () => {
return VirtualTestEditor
.create( {
@@ -1154,30 +1158,55 @@ describe( 'TodoListEditing', () => {
sinon.assert.notCalled( domEvtDataStub.preventDefault );
sinon.assert.notCalled( domEvtDataStub.stopPropagation );
} );
+
+ it( 'should do nothing when other arrow key was pressed', () => {
+ setModelData( model, '[]bar' );
+
+ domEvtDataStub = {
+ keyCode: getCode( 'arrowDown' ),
+ preventDefault: sinon.spy(),
+ stopPropagation: sinon.spy(),
+ domTarget: {
+ ownerDocument: {
+ defaultView: {
+ getSelection: () => ( { rangeCount: 0 } )
+ }
+ }
+ }
+ };
+
+ viewDoc.fire( 'keydown', domEvtDataStub );
+
+ sinon.assert.notCalled( domEvtDataStub.preventDefault );
+ sinon.assert.notCalled( domEvtDataStub.stopPropagation );
+ } );
}
} );
- describe( 'Ctrl+space keystroke handling', () => {
- let domEvtDataStub;
+ describe( 'Ctrl+enter keystroke handling', () => {
+ it( 'should execute CheckTodoListCommand', () => {
+ const command = editor.commands.get( 'checkTodoList' );
+
+ sinon.spy( command, 'execute' );
- beforeEach( () => {
- domEvtDataStub = {
- keyCode: getCode( 'space' ),
- ctrlKey: true,
+ const domEvtDataStub = {
+ keyCode: getCode( 'enter' ),
preventDefault: sinon.spy(),
stopPropagation: sinon.spy()
};
- } );
- it( 'should execute CheckTodoListCommand', () => {
- const command = editor.commands.get( 'checkTodoList' );
-
- sinon.spy( command, 'execute' );
+ if ( env.isMac ) {
+ domEvtDataStub.metaKey = true;
+ } else {
+ domEvtDataStub.ctrlKey = true;
+ }
+ // First call.
viewDoc.fire( 'keydown', domEvtDataStub );
sinon.assert.calledOnce( command.execute );
+ // Second call.
viewDoc.fire( 'keydown', domEvtDataStub );
sinon.assert.calledTwice( command.execute );
diff --git a/packages/ckeditor5-typing/src/utils/injectunsafekeystrokeshandling.js b/packages/ckeditor5-typing/src/utils/injectunsafekeystrokeshandling.js
index 73183651c04..d133f020f40 100644
--- a/packages/ckeditor5-typing/src/utils/injectunsafekeystrokeshandling.js
+++ b/packages/ckeditor5-typing/src/utils/injectunsafekeystrokeshandling.js
@@ -171,8 +171,8 @@ for ( let code = 112; code <= 135; code++ ) {
* @returns {Boolean}
*/
export function isNonTypingKeystroke( keyData ) {
- // Keystrokes which contain Ctrl don't represent typing.
- if ( keyData.ctrlKey ) {
+ // Keystrokes which contain Ctrl or Cmd don't represent typing.
+ if ( keyData.ctrlKey || keyData.metaKey ) {
return true;
}
diff --git a/packages/ckeditor5-typing/tests/utils/injectunsafekeystrokeshandling.js b/packages/ckeditor5-typing/tests/utils/injectunsafekeystrokeshandling.js
index 01d5c8dcd10..4852162abd6 100644
--- a/packages/ckeditor5-typing/tests/utils/injectunsafekeystrokeshandling.js
+++ b/packages/ckeditor5-typing/tests/utils/injectunsafekeystrokeshandling.js
@@ -17,6 +17,11 @@ describe( 'unsafe keystroke handling utils', () => {
expect( isNonTypingKeystroke( { keyCode: keyCodes[ 0 ], ctrlKey: true } ), 'Ctrl+0' ).to.be.true;
} );
+ it( 'should return "true" for any keystroke with the Cmd key', () => {
+ expect( isNonTypingKeystroke( { keyCode: keyCodes.a, metaKey: true } ), '⌘a' ).to.be.true;
+ expect( isNonTypingKeystroke( { keyCode: keyCodes[ 0 ], metaKey: true } ), '⌘0' ).to.be.true;
+ } );
+
it( 'should return "true" for all arrow keys', () => {
expect( isNonTypingKeystroke( { keyCode: keyCodes.arrowup } ), 'arrow up' ).to.be.true;
expect( isNonTypingKeystroke( { keyCode: keyCodes.arrowdown } ), 'arrow down' ).to.be.true;
diff --git a/packages/ckeditor5-utils/src/keyboard.js b/packages/ckeditor5-utils/src/keyboard.js
index 1feda514de4..fdd2d41febd 100644
--- a/packages/ckeditor5-utils/src/keyboard.js
+++ b/packages/ckeditor5-utils/src/keyboard.js
@@ -12,16 +12,17 @@
import CKEditorError from './ckeditorerror';
import env from './env';
-const macGlyphsToModifiers = {
- '⌘': 'ctrl',
- '⇧': 'shift',
- '⌥': 'alt'
+const modifiersToGlyphsMac = {
+ ctrl: '⌃',
+ cmd: '⌘',
+ alt: '⌥',
+ shift: '⇧'
};
-const modifiersToMacGlyphs = {
- 'ctrl': '⌘',
- 'shift': '⇧',
- 'alt': '⌥'
+const modifiersToGlyphsNonMac = {
+ ctrl: 'Ctrl+',
+ alt: 'Alt+',
+ shift: 'Shift+'
};
/**
@@ -38,6 +39,10 @@ const modifiersToMacGlyphs = {
*/
export const keyCodes = generateKnownKeyCodes();
+const keyCodeNames = Object.fromEntries(
+ Object.entries( keyCodes ).map( ( [ name, code ] ) => [ code, name.charAt( 0 ).toUpperCase() + name.slice( 1 ) ] )
+);
+
/**
* Converts a key name or a {@link module:utils/keyboard~KeystrokeInfo keystroke info} into a key code.
*
@@ -66,7 +71,8 @@ export function getCode( key ) {
keyCode = key.keyCode +
( key.altKey ? keyCodes.alt : 0 ) +
( key.ctrlKey ? keyCodes.ctrl : 0 ) +
- ( key.shiftKey ? keyCodes.shift : 0 );
+ ( key.shiftKey ? keyCodes.shift : 0 ) +
+ ( key.metaKey ? keyCodes.cmd : 0 );
}
return keyCode;
@@ -96,7 +102,7 @@ export function parseKeystroke( keystroke ) {
}
return keystroke
- .map( key => ( typeof key == 'string' ) ? getCode( key ) : key )
+ .map( key => ( typeof key == 'string' ) ? getEnvKeyCode( key ) : key )
.reduce( ( key, sum ) => sum + key, 0 );
}
@@ -108,22 +114,21 @@ export function parseKeystroke( keystroke ) {
* @returns {String} Keystroke text specific for the environment.
*/
export function getEnvKeystrokeText( keystroke ) {
- if ( !env.isMac ) {
- return keystroke;
- }
+ let keystrokeCode = parseKeystroke( keystroke );
+
+ const modifiersToGlyphs = Object.entries( env.isMac ? modifiersToGlyphsMac : modifiersToGlyphsNonMac );
+
+ const modifiers = modifiersToGlyphs.reduce( ( modifiers, [ name, glyph ] ) => {
+ // Modifier keys are stored as a bit mask so extract those from the keystroke code.
+ if ( ( keystrokeCode & keyCodes[ name ] ) != 0 ) {
+ keystrokeCode &= ~keyCodes[ name ];
+ modifiers += glyph;
+ }
+
+ return modifiers;
+ }, '' );
- return splitKeystrokeText( keystroke )
- // Replace modifiers (e.g. "ctrl") with Mac glyphs (e.g. "⌘") first.
- .map( key => modifiersToMacGlyphs[ key.toLowerCase() ] || key )
-
- // Decide whether to put "+" between keys in the keystroke or not.
- .reduce( ( value, key ) => {
- if ( value.slice( -1 ) in macGlyphsToModifiers ) {
- return value + key;
- } else {
- return value + '+' + key;
- }
- } );
+ return modifiers + ( keystrokeCode ? keyCodeNames[ keystrokeCode ] : '' );
}
/**
@@ -169,6 +174,23 @@ export function getLocalizedArrowKeyCodeDirection( keyCode, contentLanguageDirec
}
}
+// Converts a key name to the key code with mapping based on the env.
+//
+// See: {@link module:utils/keyboard~getCode}.
+//
+// @param {String} key The key name (see {@link module:utils/keyboard~keyCodes}).
+// @returns {Number} Key code.
+function getEnvKeyCode( key ) {
+ // Don't remap modifier key for forced modifiers.
+ if ( key.endsWith( '!' ) ) {
+ return getCode( key.slice( 0, -1 ) );
+ }
+
+ const code = getCode( key );
+
+ return env.isMac && code == keyCodes.ctrl ? keyCodes.cmd : code;
+}
+
/**
* Determines if the provided key code moves the {@link module:engine/model/documentselection~DocumentSelection selection}
* forward or backward considering the language direction of the editor content.
@@ -203,11 +225,9 @@ function generateKnownKeyCodes() {
// The idea about these numbers is that they do not collide with any real key codes, so we can use them
// like bit masks.
ctrl: 0x110000,
- // Has the same code as ctrl, because their behaviour should be unified across the editor.
- // See http://ckeditor.github.io/editor-recommendations/general-policies#ctrl-vs-cmd
- cmd: 0x110000,
shift: 0x220000,
- alt: 0x440000
+ alt: 0x440000,
+ cmd: 0x880000
};
// a-z
@@ -249,17 +269,23 @@ function splitKeystrokeText( keystroke ) {
/**
* Whether the Alt modifier was pressed.
*
- * @member {Bolean} module:utils/keyboard~KeystrokeInfo#altKey
+ * @member {Boolean} module:utils/keyboard~KeystrokeInfo#altKey
*/
/**
- * Whether the Ctrl or Cmd modifier was pressed.
+ * Whether the Ctrl modifier was pressed.
*
- * @member {Bolean} module:utils/keyboard~KeystrokeInfo#ctrlKey
+ * @member {Boolean} module:utils/keyboard~KeystrokeInfo#ctrlKey
*/
/**
* Whether the Shift modifier was pressed.
*
- * @member {Bolean} module:utils/keyboard~KeystrokeInfo#shiftKey
+ * @member {Boolean} module:utils/keyboard~KeystrokeInfo#shiftKey
+ */
+
+/**
+ * Whether the Cmd modifier was pressed.
+ *
+ * @member {Boolean} module:utils/keyboard~KeystrokeInfo#metaKey
*/
diff --git a/packages/ckeditor5-utils/tests/keyboard.js b/packages/ckeditor5-utils/tests/keyboard.js
index d497a167c61..e7114906938 100644
--- a/packages/ckeditor5-utils/tests/keyboard.js
+++ b/packages/ckeditor5-utils/tests/keyboard.js
@@ -30,7 +30,7 @@ describe( 'Keyboard', () => {
it( 'modifiers and other keys', () => {
expect( keyCodes.delete ).to.equal( 46 );
expect( keyCodes.ctrl ).to.equal( 0x110000 );
- expect( keyCodes.cmd ).to.equal( 0x110000 );
+ expect( keyCodes.cmd ).to.equal( 0x880000 );
expect( keyCodes.f1 ).to.equal( 112 );
expect( keyCodes.f12 ).to.equal( 123 );
@@ -73,40 +73,96 @@ describe( 'Keyboard', () => {
} );
it( 'adds modifiers to the keystroke code', () => {
- expect( getCode( { keyCode: 48, altKey: true, ctrlKey: true, shiftKey: true } ) )
- .to.equal( 48 + 0x110000 + 0x220000 + 0x440000 );
+ expect( getCode( { keyCode: 48, altKey: true, ctrlKey: true, shiftKey: true, metaKey: true } ) )
+ .to.equal( 48 + 0x110000 + 0x220000 + 0x440000 + 0x880000 );
} );
} );
describe( 'parseKeystroke', () => {
- it( 'parses string', () => {
- expect( parseKeystroke( 'ctrl+a' ) ).to.equal( 0x110000 + 65 );
- } );
+ const initialEnvMac = env.isMac;
- it( 'allows spacing', () => {
- expect( parseKeystroke( 'ctrl + a' ) ).to.equal( 0x110000 + 65 );
+ afterEach( () => {
+ env.isMac = initialEnvMac;
} );
- it( 'is case-insensitive', () => {
- expect( parseKeystroke( 'Ctrl+A' ) ).to.equal( 0x110000 + 65 );
- } );
+ describe( 'on Macintosh', () => {
+ beforeEach( () => {
+ env.isMac = true;
+ } );
- it( 'works with an array', () => {
- expect( parseKeystroke( [ 'ctrl', 'a' ] ) ).to.equal( 0x110000 + 65 );
- } );
+ it( 'parses string', () => {
+ expect( parseKeystroke( 'ctrl+a' ) ).to.equal( 0x880000 + 65 );
+ } );
- it( 'works with an array which contains numbers', () => {
- expect( parseKeystroke( [ 'shift', 33 ] ) ).to.equal( 0x220000 + 33 );
- } );
+ it( 'allows spacing', () => {
+ expect( parseKeystroke( 'ctrl + a' ) ).to.equal( 0x880000 + 65 );
+ } );
+
+ it( 'is case-insensitive', () => {
+ expect( parseKeystroke( 'Ctrl+A' ) ).to.equal( 0x880000 + 65 );
+ } );
+
+ it( 'works with an array', () => {
+ expect( parseKeystroke( [ 'ctrl', 'a' ] ) ).to.equal( 0x880000 + 65 );
+ } );
+
+ it( 'works with an array which contains numbers', () => {
+ expect( parseKeystroke( [ 'shift', 33 ] ) ).to.equal( 0x220000 + 33 );
+ } );
+
+ it( 'works with two modifiers', () => {
+ expect( parseKeystroke( 'ctrl+shift+a' ) ).to.equal( 0x880000 + 0x220000 + 65 );
+ } );
- it( 'works with two modifiers', () => {
- expect( parseKeystroke( 'ctrl+shift+a' ) ).to.equal( 0x110000 + 0x220000 + 65 );
+ it( 'supports forced modifier', () => {
+ expect( parseKeystroke( 'ctrl!+a' ) ).to.equal( 0x110000 + 65 );
+ } );
+
+ it( 'throws on unknown name', () => {
+ expectToThrowCKEditorError( () => {
+ parseKeystroke( 'foo' );
+ }, 'keyboard-unknown-key', null );
+ } );
} );
- it( 'throws on unknown name', () => {
- expectToThrowCKEditorError( () => {
- parseKeystroke( 'foo' );
- }, 'keyboard-unknown-key', null );
+ describe( 'on non–Macintosh', () => {
+ beforeEach( () => {
+ env.isMac = false;
+ } );
+
+ it( 'parses string', () => {
+ expect( parseKeystroke( 'ctrl+a' ) ).to.equal( 0x110000 + 65 );
+ } );
+
+ it( 'allows spacing', () => {
+ expect( parseKeystroke( 'ctrl + a' ) ).to.equal( 0x110000 + 65 );
+ } );
+
+ it( 'is case-insensitive', () => {
+ expect( parseKeystroke( 'Ctrl+A' ) ).to.equal( 0x110000 + 65 );
+ } );
+
+ it( 'works with an array', () => {
+ expect( parseKeystroke( [ 'ctrl', 'a' ] ) ).to.equal( 0x110000 + 65 );
+ } );
+
+ it( 'works with an array which contains numbers', () => {
+ expect( parseKeystroke( [ 'shift', 33 ] ) ).to.equal( 0x220000 + 33 );
+ } );
+
+ it( 'works with two modifiers', () => {
+ expect( parseKeystroke( 'ctrl+shift+a' ) ).to.equal( 0x110000 + 0x220000 + 65 );
+ } );
+
+ it( 'supports forced modifier', () => {
+ expect( parseKeystroke( 'ctrl!+a' ) ).to.equal( 0x110000 + 65 );
+ } );
+
+ it( 'throws on unknown name', () => {
+ expectToThrowCKEditorError( () => {
+ parseKeystroke( 'foo' );
+ }, 'keyboard-unknown-key', null );
+ } );
} );
} );
@@ -128,6 +184,12 @@ describe( 'Keyboard', () => {
expect( getEnvKeystrokeText( 'ctrl+A' ) ).to.equal( '⌘A' );
} );
+ it( 'replaces CTRL! with ⌃', () => {
+ expect( getEnvKeystrokeText( 'CTRL!' ) ).to.equal( '⌃' );
+ expect( getEnvKeystrokeText( 'CTRL!+A' ) ).to.equal( '⌃A' );
+ expect( getEnvKeystrokeText( 'ctrl!+A' ) ).to.equal( '⌃A' );
+ } );
+
it( 'replaces SHIFT with ⇧', () => {
expect( getEnvKeystrokeText( 'SHIFT' ) ).to.equal( '⇧' );
expect( getEnvKeystrokeText( 'SHIFT+A' ) ).to.equal( '⇧A' );
@@ -145,11 +207,13 @@ describe( 'Keyboard', () => {
expect( getEnvKeystrokeText( 'ALT+SHIFT+X' ) ).to.equal( '⌥⇧X' );
} );
- it( 'does not touch other keys', () => {
- expect( getEnvKeystrokeText( 'ESC+A' ) ).to.equal( 'ESC+A' );
- expect( getEnvKeystrokeText( 'TAB' ) ).to.equal( 'TAB' );
+ it( 'normalizes value', () => {
+ expect( getEnvKeystrokeText( 'ESC' ) ).to.equal( 'Esc' );
+ expect( getEnvKeystrokeText( 'TAB' ) ).to.equal( 'Tab' );
expect( getEnvKeystrokeText( 'A' ) ).to.equal( 'A' );
- expect( getEnvKeystrokeText( 'A+CTRL+B' ) ).to.equal( 'A+⌘B' );
+ expect( getEnvKeystrokeText( 'a' ) ).to.equal( 'A' );
+ expect( getEnvKeystrokeText( 'CTRL+a' ) ).to.equal( '⌘A' );
+ expect( getEnvKeystrokeText( 'ctrl+b' ) ).to.equal( '⌘B' );
} );
} );
@@ -158,13 +222,18 @@ describe( 'Keyboard', () => {
env.isMac = false;
} );
- it( 'does not touch anything', () => {
- expect( getEnvKeystrokeText( 'CTRL+A' ) ).to.equal( 'CTRL+A' );
- expect( getEnvKeystrokeText( 'ctrl+A' ) ).to.equal( 'ctrl+A' );
- expect( getEnvKeystrokeText( 'SHIFT+A' ) ).to.equal( 'SHIFT+A' );
- expect( getEnvKeystrokeText( 'alt+A' ) ).to.equal( 'alt+A' );
- expect( getEnvKeystrokeText( 'CTRL+SHIFT+A' ) ).to.equal( 'CTRL+SHIFT+A' );
+ it( 'normalizes value', () => {
+ expect( getEnvKeystrokeText( 'ESC' ) ).to.equal( 'Esc' );
+ expect( getEnvKeystrokeText( 'TAB' ) ).to.equal( 'Tab' );
expect( getEnvKeystrokeText( 'A' ) ).to.equal( 'A' );
+ expect( getEnvKeystrokeText( 'a' ) ).to.equal( 'A' );
+ expect( getEnvKeystrokeText( 'CTRL+a' ) ).to.equal( 'Ctrl+A' );
+ expect( getEnvKeystrokeText( 'CTRL!+a' ) ).to.equal( 'Ctrl+A' );
+ expect( getEnvKeystrokeText( 'ctrl+b' ) ).to.equal( 'Ctrl+B' );
+ expect( getEnvKeystrokeText( 'ctrl!+b' ) ).to.equal( 'Ctrl+B' );
+ expect( getEnvKeystrokeText( 'SHIFT+A' ) ).to.equal( 'Shift+A' );
+ expect( getEnvKeystrokeText( 'alt+A' ) ).to.equal( 'Alt+A' );
+ expect( getEnvKeystrokeText( 'CTRL+SHIFT+A' ) ).to.equal( 'Ctrl+Shift+A' );
} );
} );
} );
diff --git a/packages/ckeditor5-utils/tests/keystrokehandler.js b/packages/ckeditor5-utils/tests/keystrokehandler.js
index 45bb5613043..7f77abfbcd9 100644
--- a/packages/ckeditor5-utils/tests/keystrokehandler.js
+++ b/packages/ckeditor5-utils/tests/keystrokehandler.js
@@ -6,17 +6,25 @@
import EmitterMixin from '../src/emittermixin';
import KeystrokeHandler from '../src/keystrokehandler';
import { keyCodes } from '../src/keyboard';
+import env from '../src/env';
describe( 'KeystrokeHandler', () => {
+ const initialEnvMac = env.isMac;
let emitter, keystrokes;
beforeEach( () => {
+ env.isMac = false;
+
emitter = Object.create( EmitterMixin );
keystrokes = new KeystrokeHandler();
keystrokes.listenTo( emitter );
} );
+ afterEach( () => {
+ env.isMac = initialEnvMac;
+ } );
+
describe( 'listenTo()', () => {
it( 'activates the listening on the emitter', () => {
const spy = sinon.spy();