Перехватчик клавиатуры, выполненный по технологии NATIVE

Внешняя компонента для 1С 8.2 NATIVE для перехвата нажатий кнопок клавиатуры (включая исходники проекта на VC++ 2010).

Внешняя обработка (в толстом клиенте) предназначенная для тестирования и как пример использования. Собственно сама внешняя компонента содержится в макете обработки, в отдельном макете представлен zip-архив с проектом на Visual C++ 2010.

Реализован механизмы включения и выключения перехвата, настройки генерации события при нажатии или отпускании клавиши, настройки перехвата в при поступлении в очередь приложения или позже, блокировка стандартной обработки нажатия клавиш приложением 1С. Выходные данные представляют из себя строку с форматированным числом, которое содержит в себе виртуальный код клавиши и дополнительную информацию о кнопках Alt, Ctrl, Shift (отдельно левых и правых). После числа может быть передан символ (если он может быть интерпретирован) с учетом языковой раскладки.

 

98 Comments

  1. Angeros

    Это однозначно пядь.

    Reply
  2. cool.vlad4

    Ну ты молоток, тока ехал на работу думал очень надо подобную штуку сделать:-)

    Reply
  3. fishca

    (0) Только вот какой смысл в этой внешней компоненте, если она по технологии Native API и не используется на сервере?

    На сервере и перехватывать-то, как правило нечего. Если только злостных каких шпиёнов … 🙂

    Reply
  4. fishca

    (0) где исходники?

    Reply
  5. cool.vlad4

    (3) Как пример, мне например нужен хук, — а свои исходники на дельфи я куда-то дел, давно делал.

    (4) в макете выгрузить

    Reply
  6. fishca

    (0)

    Процедура ПриОткрытии()
    
    Макет = ПолучитьМакет(«ВнешняяКомпонента»);
    Макет.Записать(ИмяФайла);
    
    ПодключитьВнешнююКомпоненту(«C:UsersFahreevDocumentsVisual Studio 2010ProjectsKeyboardHookDebugKHook1C.dll», «Hook»,ТипВнешнейКомпоненты.Native);
    КомпонентаKeyBoardHook = Новый(«AddIn.Hook.KeyboardHook»);
    
    КонецПроцедуры
    
    

    Показать

    😀

    Где же мне искать такой путь на своем компе?

    Reply
  7. Kobra_RU

    Как всегда ошибка…

    Надо так:

    Процедура ПриОткрытии()
    
    Макет = ПолучитьМакет(«ВнешняяКомпонента»);
    Макет.Записать(ИмяФайла);
    
    ПодключитьВнешнююКомпоненту(ИмяФайла, «Hook»,ТипВнешнейКомпоненты.Native);
    КомпонентаKeyBoardHook = Новый(«AddIn.Hook.KeyboardHook»);
    
    КонецПроцедуры

    Показать

    Reply
  8. Kobra_RU
    fishca пишет:

    Только вот какой смысл в этой внешней компоненте, если она по технологии Native API и не используется на сервере? На сервере и перехватывать-то, как правило нечего. Если только злостных каких шпиёнов … 🙂

    (3) fishca,

    Вообще-то я хотел написать фронт-кассира на тонком клиенте. Подключение комфортное на тонком клиенте (через зазипованный архив в манифестом) желательно делать по новой технологии внешних компонент, а готовую такую в инете не нашел…

    Reply
  9. Kobra_RU
    fishca пишет:

    (0) где исходники?

    Надо открыть обработку в конфигураторе и сохранить макет ПроектZip в файл с расширением Zip. В этом архивнике папка с проектом. Открываем в Visual C++ 2010 как проект или как решение (solution).

    Reply
  10. fillin

    Плюс за исходники. Мне тоже ВК надо написать и тоже Native. Очень пригодится.

    Reply
  11. Kobra_RU
    fillin пишет:

    Плюс за исходники. Мне тоже ВК надо написать и тоже Native. Очень пригодится.

    (10) fillin,

    Там кое-что наворочено лишнего. Надеюсь, разберешься. Лишнее — это двусвязный список созданных объектов, которые последовательно опрашиваются в процедуре перехватчике KeyboardProc. Для чего? Если разработчик создает в форме несколько объектов из это компоненты (что лишено смысла при перехвате клавиатуры), то в стек клавиатуры не встраивается такое же количество обработчиков. Обработчик всегда один. А он уже опрашивает все объекты.

    Если будешь сам писать ВК, то про отладку:

    Я писал тестовую обработку в 1С, там я прописывал загрузку ВК dll-ки из папки debug проекта (а не из макета, как сейчас). Для отладки запускаем 1С, подключаемся к процессу 1С из Visual Studio и можем назначать точки останова в dll-ке, а вызовы инициировать из 1С (кнопками и т.п.)

    Reply
  12. Aleksey.z

    А можно реализовать что бы он перехватывал все время, а не только когда окно программы 1С активно, а например когда окно свернуто и активна в этот момент другая программа?

    Reply
  13. Kobra_RU
    Aleksey.z пишет:

    А можно реализовать что бы он перехватывал все время, а не только когда окно программы 1С активно, а например когда окно свернуто и активна в этот момент другая программа?

    13) Aleksey.z,

    Да, вроде бы можно.

    Для этого надо изменить параметры процедуры подключения перехватчика SetWindowsHookExA(WH_KEYBOARD, (HOOKPROC)KeyboardProc, 0, ThreadId). Она используется в конструкторе класса CAddInNative.

    Вместо ThreadId надо указать 0 или NULL, а в предпоследнем параметре (который сейчас 0, надо указать HINSTANCE dll-ки внешней компоненты. Она доступна в функции DllMain (файл dllmain.cpp) Нужно её просто сохранить в какую-нибудь глобальную статическую переменную и потом поставить как параметр в SetWindowsHookExA…

    Reply
  14. itlbv

    Огромное спасибо, обработка крайне помогла! Надо было срочно, свою писать времени не было, а тут очень вовремя на глаза попалась! Автору успехов!

    Reply
  15. pumbaE

    Автор, добавь плиз лицензию.

    Reply
  16. Kobra_RU
    pumbaE пишет:

    Автор, добавь плиз лицензию.

    (16) pumbaE,

    Лицензии не будет. Все в свободном доступе без всяких ограничений.

    Reply
  17. pumbaE

    (17) Ну как так, ну хотя бы BSD? У нас конечно это не распространено, если код есть, то можно использовать как хочешь (все думают). Но хотя бы авторство добавьте в комментарии.

    Reply
  18. timunya

    Есть вопрос , а вот если функция у нас возвращает char то так : TV_VT(pvarRetValue) = VTYPE_PSTR; правильно будет ?

    Reply
  19. Kobra_RU

    Нет, не правильно. VTYPE_PSTR — это судя по всему вариантное представление указателя на строку ANSI (не UNICODE), а все строки должны оканчиваться нулем. char можно передать в этот тип прогнав его через printf c форматной строкой %с. Что-то типа

    sprintf_s(указатель на буфер строки (не менее 2 символов), размер буфера,»%с», Входящая переменная char);

    А потом указатель на этот буфер и может быть VTYPE_PSTR…

    P.S.

    Хотя сейчас прочитал:

    «* значение типа VTYPE_PSTR соответствует строковому значению (char*) и находится в pstrVal с указанием длины в strLen;»

    Т.е. можно попробовать в качестве pstrVal передать ссылку на переменную типа char, а в strLen положить 1…

    Хотя я бы так не делал… char — в общем случае это не обязательно однобайтный символ…

    Reply
  20. zahar33

    Вопрос Исходник можно посмотреть? Для zahar33@mail.ru рейтинга немного не хватает.

    Reply
  21. Kobra_RU
    zahar33 пишет:

    Вопрос Исходник можно посмотреть? Для zahar33@mail.ru рейтинга немного не хватает.

    (21) zahar33, Исходники в обработке в макете зазипованы. Окрыть обработку в конфигураторе, найти макет, сохранить в файл с расширением zip…

    Reply
  22. zahar33

    Спасибо я это понял просто не мог скачать обработку, но о чудо 🙂 после добавления моего предыдущего сообщения мне хватило рейтинга я наконец его скачал,спасибо создателю и написавшему этот исходник и плюс в придачу

    Reply
  23. zahar33

    Спасибо я это понял просто не мог скачать обработку, но о чудо 🙂 после добавления моего предыдущего сообщения мне хватило рейтинга я наконец её скачал,спасибо создателю и написавшему этот исходник и плюс в придачу

    Reply
  24. zahar33

    Ведет себя неадекватно при нажатии на функциональную клавишу пишет: «В поле введены некорректные данные» приходится нажимать на Enter повторно

    Reply
  25. zahar33

    Все ясно только в случае если она назначена в 1С как сочетание клавиш

    Reply
  26. Necytij

    Нужная штука, спасибо.

    Reply
  27. dagroma

    Присоединяюсь к обществу, спасибо.

    Reply
  28. tormozit

    Как связать ввод с конкретным элементом формы или хотя бы формой?

    Сейчас получается перехват только глобальный для окна приложения. Если у меня открыто несколько форм, то в общем случае я не смогу определить активную и соответственно принять решение о корректной обработке нажатия.

    В таком виде годится лишь как средство обработки глобальных хоткеев.

    Reply
  29. Kobra_RU

    (29) tormozit,

    Сообщение поступает в главное окно приложения, где обрабатывается, а затем отражается далее конкретному получателю. Там где-то была галочка (или настройка) про перехват на уровне приложения. Так вот, это как раз и есть первый перехват. Второй поступает в форму где запущен объект только если она в фокусе. Если в фокусе будет другая форма 1С, то и сообщение поступит только одно (при поступлении в приложение)… Все это можно наблюдать в отладчике.

    Идея понятна? Она полностью имитирует систему 1С по обработке событий: первая в глобальном модуле приложения, а другая в модуле формы. Если мы сгенерируем внешнее событие, то оно поступит сначала в глобальник, а потом в активную форму и если в активной форме будет перехватчик он сработает только во втором случае (если выключен перехват на уровне приложения).

    Reply
  30. tormozit

    (30) Видимо поможет функция ВводДоступен(), с помощью которой в каждой форме можно будет определить ей оно пришло или не ней. Вот только жаль, что при большом числе открытых форм и интенсивном клавиатурном вводе будет создаваться неоправданная вычислительная нагрузка.

    Reply
  31. Kobra_RU

    Я так понимаю, что какая то форма в 1с должна получать сообщения. Ну так сделайте объект компоненты в этой форме и выключите в ней перехват на уровне приложения и все. Эта форма будет получать сообщения, предназначенные только для неё. Если какая то другая форма должна получать сообщения — там тоже объект сделайте и она тоже будет получать адресованные ей сообщения (а адресуются они ей если она в фокусе при нажатии клавиши). При этом первая форма ничего не получит.Мы можем сделать третью форму и сделать в ней объект и включить перехват как в форме, так и в приложении, тогда она будет получать сообщения как свои так и чужие. Если мы включим блокировку сообщений на уровне приложения, тогда эта третья блокировка будет получать все сообщения, а первые две формы никогда не получат свои сообщения. Так во всяком случае задумывалось. Первоисточники есть. поставьте проект и подправьте под себя, там все очень просто… А вообще я эту вещь писал для построения рабочего места кассира как заменитель кошмарного количества панелей кнопок (подход 1С), в которых все равно некоторые комбинации не отловишь…

    Reply
  32. Kobra_RU

    (31) tormozit,

    При чем здесь ВводДоступен(), он конечно будет работать на своем уровне, но к этой проблеме это не имеет никакого отношения. Проверка потока нажатий делается в самой компоненте путем анализа кода вызова callback функции при первом поступлении он один, при следующем другой. Задавите прием сообщений на уровне приложения и первый вызов компонента будет пропускать. Никакой нагрузки все это хозяйство не вызовет.

    Reply
  33. scorp_23

    Обработка может быть и хороша, но реального применения в работе какого-либо предприятия я не вижу.

    Reply
  34. Kobra_RU

    (34) scorp_23,

    Сама обработка приведена только для примера и тестирования и не несет какой-либо логики. Основное — это компонента и исходники, которые можно подстроить под себя для решения конкретной задачи.

    Reply
  35. martelix669

    Интересно можно ли написать такую компоненту на C#?

    Reply
  36. vst

    Спасибо за обработку.

    Но есть вопрос — как заставить реагировать на нажатия клавиш только активную форму, а не все открытые формы ?

    Пробовал в начале процедуры ВнешнееСобытие() делать условие на ВводДоступен(), но он возвращает «ложь» и в том случае, например, когда в форме производится подбор по колонке.

    Reply
  37. Kobra_RU

    (37) vst,

    На самом деле ВводДоступен() работает, проверил сам. Просто эта функция работает некорректно в отладчике. Вставьте её в обработку внешнего события тестовой обработки и проверьте не в режиме отладка.

    Более подробный ответ по функции ВводДоступен() можно найти в интернете. Я, например в google написал «вводдоступен ложь».

    Reply
  38. vst

    (38) спасибо, не знал про этот нюанс с отладчиком

    Reply
  39. ksa78

    Помощь надобно !!!!

    С помощь этой обработки пытаюсь штрих-коды со скатера (в режиме эмуляции клавы) получить, но чета не все данные получаю, такое ощущение, что какое то прерывание стоит большое. Можно ли как то решить эту проблему ??

    Reply
  40. ksa78

    (40) ksa78, Вопрос решил. У сканера ШК был включен турбо-режим эмуляции !!!!

    Reply
  41. ksa78

    Классная обработка !!!

    Reply
  42. ch-15

    Здравствуйте. Нужна помощь. При повторном открытии обработки появляется ошибка «не найден файл внешней компоненты», если перезапустить 1с, то обработка открывается и работает, но 1 раз, при перезапуске вываливается с той же ошибкой. Может у кого была такая проблема?

    Reply
  43. Kobra_RU

    Проверил. Ситуация воспроизвелась. В данном случае я думаю, здесь имеет место быть баг платформы 1С. Внешняя компонента подключается процедурой ПодключитьВнешнююКомпоненту(ИмяФайла, «Hook»,ТипВнешнейКомпоненты.Native), где четко указано имя файла, и этот файл существует. Однако 1С пытается получить компоненту из файла, который был создан при первом открытии обработки, который был удален при закрытии обработки (в функции ПриЗакрытии). Почему? Честно говоря, не знаю. Если временно заремить строку УдалитьФайлы(ИмяФайла);, то все заработает (правда в tmp будут висеть ненужные файлы).

    Решение: 1. Записывать dll-ку в файл с определенным именем и при открытии проверять его существование и создавать заново, если его нет.

    2. Попробовать действовать по рекомендациям 1С и устанавливать компоненту процедурой УстановитьВнешнююКомпоненту (в этом случае она записывается совершенно в другое место и не удаляется), для этого dll-ку надо положить в архив zip вместе с манифестом (см. подсказку к процедуре).

    Reply
  44. ch-15

    Спасибо за быстрый ответ!! помог первый вариант. Счастью моему нет предела)

    Reply
  45. babybu

    Спасибо. Хорошая обработка. На ее основе удалось сделать глобальный хук. А может кто подскажет, как в функцию ВК, написанную по NativeAPI, передавать массив или может структуру? В HasRetVal определил метод, как функцию, в GetNParams задал количество параметров данного метода — 1. Метод называется «Подключить». Если передаю скалярный параметр — все нормально (Компонента.Подключить(1)), а если пытаюсь передать массив или структуру (Компонента.Подключить(Массив)) — выдает ошибку- неверный аргумент.

    Reply
  46. gglvov

    Спасибо, очень нужная компонента!

    Reply
  47. gglvov

    Жаль рейтинга не хватает!

    Reply
  48. gglvov

    Раньше использовал AddHook.dll

    Reply
  49. gglvov

    Однако в управляемом приложении она не работает

    Reply
  50. gglvov

    Странно, ведь декларируется поддержка COM компонент в управляемом приложении, но работают не все компоненты.

    Reply
  51. gglvov

    ScanOPOS, например, работает

    Reply
  52. gglvov

    А AddHook.dll никак не хочет. Ни с регистрацией в реестре ни при использовании УстановитьВнешнююКомпоненту

    Reply
  53. gglvov

    Если AddHook.dll запаковать в zip c xml описанием и положить в макет, то УстановитьВнешнююКомпоненту его прекрасно устанавливает на клиенте, но ПодключитьВнешнююКомпоненту ни в какую его не подключает

    Reply
  54. gglvov

    Подскажите пожалуйста, а Ваша компонента в ВЕБ приложении будет работать?

    Reply
  55. gglvov

    Т.е. я хотел спросить имеется ли возможность скомпилировать cab xpi компоненты для браузеров? Простите за тупые вопросы, просто не имея на руках вашей компоненты трудно догадаться.

    Reply
  56. UncleVader

    Поддерживаю предыдущего оратора — надо чтобы в управляемом режиме тоже работала

    Reply
  57. kentavr27

    (57) UncleVader, дык вроде как и работает… А кто сказал что не работает? Вот, собственно, и пример использования этой компоненты в управляемом приложении для работы сканера штрих кода «в разрыв клавиатуры» с использованием внешнего события.

    Reply
  58. Caliban

    Подскажите пожалуйста — никак не могу понять, как мне обратиться к объекту, если я не использую список объектов. Т.е., что мне нужно написать вместо этой строчки pObject = listOfObjects.GetNextObjectByName(pObject, L»KeyboardHook»)?

    Reply
  59. Kobra_RU

    Не совсем понятно, зачем Вам это? В предоставленном коде просто реализован тестовый режим по созданию множества объектов. Если Вам список не нужен, то код значительно упрощается. Полностью удаляется класс ClistOfObjects и СItem. Собственно сам объект класса внешней компоненты создается в функции GetClassObject



    *pInterface= new CAddInNative();

    Сделайте глобальную переменную IComponentBase *p_Object и сохраняйте туда указатель на созданный объект CAddInNative.

    В дальнейшем используйте этот указатель вместо listOfObjects.GetNextObjectByName(pObject, L»KeyboardHook»)

    Reply
  60. Caliban

    (60) спасибо за ответ. Именно так я и догадался сделать. И еще один вопрос тогда вдогонку: а есть ли какой-нибудь способ сделать ОЖИДАНИЕ нажатия клавиши? Т.е., чтобы при вызове из 1С какой-либо функции компоненты она ожидала нажатия и возвращала уже код клавиши. Что-то типа getch().

    Reply
  61. Kobra_RU

    Поэкспериментировать с этим можно. И несложно, вроде. В native компонентах 1C есть функции установки и чтения переменных компоненты. Если в функцию чтения переменной вставить код ожидания нажатия клавиши с последующей передачей, то может что-то получиться. Попробуйте…

    Reply
  62. German

    А как сделать блокировку клавиши?

    блокировка стандартной обработки нажатия клавиш приложением 1С

    Я например регистрирую действие по Ctrl+Shift+Enter, как заблокировать Enter в этой комбинации?, а то кнопки по умолчанию нажимаются.

    код видится таким:

    КомпонентаKeyBoardHook.ЗахватПервым = Истина;
    Если ПолученноеЧисло = 10253 Тогда //в обработчике внешнего события
    КомпонентаKeyBoardHook.КлавиатураЗаблокирована=Истина;
    КонецЕсли;
    //Подождать секунду и
    КомпонентаKeyBoardHook.КлавиатураЗаблокирована = Ложь;
    Reply
  63. Kobra_RU

    Так работать скорее всего не будет, так как код клавиши уже поступил в приложение и обработан.

    Т.е. клавиатура заблокируется, но уже для следующих нажатий. Текущее пройдет. Кроме того срабатывание внешнего события в 1С вроде бы буферизировано. А это означает, что при быстром нажатии может пройти и большее количество сканкодов.

    Reply
  64. avz_1C

    Здравствуйте, уважаемый Автор.

    Могли бы Вы помочь мне разобраться с ошибкой, которая появляется при попытке перекомпилировать Вашу ВК из исходников проекта. Мой инструмент VS2015. В VS2010 перекомпиляция не производилась (инструмент не установлен).

    1>—— Перестроение всех файлов начато: проект: KHook1C, Конфигурация: Debug Win32 ——

    1> stdafx.cpp

    1> AddInNative.cpp

    1>g:1ситсвкkeyboardhookvsprjvknative2010khook1c-vc++ ypes.h(67): error C2371: int8_t: переопределение; различные базовые типы

    1> d:vs2015vcincludestdint.h(17): note: см. объявление «int8_t»

    ========== Перестроение всех: успешно: 0, с ошибками: 1, пропущено: 0 ==========

    Reply
  65. avz_1C

    Уважаемый автор, извините за беспокойство.

    Разобрался сам. Перекомпилировал Вашу ВК в VS2013 и VS2015.

    Проверил обе новых перекомпилированных версии путём записи в макет Вашей тестовой обработки. Всё работает.

    Если Вы разрешите, я выложу здесь ссылку на скачивание всех трёх проектов (VS2010, VS2013, VS2015).

    Если так делать нельзя, то могу прислать ссылку Вам, а Вы включите все три проекта в файлы данной статьи.

    Reply
  66. Kobra_RU

    (66) avz_1C,

    Выкладывайте самостоятельно. Никаких ограничений на переделку и использование (включая публикацию доработанных вариантов) нет…

    Reply
  67. avz_1C

    С разрешения автора выкладываю архивы с проектами данной ВК.

    Перекомпилированы в VS2013 и VS2015.

    Всё работает так, как положено.

    Вставляются в тестовую обработку автора, для проверки, путём замены двоичного макета на скомпилированную из этих проектов dll-ку.

    Reply
  68. VGHOST

    (64)

    Здравствуйте.

    Аналогичная проблема — кнопки обрабатываются формой до вызова обработчика ВнешнееСобытие(), и моменты отключения и включения клавиатуры с небогатым набором событий элементов диалога не отследить…

    Пробовал полностью обслуживать ввод с клавиатуры для единственной таблицы формы, но опять же, с «богатым» 1C-API это невозможно, да и хочется сбросить всю возможную работу на платформу.

    Предлагаю добавить компоненте метод Отправть() (Send()), который просто отправляет нажатие в дальнейшую обработку с того места, где он его перехватил, с единственным аргументом, который передается в параметре Данные обработчика ВнешнееСобытие() (какая-то странная смесь сканкодов с символом на конце — без документации разобраться не удалось).

    Это позволит фильтровать ввод при КлавиатураЗаблокирована=Истина.

    Реализуйте, пожалуйста, данную простую функцию, жутко не хочется прикручивать дополнительные ВК или разворачивать VisualStudio (за последние 20 лет основательно забыл что такое компилятор :).

    Заранее Спасибо!

    ЗЫ: 1С с некоторых пор позволяет устанавливать/загружать ВК прямо из макета, содержащего zip-файл с бибилиотеками для разных платформ и манифестом (во вложении, пришлось помучаться с его форматом) — можно по случаю скомпилить под x86_64 и выложить.

    Reply
  69. VGHOST

    Если ВК будет дорабатываться — неплохо бы флаг СобытиеПриНажатии (корректнее при Опускании, OnKeyDown) дополнить флагом СобытиеПриОтжатии, чтобы была возможность ловить оба одновременно. СобытиеПриНажатииОтжатии (OnKeyPress), которое воспринимает клавиши модификаторы только как дополнительные флаги и не генерируется при их нажатии, тоже бы не помешало — требуется чаще первых двух…

    Разобрался таки со структурой возвращаемых данных.

    Прошу включить в выложенную обработку код из вложения, выводящий отдельные поля в табло — пригодится при использовании ВК на практике.

    Там же код подключения ВК для модуля управляемой формы.

    Reply
  70. efin

    (66) avz_1C, Подскажите, как это исправляется? Ловлю аналогичную ошибку в другом старом проекте ВК.

    Reply
  71. boldinov

    Подскажите, в чем проблема при загрузки ВК из Макета, не возвращается Кириллица(непечатные символы), если подключать из файла все работает?

    Reply
  72. Yashazz

    При подключении выдаёт: «Возможно, отсутствует компонента для используемого клиентского приложения».

    Команда УстановитьВнешнююКомпоненту(«ВнешняяОбработка.Тест1.Макет.KeyboardHook») налетает на эту ошибку.

    Что делал: скачал обработку, взял из макета «ВнешняяКомпонента» бывшие там двоичные данные, сохранил с именем KeyboardHook.dll, взял рекомендованный в (69) манифест, сунул манифест и dll в zip-архив, а архив сунул в макет этой внешки, под именем KeyboardHook. Запуск под толстый клиент, управляемое приложение, модальность и синхронность разрешены. 1С 8.3.6.2449, 32-х разрядная, файловый вариант БД. Что я делаю не так?

    Reply
  73. Kobra_RU

    (73) Yashazz,

    т.е манифест такой?

    <?xml version=»1.0″ encoding=»UTF-8″?>

    -<bundle xmlns=»http://v8.1c.ru/8.2/addin/bundle»>

    <component arch=»i386″ type=»native» path=»KeyboardHook.dll» os=»Windows»/>

    <component arch=»x86_64″ type=»native» path=»KeyboardHook64.dll» os=»Windows»/>

    </bundle>

    А откуда у тебя берется KeyboardHook64.dll??? Его же по факту нет… Сотри строчку «<component arch=»x86_64″ type=»native» path=»KeyboardHook64.dll» os=»Windows»/>» из манифеста, засунь в архив и попробуй ещё раз. А вообще x64 native для 1С в качестве перехвата клавиатуры ИМХО не нужна. Клиентские части 1С 32 битные все…

    Reply
  74. user592752_kumadil

    Не подскажите, как ее использовать в УФ?

    Reply
  75. ture

    Я думал стану хакером, когда освою эту технологию! А оказалось процедура перехвата регается в винде под конкретные события, как делегаты в шаурме. Так, я не понял, почему до меня не доходит F1 и как поднять мою процедуру выше 1ссышной, чтоб это до неё не доходило F1, а не до меня?

    И, да, ну вы и накрутили с компонентой… нет я понимаю, что один раз не …, но все же при таком владение api windows, я ожидал заработать скорее комплекс неполноценностей.

    Reply
  76. user608116_3830123

    (14) Напишите, пожалуйста, измененный код. А-то трудно сообразить какие изменения нужно сделать, чтобы захват производился в не программы

    Reply
  77. user608116_3830123

    (77) 1) в файле stdafx.h я объявил переменную global_var:

    #include <windows.h>

    static HMODULE global_var;

    2) Затем в файле dllmain.cpp этой переменной назначил HINSTANCE:

    global_var = hModule;

    switch (ul_reason_for_call)…

    3) Затем в функцию SetWindowsHookExA указал параметры:

    SetWindowsHookExA(WH_KEYBOARD, (HOOKPROC)KeyboardProc, global_var, NULL);

    Но так не работает.. Подскажите, пожалуйста, что я делаю неправильно…

    Reply
  78. user608116_3830123

    Подскажите еще вопрос: Как отказаться от нажатия клавиши Caps Lock?

    Reply
  79. Sasha_61rus

    Добрый день.

    После обновления платформы до версии 8.3.10.2168 обнаружилась следующая особенность: компонента корректно работает только если присвоить свойству «ЗахватПервым» («FirstInterception») значение «Ложь» (а именно не выполняется (точнее, выполняется только если быстро нажать клавиш пять) условие «nCode == Action», где «int Action = (pm->m_FirstInterception ? HC_NOREMOVE : HC_ACTION)»).

    Разобравшись в исходниках, получилось скомпилировать под Win. x64 (перенёс процедуру «GetClassNames» из примера с диска ИТС — без этого ВК не подключалась в 64-х разрядной версии платформы).

    К посту прикреплены:

    — полученный архив с компонентами («KHook1C_x32.dll» и «KHook1C_x64.dll») и манифестом для их подключения к 1С (zip-архив создавался средствами 1С) (файл «KHook1C.zip»);

    — полученный проект для студии 2017 (файл «KHook1C_VS2017.7z»);

    — выгрузка тестовой базы, на которой проверялась работоспособность компоненты (файл «База для тестирования.dt»).

    Reply
  80. Oegir

    Привет.

    Использую сканер Штрих-Кодов в режиме эмуляции клавиатуры совместно с этой компонентой. В Windows 10 вылезла странная проблема: в 1С поступают различные данные при перехвате событий клавиатуры и сканера.

    Например, при нажатии клавиши f на клавиатуре в обработчик внешнего события поступают данные 00070f. Я закодировал в штрих-код Code-128 единственную букву F, при ее сканировании в данных оказывается 16400 независимо от раскладки клавиатуры.

    При этом нажатие клавиши и ее сканирование из Code-128 дают одинаковый результат 00189-, цифры также сканируются корректно. Ткните куда и что смотреть в исходниках dll-ки или может настройками сканера можно вырулить.

    ЗЫ: В C++ не силен, только Страуструпа лет 10-15 назад читал.

    Reply
  81. Kobra_RU

    Windows 10 не использую, т.к. с ней до сих пор возникают разные проблемы (по оборудованию, в основном), поэтому воспроизвести проблему не смогу. Разобраться в проблеме можно только если иметь навыки отладки приложений в VС++. Если такие навыки есть далее все очень просто. Точка останова в процедуре перехвата LRESULT CALLBACK KeyboardProc(int nCode,WPARAM wParam, LPARAM lParam) и пошаговая отладка, все как в 1С. Проблема, я так понял в эмуляции одновременного нажатия клавиш shift + f (а скорее всего любой клавиши).

    Перехватывается у вас код 16400. В шестнадцатиричном виде это 0x4010, состав возвращаемого кода можно посмотреть в файле Addinnative.cpp строки начиная с 395. Итак, Возвращается нажатие правого Shift и виртуального кода 0x10. Расшифровку виртуального кода можно посмотреть по таблице в MSDN, откуда видно, что это VK_SHIFT. Т.е. сканер у вас выдает нажатие shift, по идее после этого должен идти код нажатия клавиши f, однако его нет.

    Советую особо проанализировать строки:

    bool KeyPressed = !((DWORD)lParam & 0x40000000);

    if ((pm->m_EventOnKeyPressed && KeyPressed) || (!pm->m_EventOnKeyPressed && !KeyPressed))

    На самом деле бит 30 — это предыдущее состояние клавиши, т.е KeyPressed это не клавиша нажата, а если точно, клавиша была отжата до операции перехвата. Для обычной клавиатуры так и есть, однако драйвер сканера может посылать несколько нажатий клавиши не отпуская её. Может быть имеет смысл попробовать заменить на строку:

    bool KeyPressed = !((DWORD)lParam & 0x80000000); бит 31 — это именно текущий переход состояния клавиши =0 если клавиша нажата, = 1 если клавиша отпущена. Через операцию отрицания получаем правильное состояние KeyPressed.

    В любом случае точно все можно определить только в отладчике, при вскрытии, так сказать…

    Что бы не заморачиваться, в Вашем случае советую попробовать обычную scanopos.dll (драйвер сканера штрих кода от 1С) последних версий. Там есть ввод со сканера штрихкода в режиме эмуляции клавиатуры.

    Reply
  82. Flok

    Отличная компонента , все работает — спасибо !

    Reply
  83. WellMaster

    Доброго дня.

    Как подключить компоненту в Управляемых формах?

    Reply
  84. Wladimir_spb

    (84) В сообщении (70) приведен рабочий код. Достаточно просто скопировать его в модуль формы и привязать обработчики.

    Reply
  85. Wladimir_spb

    Что значит «Перехват при поступлении в очередь приложения» и «Перехват при передаче сообщения внутри приложения»?

    У меня при установке флага ЗахватПервым = Истина, большая часть нажатий не перехватывается вообще. А в режиме ЗахватПервым = Ложь ловит все нажатия.

    Reply
  86. Wladimir_spb

    (84)

    &НаКлиенте
    // Пример подключения прямо из макета обработки с управляемыми формами на платформе 8.3.5.1383.
    // Обработку при этом регистрировать в менеджере внешних обработок не нужно, сохранять файл на диске — тоже.
    //
    // Подключает ВК KeyboardHook.
    // НачатьУстановкуВнешнейКомпоненты() помещает файл компоненты и его описание из манифеста в локальное хранилище на клиенте,
    // откуда потом его забирает ПодключитьВнешнююКомпоненту().
    // Непонятно, зачем такие сложности, если все равно каждый раз читается содержимое макета, но с 1С не поспоришь…
    //
    // Макет KeyboardHook должен содержать zip-архив с библиотеками для разных платформ и манифестом, описывающим содержимое.
    // Примеры манифеста можно найти в сети по строке «http://v8.1c.ru/8.2/addin/bundle».
    //
    Процедура ПерехватКлавиатурыПодключить(Знач Оповещение=Ложь) Экспорт
    Если ПодключитьВнешнююКомпоненту(«ВнешняяОбработка.KeyboardHook.Макет.KeyboardHook», «KeyboardHook», ТипВнешнейКомпоненты.Native) Тогда
    ПерехватКлавиатуры = Новый(«AddIn.KeyboardHook.KeyboardHook»);
    ПерехватКлавиатуры.ЗахватРазрешен = Истина; // генерировать внешние события
    ПерехватКлавиатуры.СобытиеПриНажатии = Истина; // при отпускании иногда клавиши-модификаторы уже отжаты
    ПерехватКлавиатуры.ЗахватПервым = Истина; // не работает — все равно событие успевает отрабатываться в форме
    
    ИначеЕсли НЕ Оповещение Тогда // процесс установки не инициирован ранее, начинаем новый
    ПерехватКлавиатуры = Неопределено;
    Оповещение = Новый ОписаниеОповещения(«ПерехватКлавиатурыПодключить», ЭтотОбъект, Истина);
    НачатьУстановкуВнешнейКомпоненты(Оповещение, «ВнешняяОбработка.KeyboardHook.Макет.KeyboardHook»);
    КонецЕсли;
    КонецПроцедуры
    
    &НаКлиенте
    Процедура ПриОткрытии(Отказ)
    ПерехватКлавиатурыПодключить();
    КонецПроцедуры
    

    Показать

    В макет KeyboardHook нужно загрузить KHook1C.zip из поста (80)

    Reply
  87. WellMaster

    (87) Не работает этот метод.

    Пробовал и так и так.

    Есть готовый рабочий пример работы компоненты на управляемых формах?

    Reply
  88. Kobra_RU

    Внешняя компонента уже довольно старая :). Тем не менее еще при разработке проводилось тестирование в тонком клиенте еще на платформе 8.2. Все тонкости можно посмотреть в исходниках проекта. Конкретно про ЗахватПервым.

    При работе с клавиатурой нажатия (отпускания, сканкоды и т.д. и т.п.) поступают в очередь приложения туда же поступают и управляющие флаги. Один из этих флагов nCode.

    LRESULT CALLBACK KeyboardProc(int nCode,WPARAM wParam, LPARAM lParam)

    nCode может иметь разные значения, нас интересует 2 — HC_NOREMOVE и HC_ACTION.

    HC_NOREMOVE это не убирать из очереди и передать следующему обработчику.

    HC_ACTION обработать.

    Нажатие поступает в главное окно приложения и если оно не предназначено для него, а предназначено для окна какой либо формы (дочернего окна), то значение флага будет HC_NOREMOVE, а для конечного окна (которое в фокусе ввода) будет опять сработка но с кодом HC_ACTION.

    Так вот. Если ЗахватПервым = Истина, то перехват идет при сработках с флагом HC_NOREMOVE, а если ЗахватПервым = Ложь — то с флагом HC_ACTION.

    Отсюда и названия «Перехват при поступлении в очередь приложения» и «Перехват при передаче сообщения внутри приложения», конечно это все упрощенно…

    Reply
  89. Wladimir_spb

    (88)Если автор не возражает, то могу выложить

    Reply
  90. Wladimir_spb

    (89)Спасибо за подробное пояснение

    Reply
  91. WellMaster

    (90) Можно прикрепить к сообщению, как это делают выше.

    Reply
  92. Wladimir_spb

    (92)Можно, только выше все сначала спрашивают автора разработки

    И я думаю, что это правильно. Если Эмиль разрешит здесь выложить, то без проблем.

    Reply
  93. WellMaster

    (93) В принципе, я уже разобрался как подключить. Правда использовал пример конфигурации из (80).

    Оттуда же и сохранил себе макет в общие макеты, т.к. макет из обработки из статьи не заработал.

    Reply
  94. Kobra_RU

    Я сейчас не отслеживаю (и не использую) эту компоненту. Поэтому и ранее писал и сейчас сообщаю: Можно использовать, видоизменять, публиковать здесь ссылки (если это не нарушает правил, установленных infostart-ом).

    Reply
  95. Неопределено

    (0) Что-то не взлетает, выдавая ошибку при открытии:

    {ВнешняяОбработка.KeyboardHook.Форма.Форма.Форма(123)}: Тип не определен (AddIn.Hook.KeyboardHook)

    КомпонентаKeyBoardHook = Новый(«AddIn.Hook.KeyboardHook»);

    8.3.10.2252, обычное приложение, толстый клиент.

    Reply
  96. Kobra_RU

    (106) Только что проверил на платформе 8.3.10.2667. Все нормально. Единственно после выдачи разрешения на открытие внешней обработки и подключения бинарных файлов закрыл и открыл опять обработку.

    Код по подключению очень простой

    ИмяФайла  = КаталогВременныхФайлов()+»Hook1c.dll»;
    
    Макет = ПолучитьМакет(«ВнешняяКомпонента»);
    Макет.Записать(ИмяФайла);
    
    ПодключитьВнешнююКомпоненту(ИмяФайла, «Hook»,ТипВнешнейКомпоненты.Native);
    КомпонентаKeyBoardHook = Новый(«AddIn.Hook.KeyboardHook»);
    

    Показать

    Так как ошибка «Тип не определен» не происходит подключение внешней компоненты. Т.е. либо включена защита на подключение бинарных файлов, либо что-то с каталогом временных файлов.

    Reply
  97. Kobra_RU

    (106)Кстати, пришло в голову… dll-ка написана и откомпилирована на VC++ 2010. Может в системе не установлен пакет Visual C++ 2010 Redistributable? И кстати с разрядностью надо смотреть, платформа 1С у Вас x32 или x64? dll-ка сделана под 32 разрядную платформу.

    Reply
  98. Неопределено

    (108) И пакет не установлен, и платформа x64. Уже решил задачу, для которой качал, другим путём.

    Reply

Leave a Comment

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