Magic Remote
Introduction
One of the WebOS SmartTv specific capabilities is the LG Magic Remote. A pointer allowing to navigate in any app through point and click.
Supporting the magic remote for a third party application may be mandatory to be allowed to deploy on LG Store.
Since v7.2201
, Dana for WebOS supports this specific device and feature.
Configuration
To configure and use the magic remote, be sure you have set up your WebOS configuration.
To enable Magic remote integration, simply set enablePointer
property to true
in your profile:
"base-webos": {
"app": {
"enablePointer": true
}
}
Handling remote events
Goal of Dana is to forward Magic Remote events to your screens so your app can support and behave accordingly. Each app and screens must define how it should interact with it like any other input events (LEFT, RIGHT, OK, …).
Caution
Specific UX behaviours may be needed as most of TV Application are not natively designed to support a mouse pointer.
Like a classic mouse control, LG magic remote supports these four pointer events:
- click
- hover
- unhover
- scroll
Any screen is able to listen to one or all of these inputs:
import $Screen from "@Screen";
import $MouseEvent from "@MouseEvent";
export default $Screen.declare("AppScreen", {
inputs: [
$MouseEvent.click,
$MouseEvent.hover,
$MouseEvent.unhover,
$MouseEvent.scroll
],
methods: {
onMouseClick: function (element) {},
onMouseHover: function (element) {},
onMouseUnhover: function (element) {},
onMouseScroll: function ({event, element}) {},
}
}
Every handler has one parameter called element
referencing to the View
that triggered the pointer event (see more info below).
Therefore, every screen can define its own behaviour according to the kind of event and the View
underneath:
onMouseHover: function(element) {
if(element.id === this.clockView.id) { // check if the "element" matches your view's screen children
element.focus(); // "element" is a View so you can focus it directly (or use setState)
} else if(element.parent.id === this.programList.id) { // Or you can check if the element's parent is a known children
this.programList.selectItem(element.index); // "element" knows its index so you can select the good item
}
},
onMouseClick: function(element) {
if(element.data.isContent) { // you can check if your View data matches your needs
this.route("fip", {data: element.data}); // open the program info page with some data as context
}
},
onMouseScroll: function({event, element}) {
if(event.deltaY > 0) { // scroll "event" param is a WheelEvent
this._down();
} else {
this._up();
}
}
Enable collision on specific item
You need to activate view collision on items that you want to trigger mouse events. Flag isInteractive
will allow to enable above events to be triggered on some specific View
.
export default $View.declare("MyView", {
children: {
img: {class: $ImagePrimitive},
rect: {class: $RectanglePrimitive}
},
properties: {
isInteractive: true
}
});
Default value of isInteractive
is false
. Only use this flag on view which needs collision detection.
What element is returned by the events ?
Dana’s integration is based on Lightning SDK and browser collision mechanism analyze. As a result, element returned by remote events are linked to those implementation and can be different between CSS and Lightning.
By default, Dana always trigger events on the lowest possible View
in the rendering tree that is “under” the cursor (taking position and size properties in consideration)
In this example, event will be triggered on ProgramListItemView#1
CSS
In case 2 (or more) elements overlap, Dana will trigger the mouse events on the element with:
- The highest z-index (using stacking context)
Lightning
In case 2 (or more) elements overlap, Dana will trigger the mouse events on the element with:
- The highest z-index (absolute z-index, not using stacking context)
- The highest element id (integer incremented for every new Element creation)
Technical limitations
Not on primitives
Pointer events will be triggered on View
only, not on Primitive
. This is a technical choice to make event handling easier.
Therefore, if needed to distinguish two visual elements, it is recommended to create two separate views.
Caution
Creating views
instead of primitives
may impact performances, then it is important to not be greedy.
Lightning specific limitations
Bad behaviour on renderToTexture
If any of your component declares an rtt
property (to enable Lightning renderToTexture
), there is an issue with pointer events handling and positions of lightning elements.
For more information, check this GitHub issue.
Bad behaviour on RecyclingList
There is a known issue in which pointer events are not fired after navigating in a RecyclingListView
.
This is because the List container may be out of screen bounds and not considered to be active
by Lightning anymore.
An issue is opened on our side, and we will inform you once it is solved.
Z-index is not contextual
As collision detection is not using stacking context, it will not be possible to collision with a child which has a parent View
with a positive z-index. Parent view always be considering collision before its child.