2020-03-29 00:06:27 +03:00
|
|
|
/**
|
|
|
|
* Module for performing keyboard navigation.
|
|
|
|
* @module components/input/keyboardnavigation
|
|
|
|
*/
|
|
|
|
|
2020-05-04 12:44:12 +02:00
|
|
|
import inputManager from 'inputManager';
|
|
|
|
import layoutManager from 'layoutManager';
|
2020-03-19 21:20:47 -04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Key name mapping.
|
|
|
|
*/
|
|
|
|
const KeyNames = {
|
2020-05-04 12:44:12 +02:00
|
|
|
13: 'Enter',
|
|
|
|
19: 'Pause',
|
|
|
|
27: 'Escape',
|
|
|
|
32: 'Space',
|
|
|
|
37: 'ArrowLeft',
|
|
|
|
38: 'ArrowUp',
|
|
|
|
39: 'ArrowRight',
|
|
|
|
40: 'ArrowDown',
|
2020-03-19 21:20:47 -04:00
|
|
|
// MediaRewind (Tizen/WebOS)
|
2020-05-04 12:44:12 +02:00
|
|
|
412: 'MediaRewind',
|
2020-03-19 21:20:47 -04:00
|
|
|
// MediaStop (Tizen/WebOS)
|
2020-05-04 12:44:12 +02:00
|
|
|
413: 'MediaStop',
|
2020-03-19 21:20:47 -04:00
|
|
|
// MediaPlay (Tizen/WebOS)
|
2020-05-04 12:44:12 +02:00
|
|
|
415: 'MediaPlay',
|
2020-03-19 21:20:47 -04:00
|
|
|
// MediaFastForward (Tizen/WebOS)
|
2020-05-04 12:44:12 +02:00
|
|
|
417: 'MediaFastForward',
|
2020-03-19 21:20:47 -04:00
|
|
|
// Back (WebOS)
|
2020-05-04 12:44:12 +02:00
|
|
|
461: 'Back',
|
2020-03-19 21:20:47 -04:00
|
|
|
// Back (Tizen)
|
2020-05-04 12:44:12 +02:00
|
|
|
10009: 'Back',
|
2020-03-19 21:20:47 -04:00
|
|
|
// MediaTrackPrevious (Tizen)
|
2020-05-04 12:44:12 +02:00
|
|
|
10232: 'MediaTrackPrevious',
|
2020-03-19 21:20:47 -04:00
|
|
|
// MediaTrackNext (Tizen)
|
2020-05-04 12:44:12 +02:00
|
|
|
10233: 'MediaTrackNext',
|
2020-03-19 21:20:47 -04:00
|
|
|
// MediaPlayPause (Tizen)
|
2020-05-04 12:44:12 +02:00
|
|
|
10252: 'MediaPlayPause'
|
2020-03-19 21:20:47 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Keys used for keyboard navigation.
|
|
|
|
*/
|
2020-05-04 12:44:12 +02:00
|
|
|
const NavigationKeys = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'];
|
2020-03-19 21:20:47 -04:00
|
|
|
|
|
|
|
let hasFieldKey = false;
|
|
|
|
try {
|
2020-05-04 12:44:12 +02:00
|
|
|
hasFieldKey = 'key' in new KeyboardEvent('keydown');
|
2020-03-19 21:20:47 -04:00
|
|
|
} catch (e) {
|
|
|
|
console.error("error checking 'key' field");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!hasFieldKey) {
|
|
|
|
// Add [a..z]
|
|
|
|
for (let i = 65; i <= 90; i++) {
|
|
|
|
KeyNames[i] = String.fromCharCode(i).toLowerCase();
|
2020-01-19 01:09:42 +03:00
|
|
|
}
|
2020-03-19 21:20:47 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns key name from event.
|
|
|
|
*
|
2020-03-31 19:07:03 +03:00
|
|
|
* @param {KeyboardEvent} event - Keyboard event.
|
|
|
|
* @return {string} Key name.
|
2020-03-19 21:20:47 -04:00
|
|
|
*/
|
|
|
|
export function getKeyName(event) {
|
|
|
|
return KeyNames[event.keyCode] || event.key;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns _true_ if key is used for navigation.
|
|
|
|
*
|
2020-03-31 19:07:03 +03:00
|
|
|
* @param {string} key - Key name.
|
|
|
|
* @return {boolean} _true_ if key is used for navigation.
|
2020-03-19 21:20:47 -04:00
|
|
|
*/
|
|
|
|
export function isNavigationKey(key) {
|
|
|
|
return NavigationKeys.indexOf(key) != -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
export function enable() {
|
2020-05-04 12:44:12 +02:00
|
|
|
document.addEventListener('keydown', function (e) {
|
2020-03-19 21:20:47 -04:00
|
|
|
const key = getKeyName(e);
|
|
|
|
|
|
|
|
// Ignore navigation keys for non-TV
|
|
|
|
if (!layoutManager.tv && isNavigationKey(key)) {
|
|
|
|
return;
|
2020-01-19 01:09:42 +03:00
|
|
|
}
|
2020-01-17 12:05:56 +03:00
|
|
|
|
2020-03-19 21:20:47 -04:00
|
|
|
let capture = true;
|
|
|
|
|
|
|
|
switch (key) {
|
2020-05-04 12:44:12 +02:00
|
|
|
case 'ArrowLeft':
|
|
|
|
inputManager.handle('left');
|
2020-03-19 21:20:47 -04:00
|
|
|
break;
|
2020-05-04 12:44:12 +02:00
|
|
|
case 'ArrowUp':
|
|
|
|
inputManager.handle('up');
|
2020-03-19 21:20:47 -04:00
|
|
|
break;
|
2020-05-04 12:44:12 +02:00
|
|
|
case 'ArrowRight':
|
|
|
|
inputManager.handle('right');
|
2020-03-19 21:20:47 -04:00
|
|
|
break;
|
2020-05-04 12:44:12 +02:00
|
|
|
case 'ArrowDown':
|
|
|
|
inputManager.handle('down');
|
2020-03-19 21:20:47 -04:00
|
|
|
break;
|
|
|
|
|
2020-05-04 12:44:12 +02:00
|
|
|
case 'Back':
|
|
|
|
inputManager.handle('back');
|
2020-03-19 21:20:47 -04:00
|
|
|
break;
|
|
|
|
|
2020-05-04 12:44:12 +02:00
|
|
|
case 'Escape':
|
2020-03-19 21:20:47 -04:00
|
|
|
if (layoutManager.tv) {
|
2020-05-04 12:44:12 +02:00
|
|
|
inputManager.handle('back');
|
2020-03-19 21:20:47 -04:00
|
|
|
} else {
|
2019-11-23 00:29:38 +09:00
|
|
|
capture = false;
|
2020-03-19 21:20:47 -04:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2020-05-04 12:44:12 +02:00
|
|
|
case 'MediaPlay':
|
|
|
|
inputManager.handle('play');
|
2020-03-19 21:20:47 -04:00
|
|
|
break;
|
2020-05-04 12:44:12 +02:00
|
|
|
case 'Pause':
|
|
|
|
inputManager.handle('pause');
|
2020-03-19 21:20:47 -04:00
|
|
|
break;
|
2020-05-04 12:44:12 +02:00
|
|
|
case 'MediaPlayPause':
|
|
|
|
inputManager.handle('playpause');
|
2020-03-19 21:20:47 -04:00
|
|
|
break;
|
2020-05-04 12:44:12 +02:00
|
|
|
case 'MediaRewind':
|
|
|
|
inputManager.handle('rewind');
|
2020-03-19 21:20:47 -04:00
|
|
|
break;
|
2020-05-04 12:44:12 +02:00
|
|
|
case 'MediaFastForward':
|
|
|
|
inputManager.handle('fastforward');
|
2020-03-19 21:20:47 -04:00
|
|
|
break;
|
2020-05-04 12:44:12 +02:00
|
|
|
case 'MediaStop':
|
|
|
|
inputManager.handle('stop');
|
2020-03-19 21:20:47 -04:00
|
|
|
break;
|
2020-05-04 12:44:12 +02:00
|
|
|
case 'MediaTrackPrevious':
|
|
|
|
inputManager.handle('previoustrack');
|
2020-03-19 21:20:47 -04:00
|
|
|
break;
|
2020-05-04 12:44:12 +02:00
|
|
|
case 'MediaTrackNext':
|
|
|
|
inputManager.handle('nexttrack');
|
2020-03-19 21:20:47 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
capture = false;
|
|
|
|
}
|
2020-02-05 14:13:28 +01:00
|
|
|
|
2020-03-19 21:20:47 -04:00
|
|
|
if (capture) {
|
2020-05-04 12:44:12 +02:00
|
|
|
console.debug('disabling default event handling');
|
2020-03-19 21:20:47 -04:00
|
|
|
e.preventDefault();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
// Gamepad initialisation. No script is required if no gamepads are present at init time, saving a bit of resources.
|
|
|
|
// Whenever the gamepad is connected, we hand all the control of the gamepad to gamepadtokey.js by removing the event handler
|
|
|
|
function attachGamepadScript(e) {
|
2020-05-04 12:44:12 +02:00
|
|
|
console.log('Gamepad connected! Attaching gamepadtokey.js script');
|
|
|
|
window.removeEventListener('gamepadconnected', attachGamepadScript);
|
|
|
|
require(['scripts/gamepadtokey']);
|
2020-03-19 21:20:47 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// No need to check for gamepads manually at load time, the eventhandler will be fired for that
|
2020-04-04 21:29:53 +02:00
|
|
|
if (navigator.getGamepads) { /* eslint-disable-line compat/compat */
|
2020-05-04 12:44:12 +02:00
|
|
|
window.addEventListener('gamepadconnected', attachGamepadScript);
|
2020-04-04 21:29:53 +02:00
|
|
|
}
|
2020-03-29 00:06:27 +03:00
|
|
|
|
|
|
|
export default {
|
|
|
|
enable: enable,
|
|
|
|
getKeyName: getKeyName,
|
|
|
|
isNavigationKey: isNavigationKey
|
|
|
|
};
|