feat: support remote media keys

close #273
This commit is contained in:
edde746
2026-01-24 16:53:39 +01:00
parent d31b4ab7a2
commit e11c7e3eed
@@ -1154,8 +1154,16 @@ class _PlexVideoControlsState extends State<PlexVideoControls> with WindowListen
/// Determine if the key event should toggle play/pause based on configured hotkeys.
bool _isPlayPauseKey(KeyEvent event) {
final logicalKey = event.logicalKey;
final physicalKey = event.physicalKey;
// Always accept hardware media play/pause keys (Android TV remotes)
if (logicalKey == LogicalKeyboardKey.mediaPlayPause ||
logicalKey == LogicalKeyboardKey.mediaPlay ||
logicalKey == LogicalKeyboardKey.mediaPause) {
return true;
}
// When the shortcuts service is available, respect the configured play/pause hotkey
if (_keyboardService != null) {
final hotkey = _keyboardService!.hotkeys['play_pause'];
@@ -1167,6 +1175,19 @@ class _PlexVideoControlsState extends State<PlexVideoControls> with WindowListen
return physicalKey == PhysicalKeyboardKey.space || physicalKey == PhysicalKeyboardKey.mediaPlayPause;
}
/// Check if a key is a media seek key (Android TV remotes)
bool _isMediaSeekKey(LogicalKeyboardKey key) {
return key == LogicalKeyboardKey.mediaFastForward ||
key == LogicalKeyboardKey.mediaRewind ||
key == LogicalKeyboardKey.mediaSkipForward ||
key == LogicalKeyboardKey.mediaSkipBackward;
}
/// Check if a key is a media track key (Android TV remotes)
bool _isMediaTrackKey(LogicalKeyboardKey key) {
return key == LogicalKeyboardKey.mediaTrackNext || key == LogicalKeyboardKey.mediaTrackPrevious;
}
bool _isPlayPauseActivation(KeyEvent event) {
return event is KeyDownEvent && _isPlayPauseKey(event);
}
@@ -1304,6 +1325,28 @@ class _PlexVideoControlsState extends State<PlexVideoControls> with WindowListen
return KeyEventResult.handled;
}
// Handle media seek keys (Android TV remotes)
// Uses chapter navigation if chapters are available, otherwise seeks by configured time
if (event is KeyDownEvent && _isMediaSeekKey(key)) {
if (widget.canControl) {
final isForward =
key == LogicalKeyboardKey.mediaFastForward || key == LogicalKeyboardKey.mediaSkipForward;
_seekToChapter(forward: isForward);
}
_showControlsWithFocus(requestFocus: _videoPlayerNavigationEnabled);
return KeyEventResult.handled;
}
// Handle next/previous track keys (Android TV remotes)
// Uses same behavior as seek keys: chapter navigation or time-based seek
if (event is KeyDownEvent && _isMediaTrackKey(key)) {
if (widget.canControl) {
_seekToChapter(forward: key == LogicalKeyboardKey.mediaTrackNext);
}
_showControlsWithFocus(requestFocus: _videoPlayerNavigationEnabled);
return KeyEventResult.handled;
}
// Handle Back/Escape: show controls if hidden, navigate back if visible
if (_isBackKey(key)) {
// On Windows/Linux with navigation off, ESC first exits fullscreen