Предположим у нас имеется: Arduino Leonardo – 1 штука, Bluetooth модуль – 1 штука, Android смартфон – 1 штука. Ключевое отличие Leonardo от остальных ардуин заключается в том, что она поддерживает протоколы HID, а по-простому может притворятся мышкой или клавиатурой. Выглядит это примерно следующим образом:
#include "Mouse.h" // импортируем библиотеку работы с мышью
void setup(){} // ничего не настраиваем
void loop()
{
Mouse.move(10, -15, 3); // сдвигаем курсор на 10 пикселей вправо, на 15 пикселей вверх и колесо на 3 оборота
}
Как видим все крайне просто. Метод Mouse.move(X, Y, WHEEL) принимает три относительных параметра:
X – величина смещения в пикселях по оси X (отрицательные значения сдвигают влево)
Y – величина смещения в пикселях по оси Y (отрицательные значения сдвигают вверх)
WHEEL – величина смещения колеса прокрутки (отрицательные значения сдвигают в другую сторону)
Но сама по себе идея двигать курсор ничего не стоит, если не мы его контролируем, а значит нам нужно непосредственно HID (Human Interface Device), или по-простому устройство ввода. В нашем случае мы его сделаем из смартфона, «написав программу» в среде AppInventor, но, предварительно, разберемся с железной частью и напишем скетч для Arduino. Данные в Leonardo со смартфона мы будем отсылать по bluetooth. Модуль bluetooth можно использовать любой подходящий, наиболее популярным решением является HC-05(06). Подключаем по следующей схеме:
Если ваш модуль еще не настроен для управления с arduino здесь имеется хороший мануал по его настройке.
Итак, модуль подключили и настроили. Теперь необходимо определиться с функционалом. Тут все стандартно, нам необходимо получать смещение по двум координатам, левый и правый клик мыши и обороты колеса. Для начала необходимо импортировать библиотеку для работы с мышью:
#include "Mouse.h" // Импортируем библиотеку работы с мышью
И создать переменные с которыми будем работать:
int8_t mess; // Сообщение пришедшее в Serial
bool _x = false; // Префикс смещения по оси X
bool _y = false; // Префикс смещения по оси Y
bool _w = false; // Префикс оборотов колеса
В настройках Setup мы указываем порт, к которому подключен модуль bluetooth. Здесь все несколько отличается от стандартных arduino-плат. Leonardo реализован на чипе Atmega32u4 и имеет встроенную поддержку USB-соединения. Соответственно нулевой Serial-порт реализован непосредственно внутри чипа, а стандартные цифровые выводы 0 и 1 реализуют Serial1. Это означает, что для инициализации UART соединения с модулем bluetooth, нам необходимо использовать следующую конструкцию в блоке Setup:
void setup()
{
Serial1.begin(115200); // Настраиваем первый порт Serial1
}
Обратите внимание, что мы используем не Serial1, а Serial.
В цикле Loop постоянно опрашиваем буфер Serial1 и в случае поступления данных, производим их обработку:
void loop()
{
if (Serial1.available()) // Проверяем наличие данных, если что-то есть реализуем код в скобках
{
//Если что-то пришло, то реализуется код в этих скобках
}
}
Далее работаем с конструкцией if (Serial1.available()) { здесь будет наш основной код }. Принятый в буфер байт мы присваиваем переменной «mess» при помощи следующей конструкции:
mess = Serial1.read();
Можно заметить, что при инициализации переменной «mess» я использовал тип данных int8_t. Этот тип представляет собой 8-ми битное число со знаком от -128 до 127. Логика работы здесь такая — смартфон отсылает нам пакеты 8-ми битных чисел в следующем виде:
- Левый клик мыши: 8-ми битное число (108)
- Правый клик мыши: 8-ми битное число (114)
- Прокрутка колеса: два 8-ми битных числа — префикс (122), величина прокрутки (число)
- Смещение по осям: четыре 8-ми битных числа – префикс по X (120), величина смещения (число), префикс по Y (121), величина смещения (число),
Как видим всего может быть 4 пакета. Если просто пришло число 108, то мы это должны интерпретировать как левый клик мыши, число 114 — правый клик. Прокрутка колеса состоит из двух чисел где первое число (122) дает нам понять, что следующее за ним число — это количество оборотов колеса. То же самое со смещением курсора, только там уже 4 числа: первое (120) говорит о том, что следующее за ним число, означает смещение по оси X, третье число (121) предваряет число смещения по оси Y.
Парсинг всего этого дела выглядит следующим образом:
void loop()
{
if (Serial1.available()) // Проверяем наличие данных, если что-то есть реализуем код в скобках
{
mess = Serial1.read(); // Пришедшее сообщение
if (_x) // Если пришло сообщение смещения по X
{
Mouse.move(mess, 0, 0); // Перемещаем указатель по оси X на пришедшее число
_x = false; // Обнуляем флаг префикса
}
if (mess == 120) _x = true; // Если пришел префикс смещения по X
if (_y) // Если пришло сообщение смещения по Y
{
Mouse.move(0, mess, 0); // Перемещаем указатель по оси Y на пришедшее число
_y = false; // Обнуляем флаг префикса
}
if (mess == 121) _y = true; // Если пришел префикс смещения по Y
if (_w) // Если пришло сообщение прокрутки колеса
{
Mouse.move(0, 0, mess); // прокручиваем колесо на пришедшее число
_w = false; // Обнуляем флаг префикса
}
if (mess == 122) _w = true; // Если пришел префикс колеса прокрутки
if (mess == 108) Mouse.click(MOUSE_LEFT); // Левый клик
if (mess == 114) Mouse.click(MOUSE_RIGHT);// Правый клик
}
}
После присвоения переменной «mess» пришедшего значения, мы определяем в условных операторах что это за число. Если это просто клик, то мы сразу реализуем клик мыши. Если это прокрутка или смещение, то мы присваиваем соответствующей булевской переменной значение true и следующее пришедшее число кладем в соответствующий параметр конструкции Mouse.move(смещение по X, смещение по Y, прокрутка колеса). Полный код выглядит так:
#include "Mouse.h" // Импортируем библиотеку работы с мышью
int8_t mess; // Сообщение пришедшее в Serial
bool _x = false; // Префикс смещения по оси X
bool _y = false; // Префикс смещения по оси Y
bool _w = false; // Префикс оборотов колеса
void setup()
{
Serial1.begin(115200); // Настраиваем первый порт Serial1
}
void loop()
{
if (Serial1.available()) // Проверяем наличие данных, если что-то есть реализуем код в скобках
{
mess = Serial1.read(); // Пришедшее сообщение
if (_x) // Если пришло сообщение смещения по X
{
Mouse.move(mess, 0, 0); // Перемещаем указатель по оси X на пришедшее число
_x = false; // Обнуляем флаг префикса
}
if (mess == 120) _x = true; // Если пришел префикс смещения по X
if (_y) // Если пришло сообщение смещения по Y
{
Mouse.move(0, mess, 0); // Перемещаем указатель по оси Y на пришедшее число
_y = false; // Обнуляем флаг префикса
}
if (mess == 121) _y = true; // Если пришел префикс смещения по Y
if (_w) // Если пришло сообщение прокрутки колеса
{
Mouse.move(0, 0, mess); // прокручиваем колесо на пришедшее число
_w = false; // Обнуляем флаг префикса
}
if (mess == 122) _w = true; // Если пришел префикс колеса прокрутки
if (mess == 108) Mouse.click(MOUSE_LEFT); // Левый клик
if (mess == 114) Mouse.click(MOUSE_RIGHT);// Правый клик
}
}
Теперь займемся реализацией приложения для смартфона. Не забываем, что мы только-только закончили делать погодные информеры и котопоилки, а значит Andriod Studio пойло для лохов изучать пока рано, посему нальем себе кефирчика используем среду AppInventor. На базовых навыках по работе с этой средой я останавливаться не стану, можно почитать здесь, а еще лучше просто открыть и потыкаться самому, там все очень просто. Сразу перейду к блокам. Полный ээээ…. ну пусть будет код программы выглядит так:
Совсем просто, правда? А так выглядит интерфейс:
Вверху, там, где надпись: «ПОДКЛЮЧЕНО», это кнопка (список) для выбора и подключения bluetooth устройства (BTN_connect). Ползунок чуть ниже (Multipiller), регулирует скорость перемещения указателя, число справа указывает во сколько раз(TXT_mult). Серая область ниже, это непосредственно зона тачпада (Touch). Под ней три области слева-направо: левая кнопка мыши (L_click), ползунок колесика (Scroll), правая кнопка мыши (R_click).
Инициализация экрана и переменных:
Переменная «mult» (по умолчанию 2) – множитель смещения указателя. X_shift и Y_shift переменные смещения указателя. При открытии приложения, цвет панели «Touch» устанавливаем в черный.
Далее нам необходимо подключиться к bluetooth устройству (предполагается, что смартфон уже с ним спарен):
При инициализации (Перед Выбором) кнопки подключения (BTN_connect) в ее список добавятся все спаренные со смартфоном устройства и при клике по ней, откроется окно этого списка. По клику по соответствующему устройству (После Выбора), смартфон пытается подключится к выбранному устройству и в случае успеха, изменяет цвет фона «Touch» на серый, и надпись на кнопке выбора на «ПОДКЛЮЧЕНО».
Реализация смещения указателя:
Этот метод срабатывает при движении пальца по панели типа Canvas (Холст). Глобальным переменным X_shift и Y_shift присваиваются округленные (без точки) значения смещения по обоим осям. Затем, в случае если у нас установлено bluetooth соединение, программа отсылает четыре восьмибитных числа где первое число – префикс оси X (120), второе – смещение по Х, третье – префикс оси Y (121), четвертое – смещение по Y. Число смещения по обоим осям умножается на глобальную переменную «mult».
Реализация колесика схожа:
Здесь мы объявляем локальную переменную W_shift, которой точно так же присваиваем смещение по оси Y и отправляем через bluetooth два восьмибитных числа, предваряя префиксом 122.
Реализация кнопок совсем примитивна:
При клике по соответствующей кнопке происходит отправка одного восьмибитного числа.
Изменение множителя:
При изменении значения, происходит перезапись соответствующей переменной «mult» и текстовому полю (TXT_mult) присваивается новое значение «Текст».
Как видим, реализация крайне проста. На все про все потребуется один вечер времени одна Arduino Leonardo, один bluetooth модуль и смартфон, тоже одна штука. Зато теперь, можно управлять компьютером или телевизором не вставая с дивана.
При желании можно добавить двойной клик и перетаскивание мышью.
Видео процесса:
Исходники и приложение по ссылкам.
Аренда облачного сервера с быстрыми NVMе-дисками и посуточной оплатой у хостинга Маклауд.
Larymar
А почему с андроида сразу на десктоп не идти? Зачем эта прослойка?
inkelyad
У андроида возможность эмуляции им Bluetooth HID устройства в большинстве случаев не включена в ядро.
Larymar
Я скорее про всякие KDEConnect и прочие альтернативы, где на пк поднимается сервак, а андроид является к нему вьюшкой.
inkelyad
Это выглядит страшно криво. Уж лучше как тут — отдельной железкой, хотя мне кажется, что железка могла бы быть сильно менее крутой.
Fragster
Не знаю, как это выглядит, но работает это прям хорошо + кроме "тачпада" еще куча всего есть - от управления плеером (с автопаузой при звонке) до всплывания уведомлений со смартфона на компьютере.
Отдельное устройство, у которого на выходе тупой hid - явный перерасход ресурсов
ginkage
В ядро-то включена, и на всяких самсунгах и пикселях даже работает. Но почему-то некоторые производители выключают эту возможность при сборке прошивки (в ресурсах), хотя по умолчанию она включена.
volchenkodmitriy
Я тоже согласен. Вопрос должен решаться программно. Возможно с помощью доп. драйвера на самом ПК, но аппаратный огород тут совершенно лишний.
Radisto
Зато это решение будет работать даже если нет возможности установить что-либо на ПК, например на корпоративный комп, где по умолчанию кроме мыши ничего подключить и не выйдет. Хотя смарт в роли тачпада смотрится как из пушки по воробьям
dcoder_mm
И вот вы приходите на работу с ланчбоксом полным ардуин и блютуз модулей, объясняя всё это тем, что вам очень надо сделать беспроводной тачпад из смартфона.
Звучит сомнительно
Radisto
Я по своей работе сужу. Примерно так и приходится поступать.это не сомнительно звучит, это звучит глупо(давайте уж своими словами называть, к чему эти эвфемизмы), но ведь никто и не обещал, что корпоративные правила будут умными (даже если их пишут умные люди, что к сожалению тоже далеко не всегда)
Mulin
Программно, не всякий программист со стажем решит, а здесь на любителей расчет. Это первое. Второе, основная цель была была показать принцип работы HID в ардуино, а не сделать беспроводной ТАЧПАД для компьютера.
GeorgeGFedoroff
Мне кажется, что статья не об этом.
Управлять с андроида десктопом уже, наверняка, много решений. Хотя когда мне понадобилось найти быстрое, простое и универсальное (linux, windows и так далее) мне не удалось. Всегда приходится повозиться.
Статья, скорее, об ардуинке и простых вещах для неё, может для детей что-то простое, интересное и быстрое в ней найдется.
S-trace
На самом деле есть универсальное средство.
Android в более-менее современных версиях (начиная где-то с 6.0, начиная с ядра 3.18) имеет в ядре hid gadget по умолчанию, и его можно активировать при помощи https://github.com/tejado/android-usb-gadget и затем использовать при помощи https://github.com/pelya/android-keyboard-gadget/tree/master/remote-client (надо ещё перед запуском remote-client сделать setenforce 0, иначе приложение зависнет на открытии гаджета).
Работает в windows, linux и bios, проверено на смарте и планшетнике. Эмулируются клавиатура и мышь.
Работает по кабелю USB, драйвера не требуются.
GeorgeGFedoroff
Вот про «setenforce 0, иначе приложение зависнет» я и говорил «Всегда приходится повозиться». :)
inkelyad
А точно имеет? Я где-то раз в год вспоминаю про вопрос 'как сделать так, чтобы мой KeePass на телефоне мог набрать пароль в форме на десктопе', в очередной раз ищу 'сделали ли уже так, чтобы телефон мог притворяться клавиатурой?' и нахожу только какие-то древние обсуждения этт hid gadged, где говорят, что нужно свое ядро компилять.
Мне кажется, эту возможность специально выпиливают, чтобы телефоны не стали средством атаки. Потому что с клавиатуры можно много чего набрать, если не руками это делать, включая бинарник-загрузчик зловреда.
S-trace
Если верить https://github.com/pelya/android-keyboard-gadget/blob/master/README.md то точно:
For newer Kernel versions (>= 3.19) the patch is not anymore required and can be replaced by ConfigFS (USB Gadget Tool).