На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
[!] Как относитесь к модерированию на этом форуме? Выскажите свое мнение здесь
Модераторы: Qraizer
Страницы: (2) 1 [2]  все  ( Перейти к последнему сообщению )  
> Использование библиотеки Interception
    Всем привет!

    Создал тему с целью разделения темы о разработке драйверов под Windows.
    Просто чтобы не было обсуждений в одной теме "все-обо-всем".

    Библиотека Interception реализует перехват и фильтрацию данных от клавиатуры или мыши
    не уровне системы с помощью собственного драйвера-фильтра. В обсуждении решается вопрос
    перехвата данных от КартРидера, который опознается в системе как HID Keyboard.
      Ну норм, теперь обвязку сделать осталось над библиотекой мультипоточную и норм будет.

      Добавлено
      Странно что сообщение два раза вставилось. :blink:

      Добавлено
      Седня 1 апреля что ли? :scratch: На двух страницах одно и то же сообщение 2 раза :-?
        Цитата Wound @
        Странно что сообщение два раза вставилось

        Наверное это из-за того, что я первое свое сообщение в треде закрепил.
        А иначе оно по дате (после переноса сообщений) просто бы потонуло.
          Цитата JoeUser @
          Т.к. очень не хочется использовать TerminateThread, это не по фэншую С++
          Это не по фэншую WinAPI. Хуже TerminateThread() только NtShutdownSystem()
            Цитата Qraizer @
            Хуже TerminateThread() только NtShutdownSystem()

            :good: :jokingly:
              В общем, библиотека знатно помогла решить вопрос. Конечно, специализация ее узкая, и не следует от нее требовать чего-то большего. Остальное попробую получить другими средствами (мониторинг включения-отключения USB-картридера, к примеру). Вот тут я думаю libusb и поможет. Если это не де жа вю, вроде бы я там видел регистрации функций обратного вызова на включение-отключение устройств.

              Ну а пока ... магнитные карточки читаются (на изображении сырые строки с карточек Люфтганзы):

              user posted image

              Дальнейший парсинг будет несложен, методы кодирования описаны в ISO-7811. Хотя, как я понял, закодированную информацию (мой) картридер преобразует в сканкоды клавиатуры. Разделения полей данных на карте опять же по выше указанному ISO
              Скрытый текст

              14 следующих символов ! " & ' * + , : ;< = > @ _ применяют только для управления аппаратными средствами. Данные символы не могут быть использованы для передачи информации (содержания данных).

              Три следующих символа [\] зарезервированы для дополнительных национальных символов, если они потребуются. Данные символы не допускается использовать на международном уровне.

              Символ # зарезервирован для произвольных дополнительных графических символов.

              Три следующих символа % ^ ? должны иметь следующие значения:

              % - сигнальная метка начала;

              ^ - разделитель полей;

              ? - сигнальная метка конца.

              Таким образом "рыба" считывателя с использованием обсуждаемой либы такая (параллелизм считывания вне этой темы):

              ExpandedWrap disabled
                void Widget_Main::SlotRun() {
                  std::vector <std::pair<uint8_t, uint8_t>> V;
                  InterceptionContext context;
                  InterceptionDevice device;
                  InterceptionStroke stroke;
                  wchar_t hardware_id[500];
                  auto last = std::chrono::high_resolution_clock::now();
                  context = interception_create_context();
                  interception_set_filter(context, interception_is_keyboard, INTERCEPTION_FILTER_KEY_ALL);
                  while (true) {
                    while (true) {
                      device = interception_wait_with_timeout(context, 1);
                      if (!device) {
                        QCoreApplication::processEvents();
                        auto now = std::chrono::high_resolution_clock::now();
                        if (std::chrono::duration_cast<std::chrono::milliseconds>(now - last).count() > 100 &&  V.size() > 0) {
                          T->append(QString::fromStdString(KeycodeParser(V)));
                          V.clear();
                          last = now;
                        }
                      } else
                        break;
                    }
                    if (interception_receive(context, device, &stroke, 1) > 0) {
                      if (interception_is_keyboard(device)) {
                        InterceptionKeyStroke& keystroke = *(InterceptionKeyStroke*) &stroke;
                        if (keystroke.code == ScanCode::SCANCODE_ESC)
                          break;
                        size_t length = interception_get_hardware_id(context, device, hardware_id, sizeof(hardware_id));
                        if (length > 0 && length < sizeof(hardware_id)) {
                          QString Str = QString::fromWCharArray(hardware_id);
                          if (Str == "HID\\VID_0801&PID_0001&REV_0100") {
                            V.push_back(std::pair(keystroke.code, keystroke.state));
                            last = std::chrono::high_resolution_clock::now();
                          } else
                            interception_send(context, device, &stroke, 1);
                        } else
                          qDebug() << "Хрень какая-то 0_o!";
                      }
                    }
                  }
                  interception_destroy_context(context);
                  T->append("");
                  T->append("Bye!");
                }

              Преобразование скан-кодов в символьную последовательность:

              ExpandedWrap disabled
                typedef std::map<uint8_t, std::pair<uint8_t, uint8_t>> ScanMap;
                 
                const ScanMap MapChars = {
                    {0x02, {'1', '!'}}, {0x03, {'2', '@'}}, {0x04, {'3', '#'}}, {0x05, {'4', '$'}}, {0x06, {'5', '%'}},
                    {0x07, {'6', '^'}}, {0x08, {'7', '&'}}, {0x09, {'8', '*'}}, {0x0a, {'9', '('}}, {0x0b, {'0', ')'}},
                    {0x0c, {'-', '_'}}, {0x0d, {'=', '+'}}, {0x10, {'q', 'Q'}}, {0x11, {'w', 'W'}}, {0x12, {'e', 'E'}},
                    {0x13, {'r', 'R'}}, {0x14, {'t', 'T'}}, {0x15, {'y', 'Y'}}, {0x16, {'u', 'U'}}, {0x17, {'i', 'I'}},
                    {0x18, {'o', 'O'}}, {0x19, {'p', 'P'}}, {0x1a, {'[', '{'}}, {0x1b, {']', '}'}}, {0x1e, {'a', 'A'}},
                    {0x1f, {'s', 'S'}}, {0x20, {'d', 'D'}}, {0x21, {'f', 'F'}}, {0x22, {'g', 'G'}}, {0x23, {'h', 'H'}},
                    {0x24, {'j', 'J'}}, {0x25, {'k', 'K'}}, {0x26, {'l', 'L'}}, {0x27, {';', ':'}}, {0x28, {'\'', '"'}},
                    {0x29, {'`', '~'}}, {0x2b, {'\\', '|'}}, {0x2c, {'z', 'Z'}}, {0x2d, {'x', 'X'}}, {0x2e, {'c', 'C'}},
                    {0x2f, {'v', 'V'}}, {0x30, {'b', 'B'}}, {0x31, {'n', 'N'}}, {0x32, {'m', 'M'}}, {0x33, {',', '<'}},
                    {0x34, {'.', '>'}}, {0x35, {'/', '?'}}, {0x37, {'*', '*'}}, {0x39, {' ', ' '}}, {0x47, {'7', '7'}},
                    {0x48, {'8', '8'}}, {0x49, {'9', '9'}}, {0x4a, {'-', '-'}}, {0x4b, {'4', '4'}}, {0x4c, {'5', '5'}},
                    {0x4d, {'6', '6'}}, {0x4e, {'+', '+'}}, {0x4f, {'1', '1'}}, {0x50, {'2', '2'}}, {0x51, {'3', '3'}},
                    {0x52, {'0', '0'}}, {0x53, {'.', '.'}}
                };
                 
                // .....
                 
                std::string KeycodeParser(std::vector<std::pair<uint8_t, uint8_t>>& V) {
                    std::string Ret = "";
                    bool Shift = false;
                    for (auto&& i : V) {
                        if (i.first == 0x2a || i.first == 0x36) {
                            Shift = (i.second == 0x00);
                            continue;
                        }
                        try {
                            if (i.second == 0x00) {
                                std::pair<uint8_t, uint8_t> S = MapChars.at(i.first);
                                Ret += (Shift) ? S.second : S.first;
                            }
                        } catch (std::out_of_range&) {
                            QMessageBox::warning(qApp->activeWindow(), QString("Внимание"), QString("Ключ таблицы сканкодов не найден: ") + QString(std::get<0>(i)));
                        } catch (...) {
                            QMessageBox::warning(qApp->activeWindow(), QString("Внимание"), QString("Случилось что-то страшное!"));
                        }
                    }
                    return Ret;
                }


              Надеюсь может быть кому-нить когда-нить поможет! :)
              Засим вопрос считаю пока закрытым.
                ADD: А эта регулярка для разбора данных карточки (для Люфтганзы, другие не смотрел):

                ExpandedWrap disabled
                  ^%.*?\^(.+)\^.+;(\d{4})(\d{4})(\d{4})(\d{3})=(\d{2})(\d{2}).*$

                ExpandedWrap disabled
                  Group 1. DR. ULADZIMIR NOVIK      
                  Group 2. 9922
                  Group 3. 2508
                  Group 4. 9113
                  Group 5. 628
                  Group 6. 17
                  Group 7. 02
                  Цитата JoeUser @
                  Таким образом "рыба" считывателя с использованием обсуждаемой либы такая (параллелизм считывания вне этой темы):

                  Я смотрю ты там делаешь в одном месте:
                  ExpandedWrap disabled
                    interception_send(context, device, &stroke, 1);

                  Так вот, я не знаю как у тебя, у меня наблюдались небольшие глюки с вызовом этой функции. Я даже тему на этом форме создавал. Связаны они вот с чем - ты по умолчанию скорее всего посылаешь код например нажатия клавиши(а эта функция именно как клавиатура посылает данные, равносильно физическому нажатию на кнопку). Так вот иногда бывает так, что она посылает ранее уже посланные сканы клавишь. Это скорее всего может быть связано с системным клавиатурным буфером, кнопку ты как бы нажал, но не отжал(не послал код отжатия кнопки). В итоге буфер может переполнится, и тогда из него выталкиваются лишние символы и ты получаешь ранее нажатые клавиши(но это я так думаю, возможно сам механизм работы клавиатуры и буфера я не верно понял и ошибаюсь). Поэтому буфер этот вроде как надо периодически очищать(возможно я ошибаюсь). Я бы на твоем месте потестировал пока эту программу. Посмотрел - не посылает ли она левые символы, которых быть не должно(дубликаты). Если посылает, то там надо буфер чистить. Из того что я нашел в свое время, я юзал следующий код:
                  ExpandedWrap disabled
                    MSG msg;
                    PeekMessage(&msg, 0, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE);

                  Вроде как помогало. Но были какие то ньюансы. В общем я бы на твоем месте тщательно все протестировал.
                  Либо же возможно еще можно послать код отпускания клавиши(после ее нажатия через скажем 20-50 мс), но я не помню лечится это так или нет. Давно я с этим работал, такие детали уже не помню. :-?
                  Сообщение отредактировано: Wound -
                    Wound, конечно же я еще все потестирую и не раз.

                    Цитата Wound @
                    Так вот, я не знаю как у тебя, у меня наблюдались небольшие глюки с вызовом этой функции.

                    И я даже предполагаю почему у тебя было. В моем случае (скорее всего) глюков не будет, потому как я работаю на скорости реакции картридера (сперва читаю, потом пишу и это на его скорости). А это примерно на 50мс между нажатиями/отжатиями. И мне не приходилось добавлять нажатия, а только фильтровать, сиречь - удалять. В твоем же случае, на сколько я помню, ты внедрял свою цепочку нажатий. Поэтом самым первым методом я бы смоделировал задержку перед вводом самого текста (цепочки нажатий) примерно в 75-100мс, а между нажатиями и отжатиями - не менее 50 мс.

                    Цитата Wound @
                    Либо же возможно еще можно послать код отпускания клавиши(после ее нажатия через скажем 20-50 мс)

                    Ты что!!! :blink: Это не можно - это обязательно!!! Иначе комп просто сума сойдет. Представь как должна будет реагировать система, к примеру, на нажатие уже нажатой клавиши. Я в программном варианте. И если ты отжатия клавиш не передавал - считай это и был твой источник глюков. Это даже важнее того, что я предположил сразу. Если найдешь свою старую тему, можем еще раз её глянуть.

                    Вощем, Киля, тебе еще раз спасибо - выручил!

                    З.Ы: Если и дойдут руки писать дрова, так это точно не сегодня :)
                      Цитата JoeUser @
                      Ты что!!! :blink: Это не можно - это обязательно!!! Иначе комп просто сума сойдет. Представь как должна будет реагировать система, к примеру, на нажатие уже нажатой клавиши. Я в программном варианте. И если ты отжатия клавиш не передавал - считай это и был твой источник глюков. Это даже важнее того, что я предположил сразу. Если найдешь свою старую тему, можем еще раз её глянуть.

                      Ну там я воспроизводил цепочку нажатий и очень быстро, я туда вставлял отжатие кнопки через 50 мс. Но возможно у меня слишком быстро и часто нажатия были и очень много, из за чего переполнялся буфер. Там пол часа программа тыкала по 3-5 раз в секунду, и со временем иногда бывали вот такие глюки, даже когда посылка сообщений прекращалась, еще какое то время нажимались клавиши ЕМНИП :D

                      Добавлено
                      Цитата JoeUser @
                      Вощем, Киля, тебе еще раз спасибо - выручил!

                      Пожалуйста!
                      Сообщение отредактировано: Wound -
                        Цитата Wound @
                        я туда вставлял отжатие кнопки через 50 мс

                        Это ты работал на пределе, ИМХО. К примеру, есть клавы с реакцией 60мс (универсальный интерфейс от Logitech). Я бы смело ставил 75 мс и не парился. Хотя нет - парился бы на тестах. Открыл бы блокнот и гонял бы прогу на ввод 1-2 символов на разных скоростях. Ну и нашел бы предел, когда интерфейс клавиатуры переставал бы тащить.
                        0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                        0 пользователей:


                        Рейтинг@Mail.ru
                        [ Script execution time: 0,0585 ]   [ 19 queries used ]   [ Generated: 16.04.24, 12:52 GMT ]