mirror of
https://github.com/jellyfin/jellyfin-web
synced 2025-03-30 19:56:21 +00:00
Merge pull request #702 from dmitrylyzo/playback_remote
Add playback control from TV remote
This commit is contained in:
commit
7af58a03dd
4 changed files with 169 additions and 31 deletions
|
@ -1,36 +1,133 @@
|
||||||
define(['inputManager', 'focusManager'], function(inputManager, focusManager) {
|
define(["inputManager", "layoutManager"], function (inputManager, layoutManager) {
|
||||||
'use strict';
|
"use strict";
|
||||||
|
|
||||||
console.log("keyboardnavigation");
|
console.log("keyboardnavigation");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Key name mapping.
|
||||||
|
*/
|
||||||
|
// Add more to support old browsers
|
||||||
|
var KeyNames = {
|
||||||
|
13: "Enter",
|
||||||
|
19: "Pause",
|
||||||
|
27: "Escape",
|
||||||
|
32: "Space",
|
||||||
|
37: "ArrowLeft",
|
||||||
|
38: "ArrowUp",
|
||||||
|
39: "ArrowRight",
|
||||||
|
40: "ArrowDown",
|
||||||
|
// MediaRewind (Tizen/WebOS)
|
||||||
|
412: "MediaRewind",
|
||||||
|
// MediaStop (Tizen/WebOS)
|
||||||
|
413: "MediaStop",
|
||||||
|
// MediaPlay (Tizen/WebOS)
|
||||||
|
415: "MediaPlay",
|
||||||
|
// MediaFastForward (Tizen/WebOS)
|
||||||
|
417: "MediaFastForward",
|
||||||
|
// Back (WebOS)
|
||||||
|
461: "Back",
|
||||||
|
// Back (Tizen)
|
||||||
|
10009: "Back",
|
||||||
|
// MediaTrackPrevious (Tizen)
|
||||||
|
10232: "MediaTrackPrevious",
|
||||||
|
// MediaTrackNext (Tizen)
|
||||||
|
10233: "MediaTrackNext",
|
||||||
|
// MediaPlayPause (Tizen)
|
||||||
|
10252: "MediaPlayPause"
|
||||||
|
};
|
||||||
|
|
||||||
|
var hasFieldKey = false;
|
||||||
|
try {
|
||||||
|
hasFieldKey = "key" in new KeyboardEvent("keydown");
|
||||||
|
} catch (e) {
|
||||||
|
console.log("error checking 'key' field");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasFieldKey) {
|
||||||
|
// Add [a..z]
|
||||||
|
for (var i = 65; i <= 90; i++) {
|
||||||
|
KeyNames[i] = String.fromCharCode(i).toLowerCase();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns key name from event.
|
||||||
|
*
|
||||||
|
* @param {KeyboardEvent} keyboard event
|
||||||
|
* @return {string} key name
|
||||||
|
*/
|
||||||
|
function getKeyName(event) {
|
||||||
|
return KeyNames[event.keyCode] || event.key;
|
||||||
|
}
|
||||||
|
|
||||||
function enable() {
|
function enable() {
|
||||||
document.addEventListener('keydown', function(e) {
|
document.addEventListener("keydown", function (e) {
|
||||||
var capture = true;
|
var capture = true;
|
||||||
|
|
||||||
switch (e.keyCode) {
|
switch (getKeyName(e)) {
|
||||||
case 37: // ArrowLeft
|
case "ArrowLeft":
|
||||||
inputManager.handle('left');
|
inputManager.handle("left");
|
||||||
break;
|
break;
|
||||||
case 38: // ArrowUp
|
case "ArrowUp":
|
||||||
inputManager.handle('up');
|
inputManager.handle("up");
|
||||||
break;
|
break;
|
||||||
case 39: // ArrowRight
|
case "ArrowRight":
|
||||||
inputManager.handle('right');
|
inputManager.handle("right");
|
||||||
break;
|
break;
|
||||||
case 40: // ArrowDown
|
case "ArrowDown":
|
||||||
inputManager.handle('down');
|
inputManager.handle("down");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case "Back":
|
||||||
|
inputManager.handle("back");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "Escape":
|
||||||
|
if (layoutManager.tv) {
|
||||||
|
inputManager.handle("back");
|
||||||
|
} else {
|
||||||
|
capture = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "MediaPlay":
|
||||||
|
inputManager.handle("play");
|
||||||
|
break;
|
||||||
|
case "Pause":
|
||||||
|
inputManager.handle("pause");
|
||||||
|
break;
|
||||||
|
case "MediaPlayPause":
|
||||||
|
inputManager.handle("playpause");
|
||||||
|
break;
|
||||||
|
case "MediaRewind":
|
||||||
|
inputManager.handle("rewind");
|
||||||
|
break;
|
||||||
|
case "MediaFastForward":
|
||||||
|
inputManager.handle("fastforward");
|
||||||
|
break;
|
||||||
|
case "MediaStop":
|
||||||
|
inputManager.handle("stop");
|
||||||
|
break;
|
||||||
|
case "MediaTrackPrevious":
|
||||||
|
inputManager.handle("previoustrack");
|
||||||
|
break;
|
||||||
|
case "MediaTrackNext":
|
||||||
|
inputManager.handle("nexttrack");
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
capture = false;
|
capture = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (capture) {
|
if (capture) {
|
||||||
console.log("Disabling default event handling");
|
console.log("Disabling default event handling");
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
enable: enable
|
enable: enable,
|
||||||
|
getKeyName: getKeyName
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "mediaInfo", "focusManager", "imageLoader", "scrollHelper", "events", "connectionManager", "browser", "globalize", "apphost", "layoutManager", "userSettings", "scrollStyles", "emby-slider", "paper-icon-button-light", "css!assets/css/videoosd"], function (playbackManager, dom, inputManager, datetime, itemHelper, mediaInfo, focusManager, imageLoader, scrollHelper, events, connectionManager, browser, globalize, appHost, layoutManager, userSettings) {
|
define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "mediaInfo", "focusManager", "imageLoader", "scrollHelper", "events", "connectionManager", "browser", "globalize", "apphost", "layoutManager", "userSettings", "keyboardnavigation", "scrollStyles", "emby-slider", "paper-icon-button-light", "css!assets/css/videoosd"], function (playbackManager, dom, inputManager, datetime, itemHelper, mediaInfo, focusManager, imageLoader, scrollHelper, events, connectionManager, browser, globalize, appHost, layoutManager, userSettings, keyboardnavigation) {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
function seriesImageUrl(item, options) {
|
function seriesImageUrl(item, options) {
|
||||||
|
@ -437,6 +437,11 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med
|
||||||
});
|
});
|
||||||
currentVisibleMenu = null;
|
currentVisibleMenu = null;
|
||||||
toggleSubtitleSync("hide");
|
toggleSubtitleSync("hide");
|
||||||
|
|
||||||
|
// Firefox does not blur by itself
|
||||||
|
if (document.activeElement) {
|
||||||
|
document.activeElement.blur();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1087,50 +1092,66 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med
|
||||||
*/
|
*/
|
||||||
var NavigationKeys = ["ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown"];
|
var NavigationKeys = ["ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown"];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clicked element.
|
||||||
|
* To skip 'click' handling on Firefox/Edge.
|
||||||
|
*/
|
||||||
|
var clickedElement;
|
||||||
|
|
||||||
function onWindowKeyDown(e) {
|
function onWindowKeyDown(e) {
|
||||||
|
clickedElement = e.srcElement;
|
||||||
|
|
||||||
|
var key = keyboardnavigation.getKeyName(e);
|
||||||
|
|
||||||
if (!currentVisibleMenu && 32 === e.keyCode) {
|
if (!currentVisibleMenu && 32 === e.keyCode) {
|
||||||
playbackManager.playPause(currentPlayer);
|
playbackManager.playPause(currentPlayer);
|
||||||
showOsd();
|
showOsd();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (layoutManager.tv && NavigationKeys.indexOf(e.key) != -1) {
|
if (layoutManager.tv && NavigationKeys.indexOf(key) != -1) {
|
||||||
showOsd();
|
showOsd();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (e.key) {
|
switch (key) {
|
||||||
|
case "Enter":
|
||||||
|
showOsd();
|
||||||
|
break;
|
||||||
|
case "Escape":
|
||||||
|
case "Back":
|
||||||
|
// Ignore key when some dialog is opened
|
||||||
|
if (currentVisibleMenu === "osd" && !document.querySelector(".dialogContainer")) {
|
||||||
|
hideOsd();
|
||||||
|
e.stopPropagation();
|
||||||
|
}
|
||||||
|
break;
|
||||||
case "k":
|
case "k":
|
||||||
playbackManager.playPause(currentPlayer);
|
playbackManager.playPause(currentPlayer);
|
||||||
showOsd();
|
showOsd();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "l":
|
case "l":
|
||||||
case "ArrowRight":
|
case "ArrowRight":
|
||||||
case "Right":
|
case "Right":
|
||||||
playbackManager.fastForward(currentPlayer);
|
playbackManager.fastForward(currentPlayer);
|
||||||
showOsd();
|
showOsd();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "j":
|
case "j":
|
||||||
case "ArrowLeft":
|
case "ArrowLeft":
|
||||||
case "Left":
|
case "Left":
|
||||||
playbackManager.rewind(currentPlayer);
|
playbackManager.rewind(currentPlayer);
|
||||||
showOsd();
|
showOsd();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "f":
|
case "f":
|
||||||
if (!e.ctrlKey && !e.metaKey) {
|
if (!e.ctrlKey && !e.metaKey) {
|
||||||
playbackManager.toggleFullscreen(currentPlayer);
|
playbackManager.toggleFullscreen(currentPlayer);
|
||||||
showOsd();
|
showOsd();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "m":
|
case "m":
|
||||||
playbackManager.toggleMute(currentPlayer);
|
playbackManager.toggleMute(currentPlayer);
|
||||||
showOsd();
|
showOsd();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "NavigationLeft":
|
case "NavigationLeft":
|
||||||
case "GamepadDPadLeft":
|
case "GamepadDPadLeft":
|
||||||
case "GamepadLeftThumbstickLeft":
|
case "GamepadLeftThumbstickLeft":
|
||||||
|
@ -1140,7 +1161,6 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med
|
||||||
showOsd();
|
showOsd();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "NavigationRight":
|
case "NavigationRight":
|
||||||
case "GamepadDPadRight":
|
case "GamepadDPadRight":
|
||||||
case "GamepadLeftThumbstickRight":
|
case "GamepadLeftThumbstickRight":
|
||||||
|
@ -1152,6 +1172,14 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onWindowMouseDown(e) {
|
||||||
|
clickedElement = e.srcElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
function onWindowTouchStart(e) {
|
||||||
|
clickedElement = e.srcElement;
|
||||||
|
}
|
||||||
|
|
||||||
function getImgUrl(item, chapter, index, maxWidth, apiClient) {
|
function getImgUrl(item, chapter, index, maxWidth, apiClient) {
|
||||||
if (chapter.ImageTag) {
|
if (chapter.ImageTag) {
|
||||||
return apiClient.getScaledImageUrl(item.Id, {
|
return apiClient.getScaledImageUrl(item.Id, {
|
||||||
|
@ -1280,6 +1308,12 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med
|
||||||
showOsd();
|
showOsd();
|
||||||
inputManager.on(window, onInputCommand);
|
inputManager.on(window, onInputCommand);
|
||||||
dom.addEventListener(window, "keydown", onWindowKeyDown, {
|
dom.addEventListener(window, "keydown", onWindowKeyDown, {
|
||||||
|
capture: true
|
||||||
|
});
|
||||||
|
dom.addEventListener(window, window.PointerEvent ? "pointerdown" : "mousedown", onWindowMouseDown, {
|
||||||
|
passive: true
|
||||||
|
});
|
||||||
|
dom.addEventListener(window, "touchstart", onWindowTouchStart, {
|
||||||
passive: true
|
passive: true
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -1294,6 +1328,12 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med
|
||||||
}
|
}
|
||||||
|
|
||||||
dom.removeEventListener(window, "keydown", onWindowKeyDown, {
|
dom.removeEventListener(window, "keydown", onWindowKeyDown, {
|
||||||
|
capture: true
|
||||||
|
});
|
||||||
|
dom.removeEventListener(window, window.PointerEvent ? "pointerdown" : "mousedown", onWindowMouseDown, {
|
||||||
|
passive: true
|
||||||
|
});
|
||||||
|
dom.removeEventListener(window, "touchstart", onWindowTouchStart, {
|
||||||
passive: true
|
passive: true
|
||||||
});
|
});
|
||||||
stopOsdHideTimer();
|
stopOsdHideTimer();
|
||||||
|
@ -1465,7 +1505,10 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med
|
||||||
playbackManager.previousTrack(currentPlayer);
|
playbackManager.previousTrack(currentPlayer);
|
||||||
});
|
});
|
||||||
view.querySelector(".btnPause").addEventListener("click", function () {
|
view.querySelector(".btnPause").addEventListener("click", function () {
|
||||||
|
// Ignore 'click' if another element was originally clicked (Firefox/Edge issue)
|
||||||
|
if (this.contains(clickedElement)) {
|
||||||
playbackManager.playPause(currentPlayer);
|
playbackManager.playPause(currentPlayer);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
view.querySelector(".btnNextTrack").addEventListener("click", function () {
|
view.querySelector(".btnNextTrack").addEventListener("click", function () {
|
||||||
playbackManager.nextTrack(currentPlayer);
|
playbackManager.nextTrack(currentPlayer);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
define(['browser', 'dom', 'layoutManager', 'css!./emby-slider', 'registerElement', 'emby-input'], function (browser, dom, layoutManager) {
|
define(['browser', 'dom', 'layoutManager', 'keyboardnavigation', 'css!./emby-slider', 'registerElement', 'emby-input'], function (browser, dom, layoutManager, keyboardnavigation) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var EmbySliderPrototype = Object.create(HTMLInputElement.prototype);
|
var EmbySliderPrototype = Object.create(HTMLInputElement.prototype);
|
||||||
|
@ -250,7 +250,7 @@ define(['browser', 'dom', 'layoutManager', 'css!./emby-slider', 'registerElement
|
||||||
* Handle KeyDown event
|
* Handle KeyDown event
|
||||||
*/
|
*/
|
||||||
function onKeyDown(e) {
|
function onKeyDown(e) {
|
||||||
switch (e.key) {
|
switch (keyboardnavigation.getKeyName(e)) {
|
||||||
case 'ArrowLeft':
|
case 'ArrowLeft':
|
||||||
case 'Left':
|
case 'Left':
|
||||||
stepKeyboard(this, -this.keyboardStepDown || -1);
|
stepKeyboard(this, -this.keyboardStepDown || -1);
|
||||||
|
|
|
@ -22,9 +22,7 @@ define(['playbackManager', 'focusManager', 'appRouter', 'dom'], function (playba
|
||||||
|
|
||||||
var eventListenerCount = 0;
|
var eventListenerCount = 0;
|
||||||
function on(scope, fn) {
|
function on(scope, fn) {
|
||||||
if (eventListenerCount) {
|
|
||||||
eventListenerCount++;
|
eventListenerCount++;
|
||||||
}
|
|
||||||
dom.addEventListener(scope, 'command', fn, {});
|
dom.addEventListener(scope, 'command', fn, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue