renative
renative copied to clipboard
Bind keys to TV remote
Hi
What is the process to bind keys on the TV remote to control the video player - eg play/pause/seek using renative?
https://video-react.js.org/components/player/
thanks
import React, { Component } from 'react';
import Prism from 'prismjs'
import { PrismCode } from 'react-prism';
import { Player, ControlBar } from 'video-react';
import { Button } from 'reactstrap';
const sources = {
sintelTrailer: 'http://media.w3.org/2010/05/sintel/trailer.mp4',
bunnyTrailer: 'http://media.w3.org/2010/05/bunny/trailer.mp4',
bunnyMovie: 'http://media.w3.org/2010/05/bunny/movie.mp4',
test: 'http://media.w3.org/2010/05/video/movie_300.webm'
};
export default class VideoPlayer extends Component {
constructor(props, context) {
super(props, context);
this.state = {
source: sources.bunnyMovie
};
this.play = this.play.bind(this);
this.pause = this.pause.bind(this);
this.load = this.load.bind(this);
this.changeCurrentTime = this.changeCurrentTime.bind(this);
this.seek = this.seek.bind(this);
this.changePlaybackRateRate = this.changePlaybackRateRate.bind(this);
this.changeVolume = this.changeVolume.bind(this);
this.setMuted = this.setMuted.bind(this);
}
componentDidMount() {
// subscribe state change
this.player.subscribeToStateChange(this.handleStateChange.bind(this));
}
setMuted(muted) {
return () => {
this.player.muted = muted;
};
}
handleStateChange(state) {
// copy player state to this component's state
this.setState({
player: state
});
}
play() {
this.player.play();
}
pause() {
this.player.pause();
}
load() {
this.player.load();
}
changeCurrentTime(seconds) {
return () => {
const { player } = this.player.getState();
this.player.seek(player.currentTime + seconds);
};
}
seek(seconds) {
return () => {
this.player.seek(seconds);
};
}
changePlaybackRateRate(steps) {
return () => {
const { player } = this.player.getState();
this.player.playbackRate = player.playbackRate + steps;
};
}
changeVolume(steps) {
return () => {
const { player } = this.player.getState();
this.player.volume = player.volume + steps;
};
}
changeSource(name) {
return () => {
this.setState({
source: sources[name]
});
this.player.load();
};
}
render() {
return (
<div>
<Player
ref={player => {
this.player = player;
}}
autoPlay
>
<source src={this.state.source} />
<ControlBar autoHide={false} />
</Player>
<div className="py-3">
<Button onClick={this.play} className="mr-3">
play()
</Button>
<Button onClick={this.pause} className="mr-3">
pause()
</Button>
<Button onClick={this.load} className="mr-3">
load()
</Button>
</div>
<div className="pb-3">
<Button onClick={this.changeCurrentTime(10)} className="mr-3">
currentTime += 10
</Button>
<Button onClick={this.changeCurrentTime(-10)} className="mr-3">
currentTime -= 10
</Button>
<Button onClick={this.seek(50)} className="mr-3">
currentTime = 50
</Button>
</div>
<div className="pb-3">
<Button onClick={this.changePlaybackRateRate(1)} className="mr-3">
playbackRate++
</Button>
<Button onClick={this.changePlaybackRateRate(-1)} className="mr-3">
playbackRate--
</Button>
<Button onClick={this.changePlaybackRateRate(0.1)} className="mr-3">
playbackRate+=0.1
</Button>
<Button onClick={this.changePlaybackRateRate(-0.1)} className="mr-3">
playbackRate-=0.1
</Button>
</div>
<div className="pb-3">
<Button onClick={this.changeVolume(0.1)} className="mr-3">
volume+=0.1
</Button>
<Button onClick={this.changeVolume(-0.1)} className="mr-3">
volume-=0.1
</Button>
<Button onClick={this.setMuted(true)} className="mr-3">
muted=true
</Button>
<Button onClick={this.setMuted(false)} className="mr-3">
muted=false
</Button>
</div>
<div className="pb-3">
<Button onClick={this.changeSource('sintelTrailer')} className="mr-3">
Sintel teaser
</Button>
<Button onClick={this.changeSource('bunnyTrailer')} className="mr-3">
Bunny trailer
</Button>
<Button onClick={this.changeSource('bunnyMovie')} className="mr-3">
Bunny movie
</Button>
<Button onClick={this.changeSource('test')} className="mr-3">
Test movie
</Button>
</div>
<div>State</div>
<pre>
<PrismCode className="language-json">
{JSON.stringify(this.state.player, null, 2)}
</PrismCode>
</pre>
</div>
);
}
}
Ok I created a simple page to try and see if I can access the tizen API and it seems tizen variable is undefined which means I cannot access the binding functionality via the renative wrapper. This is my simple code
import React, { Component } from "react";
import { StyleSheet, Text, View } from "react-native";
export default class App extends Component {
constructor(props, context) {
super(props, context);
this.keyCode = "Initial";
}
componentDidMount() {
window.addEventListener('keydown', this.onKeyPress);
document.body.addEventListener('keydown', this.onKeyPress);
if (typeof tizen !== 'undefined')
{
var value = tizen.tvinputdevice.getSupportedKeys();
this.keyCode = value
}
else {
this.keyCode = "tizen undefined"
}
}
render() {
return (<div>
{this.keyCode}
</div>
);
}
}
I run this via
rnv run -p tizen -d -t 192.168.1.31
and output is "tizen undefined"
this is the wrapper code that is generated in platformBuilds/blank_tizen when installing the App to the Tizen TV, it seems ok to me?
<html>
<head>
<meta charset="UTF-8">
<title>App Shell</title>
<style>
body {
background-color: white;
}
</style>
</head>
<body style="margin:0px;padding:0px;overflow:hidden">
<iframe style="margin:0px;padding:0px;overflow:hidden" id="iframe" height="100%" width="100%" frameborder="0"
scrolling="no" allowfullscreen="true" sandbox="allow-scripts allow-same-origin">
</iframe>
<script>
var href = 'http://192.168.1.67:8087';
setTimeout( function () {
var iframe = document.getElementById( 'iframe' );
iframe.src = href
iframe.onload = function () {
if ( typeof tizen !== "undefined" ) iframe.contentWindow.tizen = tizen;
if ( typeof webapis !== "undefined" ) iframe.contentWindow.webapis = webapis;
if ( typeof webOS !== "undefined" ) iframe.contentWindow.webOS = webOS;
if ( typeof webOSDev !== "undefined" ) iframe.contentWindow.webOSDev = webOSDev;
}
}, 5000 );
</script>
</body>
</html>
You can see tizen variable is being passed to the iframe so it should be available in the App code but it is not there? Also the generated config.xml does contain
<tizen:privilege name='http://tizen.org/privilege/tv.inputdevice' />
So we should be able to access the tizen API
RNV = 0.29.0 Node = 14.0.0 NPM = 6.14.4
If I create a new project in Tizen Studio and put in the following code
<!DOCTYPE html>
<html>
<head>
<title></title>
<link rel="stylesheet" type="text/css" href="css/style.css"/>
<script src="./main.js"></script>
</head>
<body>
<script>
var value = tizen.tvinputdevice.getSupportedKeys();
console.log(value);
</script>
</body>
</html>
And launch this as a Debug Tizen web application then I can see in the console the output which looks fine?
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
In case this may be of interest to anyone in the future - the behaviour above is caused by the fact that 'tizen' is set with a 5s Timeout (by the way - can anyone explain why?) - it means that it is not available directly at launch, only slightly later...
The best solution would probably be to ditch the iframe and instead let the appShell be the result from webpack-dev-server (but scripts/assets loaded via external URL prefix). I think this could solve all issues and make renative more future proof.
Also there is this, but this only solves the issue for Tizen, not potential future issues with WebOS and such.
To me the same timeout problem was happening, but 100ms is enough in my case (I'm making a simple "Exit the App?" dialog screen)
I have the same problem, but I try to set the tizen after 5 seconds and it doesn't work for me!
Where do you add this code?
does it help to set the listeners on document 'load' event?
Could you give me an example?
window.addEventListener('load', (event) => {
// check if tizen global exists here
});
Should I put this code in a useEffect? And in the ./src/app/index.web.js file?
yeap, that's what I did:
useEffect(() => {
setTimeout(() => {
window.addEventListener('keydown', onKeyDownMenu);
}, 100);
}, []);
const onKeyDownMenu = (event) => {
switch (event.keyCode) {
case 8: //backspace
case 10009:
break;
}
}
And it doesn't have to be on index.web.js
, it could be at any component
This does not work?
useEffect(() => {
window.addEventListener('load', (event) => {
console.log('page is fully loaded, use tizen object here');
var value = tizen.tvinputdevice.getSupportedKeys();
console.log(value);
});
}, []);
no, it doesn't work
this is my code, the load event is not executed:
useEffect(() => {
window.addEventListener('load', (event) => {
console.log('page is fully loaded, use tizen object here');
setTimeout(() => {
if ( typeof tizen !== "undefined" ) {
var value = tizen.tvinputdevice.getSupportedKeys();
console.log(value);
}
}, 6000);
});
}, []);
this code is on the first screen of the app
Couple of observations from my experience - in case it may help someone:
First note - the key registration only works on actual device, not on the simulator.
Second note - what I have noticed is that there is a different behaviour when app is served locally in the development mode and when it's installed in the production mode - in my case it's because of the way it's being served.
In my case the Key registration works only in production mode and then it works without problems.
I simply check for 'tizen' in window
and then run tizen.tvinputdevice.registerKey(<name>)
I'm also facing the same problem, tizen in window is undefined. I tested in a real device as well.
You guys found any solution to detect remote events?
Could you check if this works?
const handler = e => { if ( e.key === "ArrowUp" || e.key === "ArrowDown" || e.key === "ArrowLeft" || e.key === "ArrowRight" || e.key === "Enter" || e.key === "Select" || e.key === "Back" ) console.log("e",e); };
useEffect(() => { window.addEventListener("keydown", handler); return () => { window.removeEventListener("keydown", handler); }; }, []);
For inputs, I'm using the prop "onKeyPress" to listen events.
Thanks in advance
Was there any progress made on this? I am experiencing the same issue with the tizen
variable in development mode.