Имя: Пароль:
1C
 
Внешняя компонента для генерации внешнего события при клавиатурном вводе
,
0 TormozIT
 
гуру
29.09.20
23:48
Заюзал внешнюю компоненту с исходниками для перехвата клавиатурного ввода http://forum.infostart.ru/forum28/topic42414/message1778089/#message1778089
Компонента отправляет внешнее событие при каждом физическом нажатии.
Но если я удерживаю клавишу (например клавишу "Вниз"), то хочу чтобы и логические нажатия начали циклически приходить. А они не генерируются этой компонентой.
Если вам известна подобная компонента для 1С, которая умеет генерировать события при удержании клавиш, поделитесь со мной.
1 TormozIT
 
гуру
30.09.20
00:23
Эх. Надо было в заголовок добавить "Вызов для настоящих ГУРУ"
2 TormozIT
 
гуру
30.09.20
08:21
Ап
3 Ёпрст
 
30.09.20
08:49
(0) так подойдет ?
https://cloud.mail.ru/public/2u3e/463pBSYsk

ОФ :)
4 TormozIT
 
гуру
30.09.20
09:08
(3) Нет. Думаю нужно раз в 50 больше времени потратить чтобы решить эту задачу. Наверняка кто то уже прошел этот путь. Жду его здесь, чтобы не проходить этот путь самому.
5 Garykom
 
гуру
30.09.20
09:11
(4) Бесплатно?
6 TormozIT
 
гуру
30.09.20
09:12
(5) Сколько просишь?
7 Garykom
 
гуру
30.09.20
09:13
(6) За совет нисколько. За реализацию хз.

Совет: "настройки генерации события при нажатии или отпускании клавиши"
8 Кирпич
 
30.09.20
09:17
Там же исходники есть
9 TormozIT
 
гуру
30.09.20
09:18
(8) Может тогда подскажешь и где там что изменить?
10 Кирпич
 
30.09.20
09:22
(9) Так это смотреть надо :)
11 TormozIT
 
гуру
30.09.20
09:27
(10) Я посмотрел. Мне не помогло.
12 Злопчинский
 
30.09.20
09:29
Узнал все буквы, но не смог прочитать слово... ;-)
13 TormozIT
 
гуру
30.09.20
09:31
LRESULT CALLBACK KeyboardProc(int nCode,WPARAM wParam, LPARAM lParam)
{

    wchar_t output[300];

    bool    QueueEnabled    = true;

    if (nCode == HC_ACTION || nCode == HC_NOREMOVE)
    {
        IComponentBase *    pObject    = 0;

        pObject    = listOfObjects.GetNextObjectByName(pObject, L"KeyboardHook");
        while (pObject)
        {

            CAddInNative *pm = dynamic_cast< CAddInNative* >(pObject);

            int Action    = (pm->m_FirstInterception ? HC_NOREMOVE : HC_ACTION);
            
            if (pm->m_HookEnabled && (nCode == Action))
                {

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

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

                    unsigned int RepeatCount    = (DWORD) lParam & 0xFFFF;
                    unsigned int ScanCode        = ((DWORD) lParam >> 16) & 0xFF;
                    unsigned int ExtendedKey        = (((DWORD) lParam >> 24) & 0x01);
                    unsigned int PreviousKeyState    = (((DWORD) lParam >> 30) & 0x01);
                    unsigned int VirtualKey            = wParam;

                    BYTE keystatebuff[256];
                    wchar_t SymbolString[10];

                    ::wmemset(SymbolString,0,10);

                    if (::GetKeyboardState(keystatebuff))
                    {

                        unsigned int ExtScanCode    = ScanCode;
                        unsigned int flags            = (((DWORD) lParam >> 29) & 0x0001) ^ 0x0001;
                        int numsymbol    = ::ToUnicode(VirtualKey, ExtScanCode, keystatebuff, SymbolString, 10, flags);
                        if (numsymbol == 10)
                            ::wmemset(SymbolString,0,10);

                    }

                    ULONG    ReturnCode    = 0;

                    if (::GetKeyState(VK_LSHIFT) & 0x80)
                        ReturnCode = ReturnCode | 0x1;
                    ReturnCode <<= 1;
                    if (::GetKeyState(VK_RSHIFT) & 0x80)
                        ReturnCode = ReturnCode | 0x1;
                    ReturnCode <<= 1;
                    if (::GetKeyState(VK_LCONTROL) & 0x80)
                        ReturnCode = ReturnCode | 0x1;
                    ReturnCode <<= 1;
                    if (::GetKeyState(VK_RCONTROL) & 0x80)
                        ReturnCode = ReturnCode | 0x1;
                    ReturnCode <<= 1;
                    if (::GetKeyState(VK_LMENU) & 0x80)
                        ReturnCode = ReturnCode | 0x1;
                    ReturnCode <<= 1;
                    if (::GetKeyState(VK_RMENU) & 0x80)
                        ReturnCode = ReturnCode | 0x1;
                    ReturnCode <<= 1;
                    ReturnCode = ReturnCode | ExtendedKey;
                    ReturnCode <<= 8;
                    ReturnCode = ReturnCode | (VirtualKey & 0x00FF);

                    int StringLength    = swprintf_s(output, 300, L"%05u%s", ReturnCode, SymbolString);

                    pm->SendEvent(output);

                }
                QueueEnabled    = QueueEnabled & !pm->m_KeyboardLocked;
            }
            pObject    = listOfObjects.GetNextObjectByName(pObject, L"KeyboardHook");
        }

    }

    if (nCode < 0 || QueueEnabled)
    {
        LRESULT RetVal = CallNextHookEx( CAddInNative::m_KeyBoardHook, nCode, wParam, lParam );
        return  RetVal;
    }

    return -1;

}
14 Garykom
 
