зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1602841 - Implement keystroke handling for PiP window for video controls. r=mconley
This implements keystroke handling behind a pref "media.videocontrols.picture-in-picture.keyboard-controls.enabled". This patch handles all the keystrokes for video controls, which include play, pause, volume decrease and increase, mute, unmute, seek forward and backward for 15 seconds or by 10% of the max video duration, seek to beginning and seek to end. This reuses the key handler logic from https://searchfox.org/mozilla-central/rev/cfd1cc461f1efe0d66c2fdc17c024a203d5a2fd8/toolkit/content/widgets/videocontrols.js#1687-1810. Differential Revision: https://phabricator.services.mozilla.com/D60631 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
fb42ac6003
Коммит
aa684c0c76
|
@ -1497,6 +1497,8 @@ pref("media.autoplay.default", 1); // 0=Allowed, 1=Blocked, 5=All Blocked
|
|||
|
||||
pref("media.videocontrols.picture-in-picture.enabled", true);
|
||||
pref("media.videocontrols.picture-in-picture.video-toggle.enabled", true);
|
||||
// Enable keyboard controls for Picture-in-Picture.
|
||||
pref("media.videocontrols.picture-in-picture.keyboard-controls.enabled", true);
|
||||
|
||||
// Show the audio toggle for Picture-in-Picture.
|
||||
#ifdef NIGHTLY_BUILD
|
||||
|
|
|
@ -1108,6 +1108,10 @@ class PictureInPictureChild extends JSWindowActorChild {
|
|||
this.unmute();
|
||||
break;
|
||||
}
|
||||
case "PictureInPicture:KeyDown": {
|
||||
this.keyDown(message.data);
|
||||
break;
|
||||
}
|
||||
case "PictureInPicture:KeyToggle": {
|
||||
this.keyToggle();
|
||||
break;
|
||||
|
@ -1247,6 +1251,138 @@ class PictureInPictureChild extends JSWindowActorChild {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This reuses the keyHandler logic in the VideoControlsWidget
|
||||
* https://searchfox.org/mozilla-central/rev/cfd1cc461f1efe0d66c2fdc17c024a203d5a2fd8/toolkit/content/widgets/videocontrols.js#1687-1810.
|
||||
* There are future plans to eventually combine the two implementations.
|
||||
*/
|
||||
keyDown({ altKey, shiftKey, metaKey, ctrlKey, keyCode }) {
|
||||
let video = this.getWeakVideo();
|
||||
if (!video) {
|
||||
return;
|
||||
}
|
||||
|
||||
var keystroke = "";
|
||||
if (altKey) {
|
||||
keystroke += "alt-";
|
||||
}
|
||||
if (shiftKey) {
|
||||
keystroke += "shift-";
|
||||
}
|
||||
if (this.contentWindow.navigator.platform.startsWith("Mac")) {
|
||||
if (metaKey) {
|
||||
keystroke += "accel-";
|
||||
}
|
||||
if (ctrlKey) {
|
||||
keystroke += "control-";
|
||||
}
|
||||
} else {
|
||||
if (metaKey) {
|
||||
keystroke += "meta-";
|
||||
}
|
||||
if (ctrlKey) {
|
||||
keystroke += "accel-";
|
||||
}
|
||||
}
|
||||
|
||||
switch (keyCode) {
|
||||
case this.contentWindow.KeyEvent.DOM_VK_UP:
|
||||
keystroke += "upArrow";
|
||||
break;
|
||||
case this.contentWindow.KeyEvent.DOM_VK_DOWN:
|
||||
keystroke += "downArrow";
|
||||
break;
|
||||
case this.contentWindow.KeyEvent.DOM_VK_LEFT:
|
||||
keystroke += "leftArrow";
|
||||
break;
|
||||
case this.contentWindow.KeyEvent.DOM_VK_RIGHT:
|
||||
keystroke += "rightArrow";
|
||||
break;
|
||||
case this.contentWindow.KeyEvent.DOM_VK_HOME:
|
||||
keystroke += "home";
|
||||
break;
|
||||
case this.contentWindow.KeyEvent.DOM_VK_END:
|
||||
keystroke += "end";
|
||||
break;
|
||||
case this.contentWindow.KeyEvent.DOM_VK_SPACE:
|
||||
keystroke += "space";
|
||||
break;
|
||||
}
|
||||
|
||||
const isVideoStreaming = video.duration == +Infinity;
|
||||
var oldval, newval;
|
||||
|
||||
try {
|
||||
switch (keystroke) {
|
||||
case "space" /* Toggle Play / Pause */:
|
||||
if (video.paused || video.ended) {
|
||||
video.play();
|
||||
} else {
|
||||
video.pause();
|
||||
}
|
||||
break;
|
||||
case "downArrow" /* Volume decrease */:
|
||||
oldval = video.volume;
|
||||
video.volume = oldval < 0.1 ? 0 : oldval - 0.1;
|
||||
video.muted = false;
|
||||
break;
|
||||
case "upArrow" /* Volume increase */:
|
||||
oldval = video.volume;
|
||||
video.volume = oldval > 0.9 ? 1 : oldval + 0.1;
|
||||
video.muted = false;
|
||||
break;
|
||||
case "accel-downArrow" /* Mute */:
|
||||
video.muted = true;
|
||||
break;
|
||||
case "accel-upArrow" /* Unmute */:
|
||||
video.muted = false;
|
||||
break;
|
||||
case "leftArrow": /* Seek back 15 seconds */
|
||||
case "accel-leftArrow" /* Seek back 10% */:
|
||||
if (isVideoStreaming) {
|
||||
return;
|
||||
}
|
||||
|
||||
oldval = video.currentTime;
|
||||
if (keystroke == "leftArrow") {
|
||||
newval = oldval - 15;
|
||||
} else {
|
||||
newval = oldval - video.duration / 10;
|
||||
}
|
||||
video.currentTime = newval >= 0 ? newval : 0;
|
||||
break;
|
||||
case "rightArrow": /* Seek forward 15 seconds */
|
||||
case "accel-rightArrow" /* Seek forward 10% */:
|
||||
if (isVideoStreaming) {
|
||||
return;
|
||||
}
|
||||
|
||||
oldval = video.currentTime;
|
||||
var maxtime = video.duration;
|
||||
if (keystroke == "rightArrow") {
|
||||
newval = oldval + 15;
|
||||
} else {
|
||||
newval = oldval + maxtime / 10;
|
||||
}
|
||||
video.currentTime = newval <= maxtime ? newval : maxtime;
|
||||
break;
|
||||
case "home" /* Seek to beginning */:
|
||||
if (!isVideoStreaming) {
|
||||
video.currentTime = 0;
|
||||
}
|
||||
break;
|
||||
case "end" /* Seek to end */:
|
||||
if (!isVideoStreaming && video.currentTime != video.duration) {
|
||||
video.currentTime = video.duration;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
}
|
||||
} catch (e) {
|
||||
/* ignore any exception from setting video.currentTime */
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The keyboard was used to attempt to open Picture-in-Picture. In this case,
|
||||
* find the focused window, and open Picture-in-Picture for the first
|
||||
|
|
|
@ -15,6 +15,8 @@ const { AppConstants } = ChromeUtils.import(
|
|||
|
||||
const AUDIO_TOGGLE_ENABLED_PREF =
|
||||
"media.videocontrols.picture-in-picture.audio-toggle.enabled";
|
||||
const KEYBOARD_CONTROLS_ENABLED_PREF =
|
||||
"media.videocontrols.picture-in-picture.keyboard-controls.enabled";
|
||||
|
||||
// Time to fade the Picture-in-Picture video controls after first opening.
|
||||
const CONTROLS_FADE_TIMEOUT_MS = 3000;
|
||||
|
@ -172,9 +174,22 @@ let Player = {
|
|||
case "keydown": {
|
||||
if (event.keyCode == KeyEvent.DOM_VK_TAB) {
|
||||
this.controls.setAttribute("keying", true);
|
||||
} else if (event.keyCode == KeyEvent.DOM_VK_ESCAPE) {
|
||||
} else if (
|
||||
event.keyCode == KeyEvent.DOM_VK_ESCAPE &&
|
||||
this.controls.hasAttribute("keying")
|
||||
) {
|
||||
this.controls.removeAttribute("keying");
|
||||
} else if (
|
||||
Services.prefs.getBoolPref(KEYBOARD_CONTROLS_ENABLED_PREF, false) &&
|
||||
!this.controls.hasAttribute("keying") &&
|
||||
(event.keyCode != KeyEvent.DOM_VK_SPACE || !event.target.id)
|
||||
) {
|
||||
// Pressing "space" fires a "keydown" event which can also trigger a control
|
||||
// button's "click" event. Handle the "keydown" event only when the event did
|
||||
// not originate from a control button and it is not a "space" keypress.
|
||||
this.onKeyDown(event);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -235,6 +250,16 @@ let Player = {
|
|||
}
|
||||
},
|
||||
|
||||
onKeyDown(event) {
|
||||
this.actor.sendAsyncMessage("PictureInPicture:KeyDown", {
|
||||
altKey: event.altKey,
|
||||
shiftKey: event.shiftKey,
|
||||
metaKey: event.metaKey,
|
||||
ctrlKey: event.ctrlKey,
|
||||
keyCode: event.keyCode,
|
||||
});
|
||||
},
|
||||
|
||||
onMouseOut(event) {
|
||||
if (
|
||||
window.screenX != this.lastScreenX ||
|
||||
|
|
Загрузка…
Ссылка в новой задаче