- PVSM.RU - https://www.pvsm.ru -
Добрый день друзья, хочу сразу высказаться: данная статья моего друга, который хотел её опубликовать, но по ошибке отправил в песочницу не доделанную, и более не смог выложить нормальный вариант, попросил об этом сделать меня. Лично для меня статья очень полезная, так что весь этот труд исключительно blide [1]!
Играя в 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 [2], который может хорошо помочь при работе с ней.
Кстати, если запустить скрипт в консоли, то после обработки запросов он будет выводить:
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 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/ [3])
http.server (http://docs.python.org/3.2/library/http.server.html [4])
Пишем своё первое приложение на Android (http://habrahabr.ru/post/109944/ [5])
man xmodmap
*синюю изоленту не использовал специально, хотелось бы попользоваться телефоном отдельно от клавиатуры
Автор: unrealphp
Источник [6]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/java/24685
Ссылки в тексте:
[1] blide: http://habrahabr.ru/users/blide/
[2] SimpleHTTPRequestHandler: http://hg.python.org/cpython/file/3.2/Lib/http/server.py#l640
[3] http://loopj.com/android-async-http/: http://loopj.com/android-async-http/
[4] http://docs.python.org/3.2/library/http.server.html: http://docs.python.org/3.2/library/http.server.html
[5] http://habrahabr.ru/post/109944/: http://habrahabr.ru/post/109944/
[6] Источник: http://habrahabr.ru/post/165639/
Нажмите здесь для печати.