гуру
30.09.20
09:34
Зачем менять в C++ когда можно в 1С?
15 Garykom
 
гуру
30.09.20
09:35
(10) Не надо ничего смотреть блин.

ВК делает события на нажатия и ОТПУСКАНИЯ кнопок. Ну?
16 Garykom
 
гуру
30.09.20
09:40
(0) >Если вам известна подобная компонента для 1С, которая умеет генерировать события при удержании клавиш, поделитесь со мной.

ВК должна делать разные события при
1. Нажатии кнопки
2. Отпускании кнопки
3. Циклическое событие между нажатием и отпусканием? А с какой частотой?
17 Garykom
 
гуру
30.09.20
09:43
(16)+ Упс просто частоту указать в ВК недостаточно, там нужно указывать время после первоначального нажатия (чтобы избежать "ааа" когда хотели просто "а" но задумались) и затем время повторов.
18 TormozIT
 
гуру
30.09.20
09:45
(15) Юзер нажал клавишу и держит ее нажатой. При этом через паузу в 1-2 сек в очередь событий приложения WinAPI начинает слать циклически с задержкой типа 50мс (repeat rate) события нажатия и отпускания этой клавиши, хотя физически она не меняет состояние.
А эта ВК шлет только при физических изменениях состояния клавиши, причем либо только при нажатии, либо только при отпускании. Ну это я смогу доработать конечно - будет допустим слать и при нажатии и при отпускании. Но мне надо циклически генерировать нажатия и ровно также как это делает WinAPI, чтобы юзер не почуял разницы.
19 Кирпич
 
30.09.20
09:46
(13) Лучше тест на 1с покажи. На чем пробовать
20 Garykom
 
гуру
30.09.20
09:55
(18) Вот эту строчку
if ((pm->m_EventOnKeyPressed && KeyPressed) || (!pm->m_EventOnKeyPressed && !KeyPressed))
исправь и будет слать и при нажатии и при отпускании
21 Кирпич
 
30.09.20
10:05
А может оно и не должно работать на повтор. Может там надо ставить хук на WH_KEYBOARD_LL, а не на WH_KEYBOARD
22 trad
 
30.09.20
10:21
(20) ты предлагаешь сидеть в цикле в одинесе пока нажата и не отпущена клавиша?
23 Garykom
 
гуру
30.09.20
10:24
(22) Логично что на сервере в 1С нет смысла в кнопках, значит клиент.
На клиенте в формах есть ПодключитьОбработчикОжидания
24 TormozIT
 
гуру
30.09.20
10:25
(23) 50мс?
25 Garykom
 
гуру
30.09.20
10:26
(24) "<Интервал> (обязательный)
Тип: Число.
Интервал времени в секундах с точностью до 1/10 секунды, через который будет осуществляться вызов процедуры (положительное число)."

100мс можно
26 trad
 
30.09.20
10:30
(23) "Логично что на сервере в 1С нет смысла в кнопках, значит клиент."
Логично, кто ж спорит ))
27 trad
 
30.09.20
10:32
(23) "ПодключитьОбработчикОжидания"
А в какой момент отключать обработчик?
На кейап?
А если он случился не в фокусе?
28 trad
 
30.09.20
10:35
Я не изучал как устроен этот кхук с иса, но знаю что WM_KEYDOWN генерится и при физическом нажатии и при автоповторе
29 Garykom
 
гуру
30.09.20
10:38
(27) Вне 1С? Ну это засада с данной ВК в целом
30 trad
 
