Issue #287 : Shortcuts now rely on Shortcut instances. Shortcut key can be changed dynamically.

This commit is contained in:
jdescottes 2015-10-10 19:32:25 +02:00
parent 8081d5e232
commit ca3bbf1c57
35 changed files with 597 additions and 185 deletions

View File

@ -62,9 +62,10 @@
$.subscribe(Events.USER_SETTINGS_CHANGED, this.onUserSettingsChange_.bind(this));
$.subscribe(Events.FRAME_SIZE_CHANGED, this.onFrameSizeChange_.bind(this));
pskl.app.shortcutService.registerShortcut('0', this.resetZoom_.bind(this));
pskl.app.shortcutService.registerShortcut('+', this.increaseZoom_.bind(this, 1));
pskl.app.shortcutService.registerShortcut('-', this.decreaseZoom_.bind(this, 1));
var shortcuts = pskl.service.keyboard.Shortcuts;
pskl.app.shortcutService.registerShortcut(shortcuts.MISC.RESET_ZOOM, this.resetZoom_.bind(this));
pskl.app.shortcutService.registerShortcut(shortcuts.MISC.INCREASE_ZOOM, this.increaseZoom_.bind(this, 1));
pskl.app.shortcutService.registerShortcut(shortcuts.MISC.DECREASE_ZOOM, this.decreaseZoom_.bind(this, 1));
window.setTimeout(function () {
this.afterWindowResize_();

View File

@ -5,6 +5,7 @@
ns.LayersListController = function (piskelController) {
this.piskelController = piskelController;
this.layerPreviewShortcut = pskl.service.keyboard.Shortcuts.MISC.LAYER_PREVIEW ;
};
ns.LayersListController.prototype.init = function () {
@ -36,10 +37,9 @@
var descriptors = [{description : 'Opacity defined in PREFERENCES'}];
var helpText = 'Preview all layers';
var toggleLayerPreviewTooltip = pskl.utils.TooltipFormatter.format(helpText, TOGGLE_LAYER_SHORTCUT, descriptors);
this.toggleLayerPreviewEl.setAttribute('title', toggleLayerPreviewTooltip);
pskl.app.shortcutService.registerShortcut(TOGGLE_LAYER_SHORTCUT, this.toggleLayerPreview_.bind(this));
pskl.app.shortcutService.registerShortcut(this.layerPreviewShortcut, this.toggleLayerPreview_.bind(this));
var tooltip = pskl.utils.TooltipFormatter.format(helpText, this.layerPreviewShortcut, descriptors);
this.toggleLayerPreviewEl.setAttribute('title', tooltip);
};
ns.LayersListController.prototype.updateButtonStatus_ = function () {

View File

@ -10,8 +10,9 @@
$.subscribe(Events.SELECT_PRIMARY_COLOR, this.onColorSelected_.bind(this, {isPrimary:true}));
$.subscribe(Events.SELECT_SECONDARY_COLOR, this.onColorSelected_.bind(this, {isPrimary:false}));
pskl.app.shortcutService.registerShortcut('X', this.swapColors.bind(this));
pskl.app.shortcutService.registerShortcut('D', this.resetColors.bind(this));
var shortcuts = pskl.service.keyboard.Shortcuts;
pskl.app.shortcutService.registerShortcut(shortcuts.COLOR.SWAP, this.swapColors.bind(this));
pskl.app.shortcutService.registerShortcut(shortcuts.COLOR.RESET, this.resetColors.bind(this));
var spectrumCfg = {
showPalette: true,

View File

@ -37,9 +37,10 @@
$.subscribe(Events.SECONDARY_COLOR_SELECTED, this.highlightSelectedColors.bind(this));
$.subscribe(Events.USER_SETTINGS_CHANGED, $.proxy(this.onUserSettingsChange_, this));
pskl.app.shortcutService.registerShortcuts(['>', 'shift+>'], this.selectNextColor_.bind(this));
pskl.app.shortcutService.registerShortcuts('123465789'.split(''), this.selectColorForKey_.bind(this));
pskl.app.shortcutService.registerShortcut('<', this.selectPreviousColor_.bind(this));
var shortcuts = pskl.service.keyboard.Shortcuts;
pskl.app.shortcutService.registerShortcut(shortcuts.COLOR.PREVIOUS_COLOR, this.selectPreviousColor_.bind(this));
pskl.app.shortcutService.registerShortcut(shortcuts.COLOR.NEXT_COLOR, this.selectNextColor_.bind(this));
pskl.app.shortcutService.registerShortcut(shortcuts.COLOR.SELECT_COLOR, this.selectColorForKey_.bind(this));
this.fillPaletteList();
this.updateFromUserSettings();

View File

@ -21,7 +21,7 @@
new pskl.tools.drawing.ColorPicker()
];
this.toolIconRenderer = new pskl.tools.IconMarkupRenderer();
this.iconMarkupRenderer = new pskl.tools.IconMarkupRenderer();
};
/**
@ -93,12 +93,10 @@
}
};
ns.ToolController.prototype.onKeyboardShortcut_ = function(charkey) {
for (var i = 0 ; i < this.tools.length ; i++) {
var tool = this.tools[i];
if (tool.shortcut.toLowerCase() === charkey.toLowerCase()) {
this.selectTool_(tool);
}
ns.ToolController.prototype.onKeyboardShortcut_ = function(toolId, charkey) {
var tool = this.getToolById_(toolId);
if (tool !== null) {
this.selectTool_(tool);
}
};
@ -115,14 +113,15 @@
var html = '';
for (var i = 0 ; i < this.tools.length ; i++) {
var tool = this.tools[i];
html += this.toolIconRenderer.render(tool, tool.shortcut);
html += this.iconMarkupRenderer.render(tool);
}
$('#tools-container').html(html);
};
ns.ToolController.prototype.addKeyboardShortcuts_ = function () {
for (var i = 0 ; i < this.tools.length ; i++) {
pskl.app.shortcutService.registerShortcut(this.tools[i].shortcut, this.onKeyboardShortcut_.bind(this));
var tool = this.tools[i];
pskl.app.shortcutService.registerShortcut(tool.shortcut, this.onKeyboardShortcut_.bind(this, tool.toolId));
}
};
})();

View File

@ -18,6 +18,7 @@
ns.DialogsController = function (piskelController) {
this.piskelController = piskelController;
this.closePopupShortcut = pskl.service.keyboard.Shortcuts.MISC.CLOSE_POPUP;
this.currentDialog_ = null;
};
@ -28,11 +29,16 @@
$.subscribe(Events.DIALOG_HIDE, this.onDialogHideEvent_.bind(this));
// TODO : JD : should be moved to a main controller
pskl.app.shortcutService.registerShortcut('alt+P', this.onDialogDisplayEvent_.bind(this, null, 'create-palette'));
var createPaletteShortcut = pskl.service.keyboard.Shortcuts.COLOR.CREATE_PALETTE;
pskl.app.shortcutService.registerShortcut(createPaletteShortcut, this.onCreatePaletteShortcut_.bind(this));
this.dialogWrapper_.classList.add('animated');
};
ns.DialogsController.prototype.onCreatePaletteShortcut_ = function () {
this.onDialogDisplayEvent_(null, 'create-palette');
};
ns.DialogsController.prototype.onDialogDisplayEvent_ = function (evt, args) {
var dialogId, initArgs;
if (typeof args === 'string') {
@ -66,7 +72,7 @@
};
ns.DialogsController.prototype.showDialogWrapper_ = function () {
pskl.app.shortcutService.registerShortcut('ESC', this.hideDialog.bind(this));
pskl.app.shortcutService.registerShortcut(this.closePopupShortcut, this.hideDialog.bind(this));
this.dialogWrapper_.classList.add('show');
};
@ -85,7 +91,7 @@
};
ns.DialogsController.prototype.hideDialogWrapper_ = function () {
pskl.app.shortcutService.unregisterShortcut('ESC');
pskl.app.shortcutService.unregisterShortcut(this.closePopupShortcut);
this.dialogWrapper_.classList.remove('show');
};

View File

@ -30,10 +30,11 @@
this.saveWrap_('moveLayerDown', true);
this.saveWrap_('removeCurrentLayer', true);
pskl.app.shortcutService.registerShortcut('up', this.selectPreviousFrame.bind(this));
pskl.app.shortcutService.registerShortcut('down', this.selectNextFrame.bind(this));
pskl.app.shortcutService.registerShortcut('n', this.addFrameAtCurrentIndex.bind(this));
pskl.app.shortcutService.registerShortcut('shift+n', this.duplicateCurrentFrame.bind(this));
var shortcuts = pskl.service.keyboard.Shortcuts;
pskl.app.shortcutService.registerShortcut(shortcuts.MISC.PREVIOUS_FRAME, this.selectPreviousFrame.bind(this));
pskl.app.shortcutService.registerShortcut(shortcuts.MISC.NEXT_FRAME, this.selectNextFrame.bind(this));
pskl.app.shortcutService.registerShortcut(shortcuts.MISC.NEW_FRAME, this.addFrameAtCurrentIndex.bind(this));
pskl.app.shortcutService.registerShortcut(shortcuts.MISC.DUPLICATE_FRAME, this.duplicateCurrentFrame.bind(this));
};
ns.PublicPiskelController.prototype.setPiskel = function (piskel, preserveState) {

View File

@ -14,6 +14,9 @@
this.elapsedTime = 0;
this.currentIndex = 0;
this.onionSkinShortcut = pskl.service.keyboard.Shortcuts.MISC.ONION_SKIN;
this.originalSizeShortcut = pskl.service.keyboard.Shortcuts.MISC.X1_PREVIEW;
this.renderFlag = true;
/**
@ -47,8 +50,8 @@
pskl.utils.Event.addEventListener(this.openPopupPreview, 'click', this.onOpenPopupPreviewClick_, this);
pskl.utils.Event.addEventListener(this.originalSizeButton, 'click', this.onOriginalSizeButtonClick_, this);
pskl.app.shortcutService.registerShortcut(ONION_SKIN_SHORTCUT, this.toggleOnionSkin_.bind(this));
pskl.app.shortcutService.registerShortcut(ORIGINAL_SIZE_SHORTCUT, this.onOriginalSizeButtonClick_.bind(this));
pskl.app.shortcutService.registerShortcut(this.onionSkinShortcut, this.toggleOnionSkin_.bind(this));
pskl.app.shortcutService.registerShortcut(this.originalSizeShortcut, this.onOriginalSizeButtonClick_.bind(this));
$.subscribe(Events.FRAME_SIZE_CHANGED, this.onFrameSizeChange_.bind(this));
$.subscribe(Events.USER_SETTINGS_CHANGED, $.proxy(this.onUserSettingsChange_, this));
@ -66,9 +69,9 @@
};
ns.PreviewController.prototype.initTooltips_ = function () {
var onionSkinTooltip = pskl.utils.TooltipFormatter.format('Toggle onion skin', ONION_SKIN_SHORTCUT);
var onionSkinTooltip = pskl.utils.TooltipFormatter.format('Toggle onion skin', this.onionSkinShortcut);
this.toggleOnionSkinButton.setAttribute('title', onionSkinTooltip);
var originalSizeTooltip = pskl.utils.TooltipFormatter.format('Original size preview', ORIGINAL_SIZE_SHORTCUT);
var originalSizeTooltip = pskl.utils.TooltipFormatter.format('Original size preview', this.originalSizeShortcut);
this.originalSizeButton.setAttribute('title', originalSizeTooltip);
};

View File

@ -18,11 +18,11 @@
$.subscribe(Events.SELECTION_DISMISSED, $.proxy(this.onSelectionDismissed_, this));
$.subscribe(Events.SELECTION_MOVE_REQUEST, $.proxy(this.onSelectionMoved_, this));
pskl.app.shortcutService.registerShortcut('ctrl+V', this.paste.bind(this));
pskl.app.shortcutService.registerShortcut('ctrl+X', this.cut.bind(this));
pskl.app.shortcutService.registerShortcut('ctrl+C', this.copy.bind(this));
pskl.app.shortcutService.registerShortcut('del', this.erase.bind(this));
pskl.app.shortcutService.registerShortcut('back', this.onBackPressed_.bind(this));
var shortcuts = pskl.service.keyboard.Shortcuts;
pskl.app.shortcutService.registerShortcut(shortcuts.SELECTION.PASTE, this.paste.bind(this));
pskl.app.shortcutService.registerShortcut(shortcuts.SELECTION.CUT, this.cut.bind(this));
pskl.app.shortcutService.registerShortcut(shortcuts.SELECTION.COPY, this.copy.bind(this));
pskl.app.shortcutService.registerShortcut(shortcuts.SELECTION.DELETE, this.onDeleteShortcut_.bind(this));
$.subscribe(Events.TOOL_SELECTED, $.proxy(this.onToolSelected_, this));
};
@ -54,7 +54,7 @@
this.cleanSelection_();
};
ns.SelectionManager.prototype.onBackPressed_ = function(evt) {
ns.SelectionManager.prototype.onDeleteShortcut_ = function(evt) {
if (this.currentSelection) {
this.erase();
} else {

View File

@ -26,8 +26,9 @@
ns.HistoryService.prototype.init = function () {
$.subscribe(Events.PISKEL_SAVE_STATE, this.onSaveStateEvent.bind(this));
this.shortcutService.registerShortcut('ctrl+Z', this.undo.bind(this));
this.shortcutService.registerShortcuts(['ctrl+Y', 'ctrl+shift+Z'] , this.redo.bind(this));
var shortcuts = pskl.service.keyboard.Shortcuts;
this.shortcutService.registerShortcut(shortcuts.MISC.UNDO, this.undo.bind(this));
this.shortcutService.registerShortcut(shortcuts.MISC.REDO, this.redo.bind(this));
this.saveState({
type : ns.HistoryService.SNAPSHOT

View File

@ -1,8 +1,13 @@
(function () {
var ns = $.namespace('pskl.service.keyboard');
/**
* TODO : JD : This is not a service, but a controller
* Moreover this should be handled by the DialogsController
*/
ns.CheatsheetService = function () {
this.isDisplayed = false;
this.closePopupShortcut = pskl.service.keyboard.Shortcuts.MISC.CLOSE_POPUP;
};
ns.CheatsheetService.prototype.init = function () {
@ -13,7 +18,9 @@
}
this.initMarkup_();
pskl.app.shortcutService.registerShortcuts(['?', 'shift+?'], this.toggleCheatsheet_.bind(this));
var cheatsheetShortcut = pskl.service.keyboard.Shortcuts.MISC.CHEATSHEET;
pskl.app.shortcutService.registerShortcut(cheatsheetShortcut, this.toggleCheatsheet_.bind(this));
pskl.utils.Event.addEventListener(document.body, 'click', this.onBodyClick_, this);
@ -46,13 +53,13 @@
};
ns.CheatsheetService.prototype.showCheatsheet_ = function () {
pskl.app.shortcutService.registerShortcut('ESC', this.hideCheatsheet_.bind(this));
pskl.app.shortcutService.registerShortcut(this.closePopupShortcut, this.hideCheatsheet_.bind(this));
this.cheatsheetEl.style.display = 'block';
this.isDisplayed = true;
};
ns.CheatsheetService.prototype.hideCheatsheet_ = function () {
pskl.app.shortcutService.unregisterShortcut('ESC');
pskl.app.shortcutService.unregisterShortcut(this.closePopupShortcut);
this.cheatsheetEl.style.display = 'none';
this.isDisplayed = false;
};
@ -65,71 +72,56 @@
};
ns.CheatsheetService.prototype.initMarkupForTools_ = function () {
var descriptors = pskl.app.toolController.tools.map(function (tool) {
return this.toDescriptor_(tool.shortcut, tool.getHelpText(), 'tool-icon ' + tool.toolId);
}.bind(this));
var descriptors = this.createShortcutDescriptors_(ns.Shortcuts.TOOL, this.getToolShortcutClassname_);
this.initMarkupForDescriptors_(descriptors, '.cheatsheet-tool-shortcuts');
};
var container = this.cheatsheetEl.querySelector('.cheatsheet-tool-shortcuts');
this.initMarkupForDescriptors_(descriptors, container);
ns.CheatsheetService.prototype.getToolShortcutClassname_ = function (shortcut) {
return 'tool-icon ' + shortcut.getId();
};
ns.CheatsheetService.prototype.initMarkupForMisc_ = function () {
var descriptors = [
this.toDescriptor_('0', 'Reset zoom level'),
this.toDescriptor_('+/-', 'Zoom in/Zoom out'),
this.toDescriptor_('ctrl + Z', 'Undo'),
this.toDescriptor_('ctrl + Y', 'Redo'),
this.toDescriptor_('&#65514;', 'Select previous frame'), /* ASCII for up-arrow */
this.toDescriptor_('&#65516;', 'Select next frame'), /* ASCII for down-arrow */
this.toDescriptor_('N', 'Create new frame'),
this.toDescriptor_('shift + N', 'Duplicate selected frame'),
this.toDescriptor_('shift + ?', 'Open/Close this popup'),
this.toDescriptor_('alt + 1', 'Toggle original size preview'),
this.toDescriptor_('alt + O', 'Toggle Onion Skin'),
this.toDescriptor_('alt + L', 'Toggle Layer Preview')
];
var container = this.cheatsheetEl.querySelector('.cheatsheet-misc-shortcuts');
this.initMarkupForDescriptors_(descriptors, container);
var descriptors = this.createShortcutDescriptors_(ns.Shortcuts.MISC);
this.initMarkupForDescriptors_(descriptors, '.cheatsheet-misc-shortcuts');
};
ns.CheatsheetService.prototype.initMarkupForColors_ = function () {
var descriptors = [
this.toDescriptor_('X', 'Swap primary/secondary colors'),
this.toDescriptor_('D', 'Reset default colors'),
this.toDescriptor_('alt + P', 'Create a Palette'),
this.toDescriptor_('&lt;/&gt;', 'Select prev/next palette color'),
this.toDescriptor_('1 to 9', 'Select palette color at index')
];
var container = this.cheatsheetEl.querySelector('.cheatsheet-colors-shortcuts');
this.initMarkupForDescriptors_(descriptors, container);
var descriptors = this.createShortcutDescriptors_(ns.Shortcuts.COLOR);
this.initMarkupForDescriptors_(descriptors, '.cheatsheet-colors-shortcuts');
};
ns.CheatsheetService.prototype.initMarkupForSelection_ = function () {
var descriptors = [
this.toDescriptor_('ctrl + X', 'Cut selection'),
this.toDescriptor_('ctrl + C', 'Copy selection'),
this.toDescriptor_('ctrl + V', 'Paste selection'),
this.toDescriptor_('del', 'Delete selection')
];
var container = this.cheatsheetEl.querySelector('.cheatsheet-selection-shortcuts');
this.initMarkupForDescriptors_(descriptors, container);
var descriptors = this.createShortcutDescriptors_(ns.Shortcuts.SELECTION);
this.initMarkupForDescriptors_(descriptors, '.cheatsheet-selection-shortcuts');
};
ns.CheatsheetService.prototype.toDescriptor_ = function (shortcut, description, icon) {
ns.CheatsheetService.prototype.createShortcutDescriptors_ = function (shortcutMap, classnameProvider) {
return Object.keys(shortcutMap).map(function (shortcutKey) {
var shortcut = shortcutMap[shortcutKey];
var classname = typeof classnameProvider == 'function' ? classnameProvider(shortcut) : '';
return this.toDescriptor_(shortcut.getKey(), shortcut.getDescription(), classname);
}.bind(this));
};
ns.CheatsheetService.prototype.toDescriptor_ = function (key, description, icon) {
if (pskl.utils.UserAgent.isMac) {
shortcut = shortcut.replace('ctrl', 'cmd');
key = key.replace('ctrl', 'cmd');
}
key = key.replace('up', '&#65514;');
key = key.replace('down', '&#65516;');
key = key.replace(/>/g, '&gt;');
key = key.replace(/</g, '&lt;');
key = key.replace(/^(.*[^ ])\+([^ ].*)$/g, '$1 + $2');
return {
'shortcut' : shortcut,
'key' : key,
'description' : description,
'icon' : icon
};
};
ns.CheatsheetService.prototype.initMarkupForDescriptors_ = function (descriptors, container) {
ns.CheatsheetService.prototype.initMarkupForDescriptors_ = function (descriptors, containerSelector) {
var container = this.cheatsheetEl.querySelector(containerSelector);
descriptors.forEach(function (descriptor) {
var shortcut = this.getDomFromDescriptor_(descriptor);
container.appendChild(shortcut);
@ -141,7 +133,7 @@
var markup = pskl.utils.Template.replace(shortcutTemplate, {
shortcutIcon : descriptor.icon,
shortcutDescription : descriptor.description,
shortcutKey : descriptor.shortcut
shortcutKey : descriptor.key
});
return pskl.utils.Template.createFromHTML(markup);

View File

@ -0,0 +1,60 @@
(function () {
var ns = $.namespace('pskl.service.keyboard');
/**
* Keyboard shortcut wrapper, use it to register on the ShortcutService.
*
* @param {String} id Shortcut identifier
* @param {String} description Shortcut description
* @param {String|Array<String>} defaultKey combination of modifiers + ([a-z0-9] or a special key)
* Special keys are defined in KeycodeTranslator. If the shortcut supports several keys,
* use an array of String keys
*/
ns.Shortcut = function (id, description, defaultKey, displayKey) {
this.id_ = id;
this.description_ = description;
this.defaultKey_ = defaultKey;
this.displayKey_ = displayKey;
};
ns.Shortcut.USER_SETTINGS_PREFIX = 'shortcut.';
ns.Shortcut.prototype.getId = function () {
return this.id_;
};
ns.Shortcut.prototype.getDescription = function () {
return this.description_;
};
/**
* Retrieve the array of String keys that match this shortcut
* @return {Array<String>} array of keys
*/
ns.Shortcut.prototype.getKeys = function () {
var keys = pskl.UserSettings.get(ns.Shortcut.USER_SETTINGS_PREFIX + this.id_) || this.defaultKey_;
if (typeof keys === 'string') {
keys = [keys];
}
return keys;
};
/**
* Get the key to be displayed for this shortcut, if
* @return {[type]} [description]
*/
ns.Shortcut.prototype.getKey = function () {
if (this.displayKey_) {
return this.displayKey_;
}
var keys = this.getKeys();
if (Array.isArray(keys) && keys.length > 0) {
return keys[0];
}
return '';
};
})();

View File

@ -2,7 +2,7 @@
var ns = $.namespace('pskl.service.keyboard');
ns.ShortcutService = function () {
this.shortcuts_ = {};
this.shortcuts_ = [];
};
/**
@ -14,43 +14,34 @@
/**
* Add a keyboard shortcut
* @param {String} rawKey (case insensitive) a key is a combination of modifiers + ([a-z0-9] or
* a special key) (check list of supported special keys in KeycodeTranslator)
* eg. 'ctrl+A',
* 'del'
* 'ctrl+shift+S'
* @param {pskl.service.keyboard.Shortcut} shortcut
* @param {Function} callback should return true to let the original event perform its default action
*/
ns.ShortcutService.prototype.registerShortcut = function (rawKey, callback) {
var parsedKey = this.parseKey_(rawKey.toLowerCase());
var key = parsedKey.key;
var meta = parsedKey.meta;
this.shortcuts_[key] = this.shortcuts_[key] || {};
if (this.shortcuts_[key][meta]) {
var keyStr = (meta !== 'normal' ? meta + ' + ' : '') + key;
console.error('[ShortcutService] >>> Shortcut [' + keyStr + '] already registered');
} else {
this.shortcuts_[key][meta] = callback;
ns.ShortcutService.prototype.registerShortcut = function (shortcut, callback) {
if (!(shortcut instanceof ns.Shortcut)) {
throw 'Invalid shortcut argument, please use instances of pskl.service.keyboard.Shortcut';
}
if (typeof callback != 'function') {
throw 'Invalid callback argument, please provide a function';
}
this.shortcuts_.push({
shortcut : shortcut,
callback : callback
});
};
ns.ShortcutService.prototype.registerShortcuts = function (keys, callback) {
keys.forEach(function (key) {
this.registerShortcut(key, callback);
}.bind(this));
};
ns.ShortcutService.prototype.unregisterShortcut = function (rawKey) {
var parsedKey = this.parseKey_(rawKey.toLowerCase());
var key = parsedKey.key;
var meta = parsedKey.meta;
this.shortcuts_[key] = this.shortcuts_[key] || {};
this.shortcuts_[key][meta] = null;
ns.ShortcutService.prototype.unregisterShortcut = function (shortcut) {
var index = -1;
this.shortcuts_.forEach(function (s, i) {
if (s.shortcut === shortcut) {
index = i;
}
});
if (index != -1) {
this.shortcuts_.splice(index, 1);
}
};
ns.ShortcutService.prototype.parseKey_ = function (key) {
@ -62,51 +53,58 @@
var parts = key.split(/\+(?!$)/);
key = parts[parts.length - 1];
return {meta : meta, key : key};
return {meta : meta, key : key.toLowerCase()};
};
/**
* Retrieve a comparable representation of a meta information for a key
* 'alt' 'ctrl' and 'shift' will always be in the same order for the same meta
*/
ns.ShortcutService.prototype.getMetaKey_ = function (meta) {
var keyBuffer = [];
['alt', 'ctrl', 'shift'].forEach(function (metaKey) {
if (meta[metaKey]) {
keyBuffer.push(metaKey);
}
});
if (keyBuffer.length > 0) {
return keyBuffer.join('+');
} else {
return 'normal';
if (meta.alt) {
keyBuffer.push('alt');
}
if (meta.ctrl) {
keyBuffer.push('ctrl');
}
if (meta.shift) {
keyBuffer.push('shift');
}
return keyBuffer.join('+') || 'normal';
};
/**
* @private
*/
ns.ShortcutService.prototype.onKeyUp_ = function(evt) {
if (!this.isInInput_(evt)) {
// jquery names FTW ...
var keycode = evt.which;
var charkey = pskl.service.keyboard.KeycodeTranslator.toChar(keycode);
var keyShortcuts = this.shortcuts_[charkey];
if (keyShortcuts) {
var meta = this.getMetaKey_({
alt : this.isAltKeyPressed_(evt),
shift : this.isShiftKeyPressed_(evt),
ctrl : this.isCtrlKeyPressed_(evt)
});
var cb = keyShortcuts[meta];
if (cb) {
var bubble = cb(charkey);
if (bubble !== true) {
evt.preventDefault();
}
$.publish(Events.KEYBOARD_EVENT, [evt]);
}
}
if (this.isInInput_(evt)) {
return;
}
var keycode = evt.which;
var eventKey = pskl.service.keyboard.KeycodeTranslator.toChar(keycode);
var eventMeta = this.getMetaKey_({
alt : evt.altKey,
shift : evt.shiftKey,
ctrl : this.isCtrlKeyPressed_(evt)
});
this.shortcuts_.forEach(function (shortcutInfo) {
shortcutInfo.shortcut.getKeys().forEach(function (key) {
if (!this.isKeyMatching_(key, eventKey, eventMeta)) {
return;
}
var bubble = shortcutInfo.callback(eventKey);
if (bubble !== true) {
evt.preventDefault();
}
$.publish(Events.KEYBOARD_EVENT, [evt]);
}.bind(this));
}.bind(this));
};
ns.ShortcutService.prototype.isInInput_ = function (evt) {
@ -114,15 +112,12 @@
return targetTagName === 'INPUT' || targetTagName === 'TEXTAREA';
};
ns.ShortcutService.prototype.isKeyMatching_ = function (key, eventKey, eventMeta) {
var parsedKey = this.parseKey_(key);
return parsedKey.key === eventKey && parsedKey.meta === eventMeta;
};
ns.ShortcutService.prototype.isCtrlKeyPressed_ = function (evt) {
return pskl.utils.UserAgent.isMac ? evt.metaKey : evt.ctrlKey;
};
ns.ShortcutService.prototype.isShiftKeyPressed_ = function (evt) {
return evt.shiftKey;
};
ns.ShortcutService.prototype.isAltKeyPressed_ = function (evt) {
return evt.altKey;
};
})();

View File

@ -0,0 +1,70 @@
(function () {
var ns = $.namespace('pskl.service.keyboard');
var createShortcut = function (id, description, defaultKey, displayKey) {
return new ns.Shortcut(id, description, defaultKey, displayKey);
};
ns.Shortcuts = {
/**
* Syntax : createShortcut(id, description, default key(s))
*/
TOOL : {
PEN : createShortcut('tool-pen', 'Pen tool', 'P'),
MIRROR_PEN : createShortcut('tool-vertical-mirror-pen', 'Vertical mirror pen tool', 'V'),
PAINT_BUCKET : createShortcut('tool-paint-bucket', 'Paint bucket tool', 'B'),
COLORSWAP : createShortcut('tool-colorswap', 'Magic bucket tool', 'A'),
ERASER : createShortcut('tool-eraser', 'Eraser pen tool', 'E'),
STROKE : createShortcut('tool-stroke', 'Stroke tool', 'L'),
RECTANGLE : createShortcut('tool-rectangle', 'Rectangle tool', 'R'),
CIRCLE : createShortcut('tool-circle', 'Circle tool', 'C'),
MOVE : createShortcut('tool-move', 'Move tool', 'M'),
SHAPE_SELECT : createShortcut('tool-shape-select', 'Shape selection', 'Z'),
RECTANGLE_SELECT : createShortcut('tool-rectangle-select', 'Rectangle selection', 'S'),
LASSO_SELECT : createShortcut('tool-lasso-select', 'Lasso selection', 'H'),
LIGHTEN : createShortcut('tool-lighten', 'Lighten tool', 'U'),
DITHERING : createShortcut('tool-dithering', 'Dithering tool', 'T'),
COLORPICKER : createShortcut('tool-colorpicker', 'Color picker', 'O')
},
SELECTION : {
CUT : createShortcut('selection-cut', 'Cut selection', 'ctrl+X'),
COPY : createShortcut('selection-copy', 'Copy selection', 'ctrl+C'),
PASTE : createShortcut('selection-cut', 'Paste selection', 'ctrl+V'),
DELETE : createShortcut('selection-delete', 'Delete selection', ['del', 'back'])
},
MISC : {
RESET_ZOOM : createShortcut('reset-zoom', 'Reset zoom level', '0'),
INCREASE_ZOOM : createShortcut('increase-zoom', 'Increase zoom level', '+'),
DECREASE_ZOOM : createShortcut('decrease-zoom', 'Decrease zoom level', '-'),
UNDO : createShortcut('undo', 'Undo', 'ctrl+Z'),
REDO : createShortcut('redo', 'Redo', ['ctrl+Y', 'ctrl+shift+Z']),
PREVIOUS_FRAME : createShortcut('previous-frame', 'Select previous frame', 'up'),
NEXT_FRAME : createShortcut('next-frame', 'Select next frame', 'down'),
NEW_FRAME : createShortcut('new-frame', 'Create new empty frame', 'N'),
DUPLICATE_FRAME : createShortcut('duplicate-frame', 'Duplicate selected frame', 'shift+N'),
CHEATSHEET : createShortcut('cheatsheet', 'Open the keyboard shortcut cheatsheet', 'shift+?'),
X1_PREVIEW : createShortcut('x1-preview', 'Toggle original size preview', 'alt+1'),
ONION_SKIN : createShortcut('onion-skin', 'Toggle onion skin', 'alt+O'),
LAYER_PREVIEW : createShortcut('layer-preview', 'Toggle layer preview', 'alt+L'),
CLOSE_POPUP : createShortcut('close-popup', 'Close an opened popup', 'ESC')
},
STORAGE : {
OPEN : createShortcut('open', '(Desktop only) Open a .piskel file', 'ctrl+O'),
SAVE : createShortcut('save', 'Save the current sprite', 'ctrl+S'),
SAVE_AS : createShortcut('save-as', '(Desktop only) Save as a new .piskel file', 'ctrl+shift+S')
},
COLOR : {
SWAP : createShortcut('swap-colors', 'Swap primary/secondary colors', 'X'),
RESET : createShortcut('reset-colors', 'Reset default colors', 'D'),
CREATE_PALETTE : createShortcut('create-palette', 'Open the palette creation popup', 'alt+P'),
PREVIOUS_COLOR : createShortcut('previous-color', 'Select the previous color in the current palette', '<'),
NEXT_COLOR : createShortcut('next-color', 'Select the next color in the current palette', '>'),
SELECT_COLOR : createShortcut('select-color', 'Select a palette color in the current palette',
'123456789'.split(''), '1 to 9')
}
};
})();

View File

@ -10,9 +10,10 @@
};
ns.StorageService.prototype.init = function () {
pskl.app.shortcutService.registerShortcut('ctrl+o', this.onOpenKey_.bind(this));
pskl.app.shortcutService.registerShortcut('ctrl+s', this.onSaveKey_.bind(this));
pskl.app.shortcutService.registerShortcut('ctrl+shift+s', this.onSaveAsKey_.bind(this));
var shortcuts = pskl.service.keyboard.Shortcuts;
pskl.app.shortcutService.registerShortcut(shortcuts.STORAGE.OPEN, this.onOpenKey_.bind(this));
pskl.app.shortcutService.registerShortcut(shortcuts.STORAGE.SAVE, this.onSaveKey_.bind(this));
pskl.app.shortcutService.registerShortcut(shortcuts.STORAGE.SAVE_AS, this.onSaveAsKey_.bind(this));
$.subscribe(Events.BEFORE_SAVING_PISKEL, this.setSavingFlag_.bind(this, true));
$.subscribe(Events.AFTER_SAVING_PISKEL, this.setSavingFlag_.bind(this, false));

View File

@ -3,19 +3,19 @@
ns.IconMarkupRenderer = function () {};
ns.IconMarkupRenderer.prototype.render = function (tool, shortcut, tooltipPosition) {
ns.IconMarkupRenderer.prototype.render = function (tool, tooltipPosition) {
tooltipPosition = tooltipPosition || 'right';
var tpl = pskl.utils.Template.get('drawingTool-item-template');
return pskl.utils.Template.replace(tpl, {
cssclass : ['tool-icon', tool.toolId].join(' '),
toolid : tool.toolId,
title : this.getTooltipText(tool, shortcut),
title : this.getTooltipText(tool),
tooltipposition : tooltipPosition
});
};
ns.IconMarkupRenderer.prototype.getTooltipText = function(tool, shortcut) {
ns.IconMarkupRenderer.prototype.getTooltipText = function(tool) {
var descriptors = tool.tooltipDescriptors;
return pskl.utils.TooltipFormatter.format(tool.getHelpText(), shortcut, descriptors);
return pskl.utils.TooltipFormatter.format(tool.getHelpText(), tool.shortcut, descriptors);
};
})();

View File

@ -11,7 +11,7 @@
this.toolId = 'tool-circle';
this.helpText = 'Circle tool';
this.shortcut = 'C';
this.shortcut = pskl.service.keyboard.Shortcuts.TOOL.CIRCLE;
};
pskl.utils.inherit(ns.Circle, ns.ShapeTool);

View File

@ -9,7 +9,7 @@
ns.ColorPicker = function() {
this.toolId = 'tool-colorpicker';
this.helpText = 'Color picker';
this.shortcut = 'O';
this.shortcut = pskl.service.keyboard.Shortcuts.TOOL.COLORPICKER;
};
pskl.utils.inherit(ns.ColorPicker, ns.BaseTool);

View File

@ -8,7 +8,7 @@
ns.ColorSwap = function() {
this.toolId = 'tool-colorswap';
this.helpText = 'Paint all pixels of the same color';
this.shortcut = 'A';
this.shortcut = pskl.service.keyboard.Shortcuts.TOOL.COLORSWAP;
this.tooltipDescriptors = [
{key : 'ctrl', description : 'Apply to all layers'},

View File

@ -10,7 +10,7 @@
ns.SimplePen.call(this);
this.toolId = 'tool-dithering';
this.helpText = 'Dithering tool';
this.shortcut = 'T';
this.shortcut = pskl.service.keyboard.Shortcuts.TOOL.DITHERING;
};
pskl.utils.inherit(ns.DitheringTool, ns.SimplePen);

View File

@ -12,7 +12,7 @@
this.toolId = 'tool-eraser';
this.helpText = 'Eraser tool';
this.shortcut = 'E';
this.shortcut = pskl.service.keyboard.Shortcuts.TOOL.ERASER;
};
pskl.utils.inherit(ns.Eraser, ns.SimplePen);

View File

@ -13,7 +13,7 @@
this.toolId = 'tool-lighten';
this.helpText = 'Lighten';
this.shortcut = 'U';
this.shortcut = pskl.service.keyboard.Shortcuts.TOOL.LIGHTEN;
this.tooltipDescriptors = [
{key : 'ctrl', description : 'Darken'},

View File

@ -9,7 +9,7 @@
ns.Move = function() {
this.toolId = ns.Move.TOOL_ID;
this.helpText = 'Move tool';
this.shortcut = 'M';
this.shortcut = pskl.service.keyboard.Shortcuts.TOOL.MOVE;
this.tooltipDescriptors = [
{key : 'ctrl', description : 'Apply to all layers'},

View File

@ -9,7 +9,7 @@
ns.PaintBucket = function() {
this.toolId = 'tool-paint-bucket';
this.helpText = 'Paint bucket tool';
this.shortcut = 'B';
this.shortcut = pskl.service.keyboard.Shortcuts.TOOL.PAINT_BUCKET;
};
pskl.utils.inherit(ns.PaintBucket, ns.BaseTool);

View File

@ -11,7 +11,7 @@
this.toolId = 'tool-rectangle';
this.helpText = 'Rectangle tool';
this.shortcut = 'R';
this.shortcut = pskl.service.keyboard.Shortcuts.TOOL.RECTANGLE;
};
pskl.utils.inherit(ns.Rectangle, ns.ShapeTool);

View File

@ -9,7 +9,7 @@
ns.SimplePen = function() {
this.toolId = 'tool-pen';
this.helpText = 'Pen tool';
this.shortcut = 'P';
this.shortcut = pskl.service.keyboard.Shortcuts.TOOL.PEN;
this.previousCol = null;
this.previousRow = null;

View File

@ -9,7 +9,7 @@
ns.Stroke = function() {
this.toolId = 'tool-stroke';
this.helpText = 'Stroke tool';
this.shortcut = 'L';
this.shortcut = pskl.service.keyboard.Shortcuts.TOOL.STROKE;
// Stroke's first point coordinates (set in applyToolAt)
this.startCol = null;

View File

@ -6,7 +6,7 @@
this.toolId = 'tool-vertical-mirror-pen';
this.helpText = 'Vertical Mirror pen';
this.shortcut = 'V';
this.shortcut = pskl.service.keyboard.Shortcuts.TOOL.MIRROR_PEN;
this.tooltipDescriptors = [
{key : 'ctrl', description : 'Use horizontal axis'},

View File

@ -11,7 +11,7 @@
this.toolId = 'tool-lasso-select';
this.helpText = 'Lasso selection';
this.shortcut = 'H';
this.shortcut = pskl.service.keyboard.Shortcuts.TOOL.LASSO_SELECT;
};
pskl.utils.inherit(ns.LassoSelect, ns.AbstractDragSelect);

View File

@ -11,7 +11,7 @@
this.toolId = 'tool-rectangle-select';
this.helpText = 'Rectangle selection';
this.shortcut = 'S';
this.shortcut = pskl.service.keyboard.Shortcuts.TOOL.RECTANGLE_SELECT;
};

View File

@ -11,7 +11,7 @@
this.toolId = 'tool-shape-select';
this.helpText = 'Shape selection';
this.shortcut = 'Z';
this.shortcut = pskl.service.keyboard.Shortcuts.TOOL.SHAPE_SELECT;
};
pskl.utils.inherit(ns.ShapeSelect, ns.BaseSelect);

View File

@ -5,7 +5,7 @@
ns.TooltipFormatter.format = function(helpText, shortcut, descriptors) {
var tpl = pskl.utils.Template.get('tooltip-container-template');
shortcut = shortcut ? '(' + shortcut + ')' : '';
shortcut = shortcut ? '(' + shortcut.getKey() + ')' : '';
return pskl.utils.Template.replace(tpl, {
helptext : helpText,
shortcut : shortcut,

View File

@ -91,6 +91,10 @@
* @private
*/
checkKeyValidity_ : function(key) {
if (key.indexOf(pskl.service.keyboard.Shortcut.USER_SETTINGS_PREFIX) === 0) {
return true;
}
var isValidKey = key in this.KEY_TO_DEFAULT_VALUE_MAP_;
if (!isValidKey) {
console.error('UserSettings key <' + key + '> not found in supported keys.');

View File

@ -157,6 +157,8 @@
"js/service/palette/reader/PaletteTxtReader.js",
"js/service/palette/PaletteImportService.js",
"js/service/SavedStatusService.js",
"js/service/keyboard/Shortcut.js",
"js/service/keyboard/Shortcuts.js",
"js/service/keyboard/ShortcutService.js",
"js/service/keyboard/KeycodeTranslator.js",
"js/service/keyboard/CheatsheetService.js",

View File

@ -0,0 +1,275 @@
describe("ShortcutService test suite", function() {
var A_KEY = 'A';
var B_KEY = 'B';
var A_KEYCODE = 65;
var B_KEYCODE = 66;
var service;
beforeEach(function() {
service = new pskl.service.keyboard.ShortcutService();
});
var createEvent = function (keycode) {
return {
which : keycode,
altKey : false,
withAltKey : function () {
this.altKey = true;
return this;
},
ctrlKey : false,
withCtrlKey : function () {
this.ctrlKey = true;
return this;
},
shiftKey : false,
withShiftKey : function () {
this.shiftKey = true;
return this;
},
preventDefaultCalled : false,
preventDefault : function () {
this.preventDefaultCalled = true;
},
target : {
nodeName : 'div'
},
setNodeName : function (nodeName) {
this.target.nodeName = nodeName;
return this;
}
};
};
var setTargetName = function (evt, targetName) {
evt.target = {
nodeName : targetName
};
};
it("accepts only shortcut instances", function() {
console.log('[ShortcutService] accepts only shortcut instances');
console.log('[ShortcutService] ... fails for missing shortcut');
expect(function () {
service.registerShortcut();
}).toThrow('Invalid shortcut argument, please use instances of pskl.service.keyboard.Shortcut');
console.log('[ShortcutService] ... fails for shortcut as empty object');
expect(function () {
service.registerShortcut({});
}).toThrow('Invalid shortcut argument, please use instances of pskl.service.keyboard.Shortcut');
console.log('[ShortcutService] ... fails for shortcut as a string');
expect(function () {
service.registerShortcut('alt+F4');
}).toThrow('Invalid shortcut argument, please use instances of pskl.service.keyboard.Shortcut');
var shortcut = new pskl.service.keyboard.Shortcut('shortcut-id', '', A_KEY);
console.log('[ShortcutService] ... fails for missing callback');
expect(function () {
service.registerShortcut(shortcut);
}).toThrow('Invalid callback argument, please provide a function');
console.log('[ShortcutService] ... fails for invalid callback');
expect(function () {
service.registerShortcut(shortcut, {callback : function () {}});
}).toThrow('Invalid callback argument, please provide a function');
console.log('[ShortcutService] ... is ok for valid arguments');
service.registerShortcut(shortcut, function () {});
});
it ("triggers shortcut", function () {
console.log('[ShortcutService] triggers shortcut');
var callbackCalled = false;
console.log('[ShortcutService] ... register shortcut for A');
var shortcutA = new pskl.service.keyboard.Shortcut('shortcut-a', '', A_KEY);
service.registerShortcut(shortcutA, function () {
callbackCalled = true;
});
console.log('[ShortcutService] ... verify shortcut is called');
service.onKeyUp_(createEvent(A_KEYCODE));
expect(callbackCalled).toBe(true);
});
it ("triggers shortcuts independently", function () {
console.log('[ShortcutService] registers shortcuts');
var shortcutA = new pskl.service.keyboard.Shortcut('shortcut-a', '', A_KEY);
var shortcutB = new pskl.service.keyboard.Shortcut('shortcut-b', '', B_KEY);
var shortcutA_B = new pskl.service.keyboard.Shortcut('shortcut-a&b', '', [A_KEY, B_KEY]);
var counters = {
a : 0,
b : 0,
a_b : 0
};
console.log('[ShortcutService] ... register separate shortcuts for A and B');
service.registerShortcut(shortcutA, function () {
counters.a++;
});
service.registerShortcut(shortcutB, function () {
counters.b++;
});
service.registerShortcut(shortcutA_B, function () {
counters.a_b++;
});
console.log('[ShortcutService] ... trigger A, expect counter A at 1, B at 0, A_B at 1');
service.onKeyUp_(createEvent(A_KEYCODE));
expect(counters.a).toBe(1);
expect(counters.b).toBe(0);
expect(counters.a_b).toBe(1);
console.log('[ShortcutService] ... trigger A, expect counter A at 1, B at 1, A_B at 2');
service.onKeyUp_(createEvent(B_KEYCODE));
expect(counters.a).toBe(1);
expect(counters.b).toBe(1);
expect(counters.a_b).toBe(2);
});
it ("unregisters shortcut", function () {
console.log('[ShortcutService] unregisters shortcut');
var callbackCalled = false;
console.log('[ShortcutService] ... register shortcut for A');
var shortcutA = new pskl.service.keyboard.Shortcut('shortcut-a', '', A_KEY);
service.registerShortcut(shortcutA, function () {
callbackCalled = true;
});
console.log('[ShortcutService] ... unregister shortcut A');
service.unregisterShortcut(shortcutA);
console.log('[ShortcutService] ... verify shortcut callback is not called');
service.onKeyUp_(createEvent(A_KEYCODE));
expect(callbackCalled).toBe(false);
});
it ("unregisters shortcut without removing other shortcuts", function () {
console.log('[ShortcutService] unregisters shortcut');
var callbackCalled = false;
console.log('[ShortcutService] ... register shortcut for A & B');
var shortcutA = new pskl.service.keyboard.Shortcut('shortcut-a', '', A_KEY);
var shortcutB = new pskl.service.keyboard.Shortcut('shortcut-b', '', B_KEY);
service.registerShortcut(shortcutA, function () {});
service.registerShortcut(shortcutB, function () {
callbackCalled = true;
});
console.log('[ShortcutService] ... unregister shortcut A');
service.unregisterShortcut(shortcutA);
console.log('[ShortcutService] ... verify shortcut callback for B can still be called');
service.onKeyUp_(createEvent(B_KEYCODE));
expect(callbackCalled).toBe(true);
});
it ("supports unregistering unknown shortcuts", function () {
console.log('[ShortcutService] unregisters shortcut');
var callbackCalled = false;
console.log('[ShortcutService] ... register shortcut for A');
var shortcutA = new pskl.service.keyboard.Shortcut('shortcut-a', '', A_KEY);
service.registerShortcut(shortcutA, function () {
callbackCalled = true;
});
console.log('[ShortcutService] ... unregister shortcut B, which was not registered in the first place');
var shortcutB = new pskl.service.keyboard.Shortcut('shortcut-b', '', B_KEY);
service.unregisterShortcut(shortcutB);
console.log('[ShortcutService] ... verify shortcut callback for A can still be called');
callbackCalled = false;
service.onKeyUp_(createEvent(A_KEYCODE));
expect(callbackCalled).toBe(true);
});
it ("does not trigger shortcuts from INPUT or TEXTAREA", function () {
console.log('[ShortcutService] triggers shortcut');
var callbackCalled = false;
console.log('[ShortcutService] ... register shortcut for A');
var shortcutA = new pskl.service.keyboard.Shortcut('shortcut-a', '', A_KEY);
service.registerShortcut(shortcutA, function () {
callbackCalled = true;
});
console.log('[ShortcutService] ... verify shortcut is not called from event on INPUT');
service.onKeyUp_(createEvent(A_KEYCODE).setNodeName('INPUT'));
expect(callbackCalled).toBe(false);
console.log('[ShortcutService] ... verify shortcut is not called from event on TEXTAREA');
service.onKeyUp_(createEvent(A_KEYCODE).setNodeName('TEXTAREA'));
expect(callbackCalled).toBe(false);
console.log('[ShortcutService] ... verify shortcut is called from event on LINK');
service.onKeyUp_(createEvent(A_KEYCODE).setNodeName('A'));
expect(callbackCalled).toBe(true);
});
it ("supports meta modifiers", function () {
console.log('[ShortcutService] triggers shortcut');
var callbackCalled = false;
console.log('[ShortcutService] ... create various A shortcuts with modifiers');
var shortcuts = [
new pskl.service.keyboard.Shortcut('a', '', A_KEY),
new pskl.service.keyboard.Shortcut('a_ctrl', '', 'ctrl+' + A_KEY),
new pskl.service.keyboard.Shortcut('a_ctrl_shift', '', 'ctrl+shift+' + A_KEY),
new pskl.service.keyboard.Shortcut('a_ctrl_shift_alt', '', 'ctrl+shift+alt+' + A_KEY),
new pskl.service.keyboard.Shortcut('a_alt', '', 'alt+' + A_KEY)
];
var counters = {
a : 0,
a_ctrl : 0,
a_ctrl_shift : 0,
a_ctrl_shift_alt : 0,
a_alt : 0,
};
shortcuts.forEach(function (shortcut) {
service.registerShortcut(shortcut, function () {
counters[shortcut.getId()]++;
});
});
var verifyCounters = function (a, a_c, a_cs, a_csa, a_a) {
expect(counters.a).toBe(a);
expect(counters.a_ctrl).toBe(a_c);
expect(counters.a_ctrl_shift).toBe(a_cs);
expect(counters.a_ctrl_shift_alt).toBe(a_csa);
expect(counters.a_alt).toBe(a_a);
};
console.log('[ShortcutService] ... trigger A, expect counters CTRL+A, CTRL+SHIFT+A, CTRL+SHIFT+ALT+A, ALT+A to remain at 0');
service.onKeyUp_(createEvent(A_KEYCODE));
verifyCounters(1,0,0,0,0);
console.log('[ShortcutService] ... trigger CTRL+A, expect counters CTRL+SHIFT+A, CTRL+SHIFT+ALT+A, ALT+A to remain at 0');
service.onKeyUp_(createEvent(A_KEYCODE).withCtrlKey());
verifyCounters(1,1,0,0,0);
console.log('[ShortcutService] ... trigger CTRL+A, expect counters CTRL+SHIFT+ALT+A, ALT+A to remain at 0');
service.onKeyUp_(createEvent(A_KEYCODE).withCtrlKey().withShiftKey());
verifyCounters(1,1,1,0,0);
console.log('[ShortcutService] ... trigger CTRL+A, expect counter ALT+A to remain at 0');
service.onKeyUp_(createEvent(A_KEYCODE).withCtrlKey().withShiftKey().withAltKey());
verifyCounters(1,1,1,1,0);
console.log('[ShortcutService] ... trigger CTRL+A, expect all counters at 1');
service.onKeyUp_(createEvent(A_KEYCODE).withAltKey());
verifyCounters(1,1,1,1,1);
});
});