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

в 12:08, , рубрики: android, java, python, Программирование, метки: , , ,

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

Автор: unrealphp

Источник

Поделиться

* - обязательные к заполнению поля