30.09.20
10:42
(29) Ну конечно вне 1с.
Организовывать автоповтор внутри, в данной ситуации, бесперспективная затея
31 trad
 
30.09.20
10:44
Посмотрел.
Там где-то вокруг вот этого надо поплясать
int Action    = (pm->m_FirstInterception ? HC_NOREMOVE : HC_ACTION);
и выкурить это блокирование автоповтора
32 trad
 
30.09.20
10:45
более полная цитата:
int Action    = (pm->m_FirstInterception ? HC_NOREMOVE : HC_ACTION);
  if (pm->m_HookEnabled && (nCode == Action))
33 TormozIT
 
гуру
30.09.20
11:01
(32) Если ты думаешь, что "m_FirstInterception" это типа "первое нажатие", то нет. Это "перехват первым до обработки приложением".
34 trad
 
30.09.20
11:04
(33) слабо мне понятная муть ))
35 TormozIT
 
гуру
30.09.20
11:10
(34) Это объяснение от автора ВК.
36 TormozIT
 
гуру
12.10.20
16:20
Заработало. Опубликовал код тут https://github.com/tormozit/KeyboardHook_1C
Вот исправленная процедура - хук тот же самый.

LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    wchar_t output[300];
    bool QueueEnabled = true;
    if (nCode == HC_ACTION || nCode == HC_NOREMOVE)
    {
        IComponentBase * pObject = 0;
        pObject    = listOfObjects.GetNextObjectByName(pObject, L"KeyboardHook");
        while (pObject)
        {
            CAddInNative *pm = dynamic_cast< CAddInNative* >(pObject);
            if (pm->m_HookEnabled)
            {
                unsigned int TransitionState = (((DWORD)lParam >> 31) & 0x01);
                if (TransitionState == 0)
                {
                    unsigned int RepeatCount = (DWORD) lParam & 0xFFFF;
                    unsigned int ScanCode = ((DWORD) lParam >> 16) & 0xFF;
                    unsigned int ExtendedKey = (((DWORD) lParam >> 24) & 0x01);
                    unsigned int PreviousKeyState = (((DWORD) lParam >> 30) & 0x01);
                    unsigned int VirtualKey    = wParam;
                    BYTE keystatebuff[256];
                    wchar_t SymbolString[10];
                    ::wmemset(SymbolString,0,10);
                    if (::GetKeyboardState(keystatebuff))
                    {
                        unsigned int ExtScanCode = ScanCode;
                        unsigned int flags= (((DWORD) lParam >> 29) & 0x0001) ^ 0x0001;
                        int numsymbol = ::ToUnicode(VirtualKey, ExtScanCode, keystatebuff, SymbolString, 10, flags);
                        if (numsymbol == 10)
                            ::wmemset(SymbolString,0,10);
                    }
                    ULONG    ReturnCode    = 0;
                    if (::GetKeyState(VK_LSHIFT) & 0x80)
                        ReturnCode = ReturnCode | 0x1;
                    ReturnCode <<= 1;
                    if (::GetKeyState(VK_RSHIFT) & 0x80)
                        ReturnCode = ReturnCode | 0x1;
                    ReturnCode <<= 1;
                    if (::GetKeyState(VK_LCONTROL) & 0x80)
                        ReturnCode = ReturnCode | 0x1;
                    ReturnCode <<= 1;
                    if (::GetKeyState(VK_RCONTROL) & 0x80)
                        ReturnCode = ReturnCode | 0x1;
                    ReturnCode <<= 1;
                    if (::GetKeyState(VK_LMENU) & 0x80)
                        ReturnCode = ReturnCode | 0x1;
                    ReturnCode <<= 1;
                    if (::GetKeyState(VK_RMENU) & 0x80)
                        ReturnCode = ReturnCode | 0x1;
                    ReturnCode <<= 1;
                    ReturnCode = ReturnCode | ExtendedKey;
                    ReturnCode <<= 8;
                    ReturnCode = ReturnCode | (VirtualKey & 0x00FF);
                    int StringLength = swprintf_s(output, 300, L"%05u%s", ReturnCode, SymbolString);
                    pm->SendEvent(output);
                }
                QueueEnabled = QueueEnabled & !pm->m_KeyboardLocked;
            }
            pObject    = listOfObjects.GetNextObjectByName(pObject, L"KeyboardHook");
        }
    }
    if (nCode < 0 || QueueEnabled)
    {
        LRESULT RetVal = CallNextHookEx( CAddInNative::m_KeyBoardHook, nCode, wParam, lParam );
        return  RetVal;
    }
    return -1;
}