Знущаємося над Google Cast, або мишу для телевізора



Як тільки я дізнався про таку чудову річ, як Chromecast, відразу побіг його купувати, адже перетворити свій ТБ в SmartTV (ну або на худий кінець не перетыкать більше HDMI для перегляду фільмів) за дві тисячі рублів — дуже весела перспектива. Однак ще більш весела перспектива — це почати програмувати під нього.

Більшість завдань для Хромкаста, які реалізують зараз — це найпростіші програми-відеоплеєри. Формений несправедливість для середовища, яка може виконувати HTML5 на рівні свіжого Хрому. Але от невдача: немає в цьому середовищі ніяких подій миші, що логічно. Але і це не проблема для нас з вами.

Отже, для початку створимо найпростіші Sender App і Reciever App. Інструкції для цього є в офіційній документації. Якщо коротко, то для цього вам потрібно:

  • Зареєструватися тут, зареєструвати свій Chromecast і свою програму;
  • Створити HTML-додаток Sender для Chrome (інструкція;
  • Створити HTML-додаток Reciever для Cast-пристрої (інструкція).


Є маленький чіт, який дозволить вам уникнути зайвого кроку по заливці створеного Receiver-додатки на зовнішній хостинг. Коли ви зареєстрували свій Chromecast і додали додаток (можете зареєструвати його на будь-яку ліву сторінку на будь-якому лівому домені, головне, щоб вона відкривалася), ви можете відкрити дебаг вашого додатки, як описано тут, і далі просто ввести в JS-консолі:

location.href = 'http://IP-вашего-локального-сервера/'

і відкрити, таким чином, сторінку Receiver-програми з локального веб-сервера.

Ну, перейдемо, власне, до самого експерименту. Всі чари нашої програми буде полягати в тому, що ми будемо передавати з Хрому координати покажчика миші за допомогою стандартного методу Google Cast API для передачі повідомлення. Суть в тому, що з'єднання між Receiver і Sender додатків йде через ваш локальний WiFi (і, судячи з усього, WebSockets), тому затримка передачі даних мінімальна.

Для початку:

Власне, функція, яка творить дива в Sender-додатку:
JS
function() {
if (!$('body').data('casting')) {
$('body').data('casting', true).on('mousemove', (function(e) {
return window.session.sendMessage(namespace, {
x: e.clientX,
y: e.clientY
}, (function() {}), (function() {}));
}).throttle(10)).on('click', function() {
return window.session.sendMessage(namespace, {
event: 'click'
}, (function() {}), (function() {}));
});
}
return;
}


CoffeeScript
->
unless (body = $('body')).data 'casting'
body
.data 'casting', true
.on 'mousemove', ((e) ->
window.session.sendMessage namespace, { x: e.clientX, y: e.clientY }, (->), (->)
).throttle(10)
.on 'click', ->
window.session.sendMessage namespace, { event: 'click'}, (->), (->)



Чарівна функція throttle в даному випадку мною запозичена з Sugar.JS. Як багато здогадалися, вона обмежує виклик коллбека не частіше разу на 10 мс, щоб не зафлудить наш Chromecast. Namespace — це просто унікальна рядок, ім'я, яке дається каналу даних. У моєму випадку це 'urn:x-cast:com.google.cast.magnum.remote_control'.

Викликати цю функцію нам потрібно в той момент, коли ми встановлюємо сесію зв'язку з Cast-пристроєм, тобто 1) всередині sessionListener (у разі оновлення сторінки, якщо з'єднання вже було встановлено), а так само 2) у success-коллбеке в requestSession.

Отже, Sender тепер відправляє дані про координати покажчика миші, залишилося їх якось обробити в Receiver'е:
JS
this.cursor = document.createElement('div');
this.cursor.style.position = 'absolute';
this.cursor.classList.add('magnum-cursor');
document.body.appendChild(this.cursor);
this.messageBus = receiverManager.getCastMessageBus(this.namespace, cast.receiver.CastMessageBus.MessageType.JSON);
return this.messageBus.onMessage = (function(_this) {
return function(e) {
if (e.data.x && e.data.y) {
var element;
_this.cursor.style.left = e.data.x + 'px';
_this.cursor.style.top = e.data.y + 'px';
element = document.elementFromPoint(e.data.x - 1, e.data.y - 1);
if (_this.currentHover !== element) {
if (_this.currentHover) {
_this.currentHover.dispatchEvent(new Event('mouseleave'));
_this.currentHover.classList.remove('hover');
}
_this.currentHover = element;
_this.currentHover.dispatchEvent(new Event('mouseenter'));
return _this.currentHover.classList.add('hover');
}
} else if (e.data.event) {
return _this.currentHover.dispatchEvent(new Event(e.data.event));
}
};
})(this);


CoffeeScript
@messageBus = receiverManager.getCastMessageBus @namespace, cast.receiver.CastMessageBus.MessageType.JSON

@messageBus.onMessage = (e) =>
if e.data.x && e.data.y
@cursor.style.left = e.data.x + 'px'
@cursor.style.top = e.data.y + 'px'

# we should get neighboor pixel; otherwise we will get cursor element forever.
element = document.elementFromPoint e.data.x - 1, e.data.y - 1

if @currentHover != element
if @currentHover
@currentHover.dispatchEvent new Event('mouseleave')
@currentHover.classList.remove 'hover'

@currentHover = element

@currentHover.dispatchEvent new Event('mouseenter')
@currentHover.classList.add 'hover'

else if e.data.event
@currentHover.dispatchEvent new Event(e)



receiverManager ми створюємо заздалегідь у відповідності з документацією. cursor — це просто div-елемент, який буде бігати по екрану, замінюючи нам курсор. Власне, на цьому ми всі і зробили.

Повний готовий приклад можна подивитися у мене на гітхабі. Чекаю ваших коментарів.

P. S.: Якщо тема буде цікава, і якщо мені буде не лінь, в наступному випуску розповім, як зробити з вашого смартфона 3D-пульт для програми Google Cast (прямо як LG Magic Remote, і навіть крутіше, тому що інтерактивний).

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.