/** * Copyright 2013 IBM Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. **/ RED.keyboard = (function() { var isMac = /Mac/i.test(window.navigator.platform); var handlers = {}; var partialState; var keyMap = { "left":37, "up":38, "right":39, "down":40, "escape":27, "enter": 13, "backspace": 8, "delete": 46, "space": 32, ";":186, "=":187, ",":188, "-":189, ".":190, "/":191, "\\":220, "'":222, "?":191 // <- QWERTY specific } var metaKeyCodes = { 16:true, 17:true, 18: true, 91:true, 93: true } var actionToKeyMap = {} // FF generates some different keycodes because reasons. var firefoxKeyCodeMap = { 59:186, 61:187, 173:189 } function init() { $.getJSON("red/keymap.json",function(data) { for (var scope in data) { if (data.hasOwnProperty(scope)) { var keys = data[scope]; for (var key in keys) { if (keys.hasOwnProperty(key)) { addHandler(scope,key,keys[key]); } } } } }) RED.actions.add("core:show-help", showKeyboardHelp); } function parseKeySpecifier(key) { var parts = key.toLowerCase().split("-"); var modifiers = {}; var keycode; var blank = 0; for (var i=0;i 1) { return null; } else { keycode = parts[i].toUpperCase().charCodeAt(0); } break; } } return [keycode,modifiers]; } function resolveKeyEvent(evt) { var slot = partialState||handlers; if (evt.ctrlKey || evt.metaKey) { slot = slot.ctrl; } if (slot && evt.shiftKey) { slot = slot.shift; } if (slot && evt.altKey) { slot = slot.alt; } var keyCode = firefoxKeyCodeMap[evt.keyCode] || evt.keyCode; if (slot && slot[keyCode]) { var handler = slot[keyCode]; if (!handler.scope) { if (partialState) { partialState = null; return resolveKeyEvent(evt); } else { partialState = handler; evt.preventDefault(); return null; } } else if (handler.scope && handler.scope !== "*") { var target = evt.target; while (target.nodeName !== 'BODY' && target.id !== handler.scope) { target = target.parentElement; } if (target.nodeName === 'BODY') { handler = null; } } partialState = null; return handler; } else if (partialState) { partialState = null; return resolveKeyEvent(evt); } } d3.select(window).on("keydown",function() { if (metaKeyCodes[d3.event.keyCode]) { return; } var handler = resolveKeyEvent(d3.event); if (handler && handler.ondown) { if (typeof handler.ondown === "string") { RED.actions.invoke(handler.ondown); } else { handler.ondown(); } d3.event.preventDefault(); } }); function addHandler(scope,key,modifiers,ondown) { var mod = modifiers; var cbdown = ondown; if (typeof modifiers == "function" || typeof modifiers === "string") { mod = {}; cbdown = modifiers; } var keys = []; var i=0; if (typeof key === 'string') { if (typeof cbdown === 'string') { actionToKeyMap[cbdown] = {scope:scope,key:key}; } var parts = key.split(" "); for (i=0;i'; function showKeyboardHelp() { if (!RED.settings.theme("menu.menu-item-keyboard-shortcuts",true)) { return; } if (!shortcutDialog) { shortcutDialog = $('
'+ '
    '+ '
    ') .appendTo("body"); var shortcutList = $('#keyboard-shortcut-list').editableList({ addButton: false, scrollOnAdd: false, addItem: function(container,i,object) { var item = $('
    ').appendTo(container); var key = $('
    ').appendTo(item); key.append(formatKey(object.key)); var text = object.id.replace(/(^.+:([a-z]))|(-([a-z]))/g,function(_,_,A,_,B,pos) { if (pos === 0) { return A.toUpperCase(); } else { return " "+B.toUpperCase(); } }); var label = $('
    ').html(text).appendTo(item); var scope = $('
    ').html(object.scope).appendTo(item); }, }); var shortcuts = RED.actions.list(); shortcuts.sort(function(A,B) { return A.id.localeCompare(B.id); }); shortcuts.forEach(function(s) { if (s.key) { shortcutList.editableList('addItem',s); } }) shortcutDialog.dialog({ modal: true, autoOpen: false, width: "800", height: "400", title:RED._("keyboard.title"), resizable: false }); } shortcutDialog.dialog("open"); } function formatKey(key) { var formattedKey = isMac?key.replace(/ctrl-?/,"⌘"):key; formattedKey = isMac?formattedKey.replace(/alt-?/,"⌥"):key; formattedKey = formattedKey.replace(/shift-?/,"⇧") formattedKey = formattedKey.replace(/left/,"←") formattedKey = formattedKey.replace(/up/,"↑") formattedKey = formattedKey.replace(/right/,"→") formattedKey = formattedKey.replace(/down/,"↓") return ''+formattedKey.split(" ").join(' ')+''; } return { init: init, add: addHandler, remove: removeHandler, getShortcut: function(actionName) { return actionToKeyMap[actionName]; }, formatKey: formatKey } })();