Тюним клавиатуру правильно

от автора


Добрый день друзья, хочу сразу высказаться: данная статья моего друга, который хотел её опубликовать, но по ошибке отправил в песочницу не доделанную, и более не смог выложить нормальный вариант, попросил об этом сделать меня. Лично для меня статья очень полезная, так что весь этот труд исключительно 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(). Полные сорцы скину в конце, а тут оставлю функцию самого запроса.

Java

 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
*синюю изоленту не использовал специально, хотелось бы попользоваться телефоном отдельно от клавиатуры

ссылка на оригинал статьи http://habrahabr.ru/post/165639/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *