diff --git a/data/core.yaml b/data/core.yaml index 1ed815305..327c8f78d 100644 --- a/data/core.yaml +++ b/data/core.yaml @@ -1967,6 +1967,7 @@ en: enter: Enter esc: Esc home: Home + menu: Menu option: Option pause: Pause pgdn: PgDn diff --git a/data/shortcuts.json b/data/shortcuts.json index d9b595d79..fec11cba0 100644 --- a/data/shortcuts.json +++ b/data/shortcuts.json @@ -107,7 +107,7 @@ "text": "shortcuts.browsing.selecting.title" }, { - "shortcuts": ["Left-click"], + "shortcuts": ["Left-click", "shortcuts.key.space"], "text": "shortcuts.browsing.selecting.select_one" }, { @@ -131,7 +131,7 @@ "text": "shortcuts.browsing.with_selected.title" }, { - "shortcuts": ["Right-click", "shortcuts.key.space"], + "shortcuts": ["Right-click", "☰"], "text": "shortcuts.browsing.with_selected.edit_menu" }, { diff --git a/dist/locales/en.json b/dist/locales/en.json index 04722c333..5d4862394 100644 --- a/dist/locales/en.json +++ b/dist/locales/en.json @@ -2428,6 +2428,7 @@ "enter": "Enter", "esc": "Esc", "home": "Home", + "menu": "Menu", "option": "Option", "pause": "Pause", "pgdn": "PgDn", diff --git a/modules/behavior/select.js b/modules/behavior/select.js index 6c66802ae..359f5d89e 100644 --- a/modules/behavior/select.js +++ b/modules/behavior/select.js @@ -15,7 +15,7 @@ export function behaviorSelect(context) { // legacy option to show menu on every click var _alwaysShowMenu = +prefs('edit-menu-show-always') === 1; var _tolerancePx = 4; - var _lastMouse = null; + var _lastPointerEvent = null; var _showMenu = false; var _p1 = null; var _downPointerId = null; @@ -26,21 +26,35 @@ export function behaviorSelect(context) { var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse'; function point(event) { - return utilFastMouse(context.container().node())(event || d3_event); + // don't use map().mouse() since additional pointers unrelated to selection can + // move between pointerdown and pointerup + return utilFastMouse(context.map().supersurface.node())(event || d3_event); } function keydown() { + + if (d3_event.keyCode === 93 || // context menu key + d3_event.keyCode === 32) { // spacebar + d3_event.preventDefault(); + } + + if (d3_event.repeat) return; // ignore repeated events for held keys + + // if any key is pressed the user is probably doing something other than long-pressing if (_longPressTimeout) window.clearTimeout(_longPressTimeout); - var e = d3_event; - if (e && e.shiftKey) { + if (d3_event.shiftKey) { context.surface() .classed('behavior-multiselect', true); } - if (e && e.keyCode === 93) { // context menu - e.preventDefault(); + if (d3_event.keyCode === 32) { // spacebar + if (!_p1) { + _p1 = point(_lastPointerEvent); + if (_longPressTimeout) window.clearTimeout(_longPressTimeout); + _longPressTimeout = window.setTimeout(didLongPress, 500, 'spacebar'); + } } } @@ -48,31 +62,33 @@ export function behaviorSelect(context) { function keyup() { if (_longPressTimeout) window.clearTimeout(_longPressTimeout); - var e = d3_event; - if (!e || !e.shiftKey) { + if (!d3_event.shiftKey) { context.surface() .classed('behavior-multiselect', false); } - - if (e && e.keyCode === 93) { // context menu - e.preventDefault(); + if (d3_event.keyCode === 93) { // context menu key + d3_event.preventDefault(); _lastInteractionType = 'menukey'; contextmenu(); + } else if (d3_event.keyCode === 32) { // spacebar + d3_event.preventDefault(); + _lastInteractionType = 'spacebar'; + _showMenu = _alwaysShowMenu; + click(); } } function pointerdown() { if (_p1) return; - _p1 = point(); _downPointerId = d3_event.pointerId || 'mouse'; if (_longPressTimeout) window.clearTimeout(_longPressTimeout); - _longPressTimeout = window.setTimeout(didLongPress, 500, d3_event.pointerType || 'mouse'); + _longPressTimeout = window.setTimeout(didLongPress, 500, 'longdown-' + (d3_event.pointerType || 'mouse')); - _lastMouse = d3_event; + _lastPointerEvent = d3_event; d3_select(window) .on(_pointerPrefix + 'up.select', pointerup, true); @@ -81,9 +97,10 @@ export function behaviorSelect(context) { } - function didLongPress(pointerType) { + function didLongPress(iType) { + // treat long presses like right-clicks _longPressTimeout = null; - _lastInteractionType = 'longdown-' + pointerType; + _lastInteractionType = iType; _showMenu = true; click(); } @@ -92,7 +109,7 @@ export function behaviorSelect(context) { function pointermove() { if (_downPointerId && _downPointerId !== (d3_event.pointerId || 'mouse')) return; - _lastMouse = d3_event; + _lastPointerEvent = d3_event; } @@ -112,13 +129,13 @@ export function behaviorSelect(context) { e.preventDefault(); if (!+e.clientX && !+e.clientY) { - if (_lastMouse) { - e.sourceEvent = _lastMouse; + if (_lastPointerEvent) { + e.sourceEvent = _lastPointerEvent; } else { return; } } else { - _lastMouse = d3_event; + _lastPointerEvent = d3_event; _lastInteractionType = 'rightclick'; } @@ -134,12 +151,12 @@ export function behaviorSelect(context) { if (_longPressTimeout) window.clearTimeout(_longPressTimeout); if (!_p1) return; - var p2 = point(_lastMouse); + var p2 = point(_lastPointerEvent); var dist = geoVecLength(_p1, p2); _p1 = null; if (dist > _tolerancePx) return; - var datum = (d3_event && d3_event.target.__data__) || (_lastMouse && _lastMouse.target.__data__); + var datum = (d3_event && d3_event.target.__data__) || (_lastPointerEvent && _lastPointerEvent.target.__data__); var isMultiselect = (d3_event && d3_event.shiftKey) || context.surface().select('.lasso').node(); processClick(datum, isMultiselect); @@ -220,18 +237,24 @@ export function behaviorSelect(context) { } } - // reset for next time.. + resetProperties(); + } + + + function resetProperties() { _showMenu = false; + _p1 = null; + _downPointerId = null; + if (_longPressTimeout) window.clearTimeout(_longPressTimeout); + _longPressTimeout = null; + _lastInteractionType = null; + // don't reset _lastPointerEvent since it might still be useful } function behavior(selection) { - _lastMouse = null; - _showMenu = false; - _p1 = null; - _downPointerId = null; - _longPressTimeout = null; - _lastInteractionType = null; + resetProperties(); + _lastPointerEvent = context.map().lastPointerEvent(); d3_select(window) .on('keydown.select', keydown) diff --git a/modules/modes/select.js b/modules/modes/select.js index f5191e080..8fa27d0ad 100644 --- a/modules/modes/select.js +++ b/modules/modes/select.js @@ -184,15 +184,6 @@ export function modeSelect(context, selectedIDs) { }; - function spacebar() { // toggle the menu - if (context.map().supersurface.select('.edit-menu').empty()) { - mode.showMenu('spacebar'); - } else { - closeMenu(); - } - } - - mode.selectedIDs = function() { return selectedIDs; }; @@ -269,8 +260,7 @@ export function modeSelect(context, selectedIDs) { .on(['{', uiCmd('⌘['), 'home'], firstVertex) .on(['}', uiCmd('⌘]'), 'end'], lastVertex) .on(['\\', 'pause'], nextParent) - .on('⎋', esc, true) - .on('space', spacebar); + .on('⎋', esc, true); d3_select(document) .call(keybinding); diff --git a/modules/renderer/map.js b/modules/renderer/map.js index 084179aa5..648bd9f2b 100644 --- a/modules/renderer/map.js +++ b/modules/renderer/map.js @@ -684,6 +684,11 @@ export function rendererMap(context) { }; + map.lastPointerEvent = function() { + return _lastPointerEvent; + }; + + map.mouse = function() { var event = _lastPointerEvent || d3_event; if (event) { diff --git a/modules/ui/cmd.js b/modules/ui/cmd.js index 648ce3050..c2203adb1 100644 --- a/modules/ui/cmd.js +++ b/modules/ui/cmd.js @@ -55,6 +55,7 @@ uiCmd.display = function(code) { '⇟': mac ? '⇟ ' + t('shortcuts.key.end') : t('shortcuts.key.end'), '↵': mac ? '↵ ' + t('shortcuts.key.return') : t('shortcuts.key.enter'), '⎋': mac ? '⎋ ' + t('shortcuts.key.esc') : t('shortcuts.key.esc'), + '☰': mac ? '☰ ' + t('shortcuts.key.menu') : t('shortcuts.key.menu'), }; return replacements[code] || code;