Skip to content

Commit b104f1f

Browse files
committed
add LG webos keyboard support (no search), add play_pause, play, and pause commands to all platforms using media player actions
1 parent 35411c5 commit b104f1f

File tree

10 files changed

+160
-25
lines changed

10 files changed

+160
-25
lines changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,10 @@ A super customizable universal remote card iterating on the work of several othe
2323
- Sony BRAVIA (with keyboard via ADB)
2424
- Fire TV (with keyboard)
2525
- Roku (with keyboard)
26+
- LG webOS (with keyboard)
2627
- Kodi (with keyboard)
2728
- Apple TV
2829
- Samsung TV
29-
- LG webOS
3030
- Jellyfin
3131
- Support for multiple buttons, touchpads, and sliders using default or user defined custom actions.
3232
- Complete [Home Assistant actions](https://www.home-assistant.io/dashboards/actions/) support.
@@ -62,10 +62,10 @@ This card supports several media platforms with default key and source lists. Fo
6262
| [Sony BRAVIA](https://www.home-assistant.io/integrations/braviatv/) | Default keys | Default sources and slider | [ADB](https://www.home-assistant.io/integrations/androidtv/) remote (preferred) or media player |
6363
| [Fire TV](https://www.home-assistant.io/integrations/androidtv/) | Default keys | Default sources and slider | Remote (preferred) or media player |
6464
| [Roku](https://www.home-assistant.io/integrations/roku/) | Default keys | Default sources and slider | Remote for keyboard, media player for search (provide one for keyboard ID and the others in their fields) |
65+
| [LG webOS](https://www.home-assistant.io/integrations/webostv/) | NA | Default keys, sources, and slider | Media Player |
6566
| [Kodi](https://www.home-assistant.io/integrations/kodi/) | NA | Default keys, sources, and slider | Media player |
6667
| [Apple TV](https://www.home-assistant.io/integrations/apple_tv) | Default keys | Default sources and slider | NA |
6768
| [Samsung TV](https://www.home-assistant.io/integrations/samsungtv/) | Default keys | Default sources (requires the [SamsungTV Smart Component custom integration](https://github.com/ollo69/ha-samsungtv-smart)) and slider | NA |
68-
| [LG webOS](https://www.home-assistant.io/integrations/webostv/) | NA | Default keys, sources, and slider | NA |
6969
| [Jellyfin](https://www.home-assistant.io/integrations/jellyfin/) | Default keys | Play/Pause and slider | NA |
7070

7171
## Action Timings
@@ -371,7 +371,7 @@ For Roku make sure to include both the remote and media player IDs at the genera
371371

372372
Send text to your supported media platform seamlessly using the action or default key `keyboard`. The dialog has several listeners which will send anything you type to your media platform immediately. You can also paste by holding or typing CTRL + V into the dialog.
373373

374-
Because we do not have a way to retrieve the currently on screen text of most media platforms, the dialog and platform text may become out of sync if a message gets dropped due to a network issue, you attempt to erase more than one character at a time, you try to modify the middle of the entered text, or if you prematurely close the dialog window. The keyboard dialog will attempt to prevent you from doing things that would cause this, but please remember that if you make a mistake you have to backspace all the way to the incorrect character from the end of your input text one character at at a time. In my testing the dialog always kept in sync with the platform text unless I attempted to delete more than one character. This does not apply to Kodi, which sets the text field to the entire dialog text every time it's action is called.
374+
Because we do not have a way to retrieve the currently on screen text of most media platforms, the dialog and platform text may become out of sync if a message gets dropped due to a network issue, you attempt to erase more than one character at a time, you try to modify the middle of the entered text, or if you prematurely close the dialog window. The keyboard dialog will attempt to prevent you from doing things that would cause this, but please remember that if you make a mistake you have to backspace all the way to the incorrect character from the end of your input text one character at at a time. In my testing the dialog always kept in sync with the platform text unless I attempted to delete more than one character. This does not apply to Kodi or LG webOS, which sets the text field to the entire dialog text every time it's action is called.
375375

376376
ADB can be slow and you may notice some delay in what you type and what appears on your Android TV, Sony BRAVIA, or Fire TV device. Make sure to use the newer ADB integration remote entity for a faster typing experience.
377377

dist/universal-remote-card.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/classes/keyboard-dialog.ts

Lines changed: 74 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,36 @@ export class KeyboardDialog extends LitElement {
6363
});
6464
}
6565

66+
webosOnKeyDown(e: KeyboardEvent) {
67+
e.stopImmediatePropagation();
68+
69+
if (['Backspace', 'Enter'].includes(e.key)) {
70+
const text = this.textarea?.value ?? '';
71+
this.hass.callService('webostv', 'command', {
72+
entity_id: this.config?.keyboard_id,
73+
command: 'com.webos.service.ime/insertText',
74+
payload: {
75+
text: text,
76+
replace: true,
77+
},
78+
});
79+
}
80+
}
81+
82+
webosOnInput(e: InputEvent) {
83+
e.stopImmediatePropagation();
84+
85+
const text = this.textarea?.value ?? '';
86+
this.hass.callService('webostv', 'command', {
87+
entity_id: this.config?.keyboard_id,
88+
command: 'com.webos.service.ime/insertText',
89+
payload: {
90+
text: text,
91+
replace: true,
92+
},
93+
});
94+
}
95+
6696
rokuOnKeyDown(e: KeyboardEvent) {
6797
e.stopImmediatePropagation();
6898
this.forceCursorToEnd();
@@ -147,14 +177,13 @@ export class KeyboardDialog extends LitElement {
147177
const inputType = e.inputType ?? '';
148178
const text = e.data ?? '';
149179
if (text && inputType == 'insertText') {
150-
this.androidTvSendText(text);
180+
this.adbSendText(text);
151181
} else if (!this.onKeyDownFired) {
152182
const inputTypeToKey: Record<string, string> = {
153183
deleteContentBackward: '67',
154184
insertLineBreak: '66',
155185
};
156186
const key = inputTypeToKey[inputType ?? ''];
157-
158187
if (key) {
159188
this.hass.callService(
160189
this.domain ?? 'remote',
@@ -169,6 +198,17 @@ export class KeyboardDialog extends LitElement {
169198
this.onKeyDownFired = false;
170199
}
171200

201+
adbSendText(text: string) {
202+
this.hass.callService(
203+
this.domain ?? 'remote',
204+
this.service ?? 'send_command',
205+
{
206+
entity_id: this.config?.keyboard_id,
207+
command: `input text "${text}"`,
208+
},
209+
);
210+
}
211+
172212
androidTvOnKeyDown(e: KeyboardEvent) {
173213
e.stopImmediatePropagation();
174214
this.forceCursorToEnd();
@@ -198,7 +238,7 @@ export class KeyboardDialog extends LitElement {
198238
const inputType = e.inputType ?? '';
199239
const text = e.data ?? '';
200240
if (text && inputType == 'insertText') {
201-
this.androidTvSendText(text);
241+
this.adbSendText(text);
202242
} else if (!this.onKeyDownFired) {
203243
const inputTypeToKey: Record<string, string> = {
204244
deleteContentBackward: 'DEL',
@@ -218,17 +258,6 @@ export class KeyboardDialog extends LitElement {
218258
this.onKeyDownFired = false;
219259
}
220260

221-
androidTvSendText(text: string) {
222-
this.hass.callService(
223-
this.domain ?? 'remote',
224-
this.service ?? 'send_command',
225-
{
226-
entity_id: this.config?.keyboard_id,
227-
command: `input text "${text}"`,
228-
},
229-
);
230-
}
231-
232261
keyboardOnPaste(e: ClipboardEvent) {
233262
e.stopImmediatePropagation();
234263
if (this.config?.platform != 'Kodi') {
@@ -246,6 +275,14 @@ export class KeyboardDialog extends LitElement {
246275
done: false,
247276
});
248277
break;
278+
case 'LG webOS':
279+
this.hass.callService('webostv', 'command', {
280+
entity_id: this.config?.keyboard_id,
281+
command: 'com.webos.service.ime/insertText',
282+
text: this.textarea?.value ?? '',
283+
replace: true,
284+
});
285+
break;
249286
case 'Roku':
250287
this.hass.callService('remote', 'send_command', {
251288
entity_id: this.config?.keyboard_id,
@@ -281,6 +318,8 @@ export class KeyboardDialog extends LitElement {
281318
done: true,
282319
});
283320
break;
321+
case 'LG webOS':
322+
break;
284323
case 'Roku':
285324
this.hass.callService('roku', 'search', {
286325
entity_id: this.getRokuId('media_player'),
@@ -317,6 +356,16 @@ export class KeyboardDialog extends LitElement {
317356
done: false,
318357
});
319358
break;
359+
case 'LG webOS':
360+
this.hass.callService('webostv', 'command', {
361+
entity_id: this.config?.keyboard_id,
362+
command: 'com.webos.service.ime/insertText',
363+
payload: {
364+
text: text,
365+
replace: true,
366+
},
367+
});
368+
break;
320369
case 'Roku':
321370
this.hass.callService('remote', 'send_command', {
322371
entity_id: this.getRokuId('remote'),
@@ -351,6 +400,12 @@ export class KeyboardDialog extends LitElement {
351400
done: true,
352401
});
353402
break;
403+
case 'LG webOS':
404+
this.hass.callService('webostv', 'command', {
405+
entity_id: this.config?.keyboard_id,
406+
command: 'com.webos.service.ime/sendEnterKey',
407+
});
408+
break;
354409
case 'Roku':
355410
this.hass.callService('remote', 'send_command', {
356411
entity_id: this.getRokuId('remote'),
@@ -492,6 +547,11 @@ export class KeyboardDialog extends LitElement {
492547
keyDownHandler = this.kodiOnKeyDown;
493548
antiCursorMoveHandler = undefined;
494549
break;
550+
case 'LG webOS':
551+
inputHandler = this.webosOnInput;
552+
keyDownHandler = this.webosOnKeyDown;
553+
antiCursorMoveHandler = undefined;
554+
break;
495555
case 'Roku':
496556
inputHandler = this.rokuOnInput;
497557
keyDownHandler = this.rokuOnKeyDown;

src/models/interfaces/IActions.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@ export const KeyboardPlatforms = [
33
'Sony BRAVIA',
44
'Fire TV',
55
'Roku',
6+
'LG webOS',
67
'Kodi',
78
] as const;
89
export type KeyboardPlatform = (typeof KeyboardPlatforms)[number];
910
export const Platforms = [
1011
...KeyboardPlatforms,
1112
'Apple TV',
1213
'Samsung TV',
13-
'LG webOS',
1414
'Jellyfin',
1515
] as const;
1616
export type Platform = (typeof Platforms)[number];

src/models/maps/apple_tv/defaultKeys.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,15 @@ export const appleTVDefaultKeys: IElementConfig[] = [
166166
hold_action: { action: 'repeat' },
167167
},
168168
},
169+
{
170+
type: 'button',
171+
name: 'play_pause',
172+
tap_action: {
173+
action: 'perform-action',
174+
perform_action: 'media_player.media_play_pause',
175+
},
176+
icon: 'mdi:play-pause',
177+
},
169178
{
170179
type: 'button',
171180
name: 'play',

src/models/maps/bravia/defaultKeys.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,15 @@ export const braviaTVDefaultKeys: IElementConfig[] = [
138138
hold_action: { action: 'repeat' },
139139
},
140140
},
141+
{
142+
type: 'button',
143+
name: 'play_pause',
144+
tap_action: {
145+
action: 'perform-action',
146+
perform_action: 'media_player.media_play_pause',
147+
},
148+
icon: 'mdi:play-pause',
149+
},
141150
{
142151
type: 'button',
143152
name: 'play',

src/models/maps/fire_tv/defaultKeys.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,33 @@ export const fireTVDefaultKeys: IElementConfig[] = [
171171
hold_action: { action: 'repeat' },
172172
},
173173
},
174+
{
175+
type: 'button',
176+
name: 'play_pause',
177+
tap_action: {
178+
action: 'perform-action',
179+
perform_action: 'media_player.media_play_pause',
180+
},
181+
icon: 'mdi:play-pause',
182+
},
183+
{
184+
type: 'button',
185+
name: 'play',
186+
tap_action: {
187+
action: 'perform-action',
188+
perform_action: 'media_player.media_play',
189+
},
190+
icon: 'mdi:play',
191+
},
192+
{
193+
type: 'button',
194+
name: 'pause',
195+
tap_action: {
196+
action: 'perform-action',
197+
perform_action: 'media_player.media_pause',
198+
},
199+
icon: 'mdi:pause',
200+
},
174201
{
175202
type: 'button',
176203
name: 'fast_forward',

src/models/maps/roku/defaultKeys.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -131,21 +131,21 @@ export const rokuDefaultKeys: IElementConfig[] = [
131131
},
132132
{
133133
type: 'button',
134-
name: 'play',
134+
name: 'play_pause',
135135
tap_action: { action: 'key', key: 'play' },
136-
icon: 'mdi:play',
136+
icon: 'mdi:play-pause',
137137
},
138138
{
139139
type: 'button',
140-
name: 'pause',
140+
name: 'play',
141141
tap_action: { action: 'key', key: 'play' },
142-
icon: 'mdi:pause',
142+
icon: 'mdi:play',
143143
},
144144
{
145145
type: 'button',
146-
name: 'play_pause',
146+
name: 'pause',
147147
tap_action: { action: 'key', key: 'play' },
148-
icon: 'mdi:play-pause',
148+
icon: 'mdi:pause',
149149
},
150150
{
151151
type: 'button',

src/models/maps/samsung_tv/defaultKeys.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,15 @@ export const samsungTVDefaultKeys: IElementConfig[] = [
153153
hold_action: { action: 'repeat' },
154154
},
155155
},
156+
{
157+
type: 'button',
158+
name: 'play_pause',
159+
tap_action: {
160+
action: 'perform-action',
161+
perform_action: 'media_player.media_play_pause',
162+
},
163+
icon: 'mdi:play-pause',
164+
},
156165
{
157166
type: 'button',
158167
name: 'play',

src/models/maps/webos/defaultKeys.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,15 @@ export const webosDefaultKeys: IElementConfig[] = [
192192
hold_action: { action: 'repeat' },
193193
},
194194
},
195+
{
196+
type: 'button',
197+
name: 'play_pause',
198+
tap_action: {
199+
action: 'perform-action',
200+
perform_action: 'media_player.media_play_pause',
201+
},
202+
icon: 'mdi:play-pause',
203+
},
195204
{
196205
type: 'button',
197206
name: 'play',
@@ -210,6 +219,18 @@ export const webosDefaultKeys: IElementConfig[] = [
210219
},
211220
icon: 'mdi:pause',
212221
},
222+
{
223+
type: 'button',
224+
name: 'keyboard',
225+
tap_action: { action: 'keyboard' },
226+
icon: 'mdi:keyboard',
227+
},
228+
{
229+
type: 'button',
230+
name: 'textbox',
231+
tap_action: { action: 'textbox' },
232+
icon: 'mdi:text-box',
233+
},
213234
{
214235
type: 'button',
215236
name: 'channel_up',

0 commit comments

Comments
 (0)