Добрый день друзья, хочу сразу высказаться: данная статья моего друга, который хотел её опубликовать, но по ошибке отправил в песочницу не доделанную, и более не смог выложить нормальный вариант, попросил об этом сделать меня. Лично для меня статья очень полезная, так что весь этот труд исключительно blide!
Играя в Team Fortess 2 и при этом слушая музыку, я сильно негодовал из-за невозможностью регулировки громкости проигрывателя Clementine отдельно от общей громкости. Но лишних клавиш на клавиатуре у меня нет, все используются.
Нетривиальная задача должна иметь нетривиальное решение, поэтому я решил сделать эмуляцию нажатия клавиш через мое android-устройство посредствам http. Незнание Java и Python ничем не помешало, не спроста же у меня на жёстком диске есть ext3-раздел.
Для начала требовалось узнать список поддерживаемых и свободных клавиш. В Ubuntu можно с помощью утилиты xmodmap и файликов /usr/library/X11/*keysum.h Для меня таковыми оказались:
#define XF86XK_Launch0 0x1008FF40 /* Launch Application */
…
#define XF86XK_LaunchF 0x1008FF4F /* Launch Application */
Нам нужны коды данных клавиш(я выбрал только 2); например, узнать код клавиши с обозначением «XF86XK_Launch1» можно с помощью команды «xmodmap -pk|preg 'Launch1'
», мы получим код «156»(мной выбраны 156 и 157).
Сервер
Пользуясь наижелезнейшей логикой, я понял, что tcp-сервер я буду писать на незнакомом мне Python 3 с помощью модуля http. Этот этап не вызвал никаких трудностей, потому что в модуле есть достаточно хорошая и понятная основа для написания tcp-сервера, а именно классы «BaseHTTPRequestHandler» и «SimpleHTTPRequestHandler». Для эмуляции нажатия клавиш был использован «pyatspi.registry», ну тут собственно нечего комментировать.
В процессе дебагинга мне показалось, что весьма полезным будет знать время отклика, но тут случилось что-то интересное; в эмуляторе данная фича работала как надо, а вот время отклика, полученное при работе с физическим девайсом, заставило меня переосмыслить идеи об устройстве мира. Постепенно мне начало казаться, что я — гуру программирования и магистр времени. Иначе как мне удалось бы сократить время отклика до отрицательных значений? Я готов выслушать ваши теорию по данному прецеденту.
import pyatspi, time
import http.server
import socketserver
class HttpKeyboard(http.server.BaseHTTPRequestHandler):
server_version = "SimpleHTTP/0.1"
def do_GET(self):
"""Serve a GET request."""
reg = pyatspi.Registry.generateKeyboardEvent
path = self.path.split('/')
if len(path) == 3:
ms = int(round(time.time() * 1000)) - int(path[2])
reg(int(path[1]), None, pyatspi.KEY_PRESSRELEASE)
print ("key %s - %s ms" % (path[1], ms))
f = self.send_head()
def send_head(self):
self.send_response(200)
self.send_header("Content-type", "text/html; charset=utf-8")
self.send_header("Content-Length", 0)
self.end_headers()
httpd = socketserver.TCPServer(("", 8000), HttpKeyboard)
print("serving at port", 8000)
if __name__ == "__main__":
httpd.serve_forever()
В этой библиотеке есть пример обработчика запросов — класс SimpleHTTPRequestHandler, который может хорошо помочь при работе с ней.
Кстати, если запустить скрипт в консоли, то после обработки запросов он будет выводить:
key 156 - 527 ms
// код клавиши и задержка(которая бывает меньше нуля)
192.168.0.101 - - [07/Jan/2013 19:57:09] "GET /156/1357574229198 HTTP/1.1" 200
В данном случае:
156 — код клавиши
1357574229198 — время нажатия кнопки на вдвойнедополнительной клавиатуре
Добавить http-заголовки я решил, чтобы результат запроса можно было бы обработать на девайсе готовыми средствами.
Android-приложение
Для асинхронных запросов я выбрал Android Asynchronous Http Client. Устройства находятся в одной wifi-сетке, поэтому использовались внутренние ip, больше ничего интересного на данном этапе я не нашёл кроме враждебно настроенной System.currentTimeMillis(). Полные сорцы скину в конце, а тут оставлю функцию самого запроса.
public void KeyHttp(String key) {
AsyncHttpClient client = new AsyncHttpClient();
EditText edit = (EditText) findViewById(R.id.editText1);
client.get("http://"+edit.getText()+"/"+key+"/"+System.currentTimeMillis(), new AsyncHttpResponseHandler() {
@Override
public void onSuccess(String response) {
this.log("success result");
}
@Override
public void onStart() {
this.log("starting");
}
@Override
public void onFailure(Throwable error) {
this.log("failure result");
}
public void log(String text) {
TextView view = (TextView) findViewById(R.id.textView1);
view.setText(text);
}
});
}
Итог
Запустим сервер и установим приложение на девайс.
Ну вот, теперь всё готово для комфортного увеличения игрового времени на linux-машине в Team Fortress 2 под бунтарские ритмы The Offspring.
Клавиши можно использовать любые и в любом количестве. Я частенько вижу у знакомых телевизор и пк подключенные через hdmi, но находящиеся в разных комнатах, такой itlife-хак, думаю, пришёлся бы им по душе. На самом деле сфера применения данного инструмента достаточно широка: от домашних медиа-центров до недомашних медиа-центров.
Спасибо за интерес к материалу.
Ссылки:
Android Asynchronous Http Client (http://loopj.com/android-async-http/)
http.server (http://docs.python.org/3.2/library/http.server.html)
Пишем своё первое приложение на Android (http://habrahabr.ru/post/109944/)
man xmodmap
*синюю изоленту не использовал специально, хотелось бы попользоваться телефоном отдельно от клавиатуры
Автор: unrealphp