1 (изменено: dmitry-semin, 2020-05-20 11:13:55)

Тема: AHK: DllCall() и GetKeyboardState

Доброго всем времени суток!
Есть задача: получать vk код нажатой клавиши в цикле.
Я застопорился уже на том, что не могу вывести нажата ли вообще клавиша (любая).
Я прочитал, как мне кажется внимательно, раздел DllCall() и GetKeyboardState на https://docs.microsoft.com/en-us/window … boardstate

То, к чему я пришёл выглядит следующим образом:


#Persistent
#SingleInstance force
if not (A_IsAdmin or RegExMatch(full_command_line, " /restart(?!\S)"))
{
try
{
if A_IsCompiled
Run *RunAs "%A_ScriptFullPath%" /restart
else
Run *RunAs "%A_AhkPath%" /restart "%A_ScriptFullPath%"
}
ExitApp
}
#InstallKeybdHook
#InstallMouseHook
#UseHook
VarSetCapacity(lpKeyState,256,0)

loop 
{
Result := DllCall("GetKeyboardState" , PBYTE, lpKeyState, "BOOL")
ToolTip,
    (
    Result is %Result%
    lpKeyState is %lpKeyState%
    )
}
return

Ну и само собой не работает.

Находил на форуме

http://forum.script-coding.com/viewtopic.php?id=3854

похожий код, но не понял как он работает и почему не работает у меня.

Видимо синтаксис DllCall не понимаю.
Прошу указать на ошибки.
Спасибо.

2

Re: AHK: DllCall() и GetKeyboardState

Ну, начнём с того, что у вас в коде нет GetKeyboardState.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

3

Re: AHK: DllCall() и GetKeyboardState

teadrinker
Извиняюсь, пробовал другие функции, видимо забыл убрать. Тем не менее вопрос актуален.

4

Re: AHK: DllCall() и GetKeyboardState

Теперь попробуйте на словах описать, что этот код должен делать, и как именно он должен работать.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

5

Re: AHK: DllCall() и GetKeyboardState

teadrinker
Постараюсь.

teadrinker пишет:

что этот код должен делать

Вообще моя конечная цель это получение массива в котором VK коду будет соответствовать статус 0 или 1 в зависимости от статуса клавиши в момент выполнения функции.
Но я не могу корректно перевести код приведенный в документации https://docs.microsoft.com/en-us/window … boardstate для С++ на логику AHK.

teadrinker пишет:

как именно он должен работать.

На текущем этапе, в моём понимании когда я нажимаю любую клавишу в момент выполнения цикла переменная Result должна стать равной единице и отобразиться в Tooltip
В дальнейшем я планирую из массива lpKeyState вытащить какая именно клавиша нажата. Идея взята из описания параметра lpKeyState

The 256-byte array that receives the status data for each virtual key.

6

Re: AHK: DllCall() и GetKeyboardState

Почти всё верно, только почему вы решили, что значение result будет зависеть от статуса одной клавиши? Это просто показатель успешного или неуспешного выполнения всей функции.

Result := DllCall("GetKeyboardState" , PBYTE, lpKeyState, "BOOL")

Говорите, прочитали документацию по DllCall, тогда что такое у вас PBYTE и BOOL? Почему одно в кавычках, другое — нет? Читайте внимательно раздел Types of Arguments and Return Values.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

7

Re: AHK: DllCall() и GetKeyboardState

teadrinker
Забегу немного вперёд, а можно без перебора узнать что в переменной не только нули?


VarSetCapacity(state, 256, 0) 

NumPut(-128, state, 0x10 , "Char")  

Loop % VarSetCapacity(state)
	If NumGet(&state, A_Index, "Char") < 0 && (b := 1)
		break
		
MsgBox % b ? "Не все нули" : "Все нули"
По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru
Win10x64, AutoHotkey_L v1.1.32.00 (Unicode 32-bit). AhkSpy, Hotkey, ClockGui

8

Re: AHK: DllCall() и GetKeyboardState

Легко:

VarSetCapacity(empty, 256, 0)
VarSetCapacity(state, 256, 0) 

NumPut(-128, state, 0x10 , "Char")

b := DllCall("msvcrt\memcmp", "Ptr", &empty, "Ptr", &state, "Ptr", 256)
MsgBox % b ? "Не все нули" : "Все нули"
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

9

Re: AHK: DllCall() и GetKeyboardState

Исправил саму функцию (не исправил, а попытался).

Result := DllCall("GetKeyboardState" , "UChar", lpKeyState, "int")

int потому, что

An Int should also be used for each BOOL argument expected by a function (a BOOL value should be either 1 or 0).

Char потому, что

An unsigned character (UChar) can be used with functions that expect a BYTE.

На самом деле пробовал этот вариант уже. Он не работает.
Я вижу, что мое понимание  DllCall на нулевом уровне, но я хотел бы все-таки научится.

10 (изменено: Malcev, 2020-05-21 06:10:52)

Re: AHK: DllCall() и GetKeyboardState

А разве функция ждет Byte?
Она ждет ссылку на массив байтов.
Как его создавать написано в справке по dllcall.

11

Re: AHK: DllCall() и GetKeyboardState

teadrinker
Спасибо.
Забыл что там находятся не только нажатые клавиши, узнать без перебора что какое то из значений меньше нуля не получится?

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru
Win10x64, AutoHotkey_L v1.1.32.00 (Unicode 32-bit). AhkSpy, Hotkey, ClockGui

12

Re: AHK: DllCall() и GetKeyboardState

dmitry-semin

https://i.imgur.com/KWOeBZB.png

Если описание параметра начинается с P или с lp — это значит, что ожидается указатель, адрес какого-либо буфера в памяти. В AHK такой буфер можно создать с помощью VarSetCapacity. В DllCall это будет тип данных "Ptr":

DllCall("GetKeyboardState", "Ptr", &buff)

где buff — это предварительно созданный буфер.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

13

Re: AHK: DllCall() и GetKeyboardState

serzh82saratov
Ну, не знаю, может предварительно все toggle-клавиши в ноль установить, не пробовал.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

14

Re: AHK: DllCall() и GetKeyboardState

Нет, там периодически печатные клавиши меняют состояния.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru
Win10x64, AutoHotkey_L v1.1.32.00 (Unicode 32-bit). AhkSpy, Hotkey, ClockGui

15 (изменено: dmitry-semin, 2020-05-22 11:23:27)

Re: AHK: DllCall() и GetKeyboardState

Спасибо большое всем, кто отписался в теме. Пойду учить мат.часть.
1) Я полагал что полученный массив в функции можно будет просмотреть c помощью For-loop, чтобы понять, что внутри такого массива ключ, а что значения. Вот то, что я ожидал увидеть внутри:
ключ значение
0x41 0
0x42 1
0x43 0
0x44 1
0x45 0
0x46 1
0x47 0
2) Если я помещаю код внутрь цикла содержимое массива меняется самопроизвольно. Я ожидал, что изменения будут только при на нажатии мной клавиш во время выполнения цикла.
3) если я нажимаю левую кнопку мыши в окне скрипта, то статус "Не все нули" : "Все нули" меняется от каждого нажатия, но не от клавиатуры. Как будто тугл.


#Persistent
#SingleInstance force
if not (A_IsAdmin or RegExMatch(full_command_line, " /restart(?!\S)"))
{
try
{
if A_IsCompiled
Run *RunAs "%A_ScriptFullPath%" /restart
else
Run *RunAs "%A_AhkPath%" /restart "%A_ScriptFullPath%"
}
ExitApp
}
#InstallKeybdHook
#InstallMouseHook
#UseHook

VarSetCapacity(lpKeyState, 512, 0)

loop 
{
Result := DllCall("GetKeyboardState", "Ptr", &lpKeyState)
ToolTip,
(
% lpKeyState ? "Не все нули" : "Все нули"
)
}
return

В любом случае спасибо за помощь.

16 (изменено: serzh82saratov, 2020-05-24 17:55:39)

Re: AHK: DllCall() и GetKeyboardState

Лично для меня описание неоднозначно.
Если " < 0 ? GetKeyName" заменить на " != 0 ? GetKeyName", то будут видны все ключи.
И не ясно почему для некоторых клавиш появляются некие значения, после нажатия отпускания они могут исчезнуть...

Убрал под спойлер, так как ТС вроде сам хочет разобраться.

+ открыть спойлер

SetFormat, IntegerFast, h
VarSetCapacity(KeyState, 256, 0)

Loop
{
	Tip =
	ThreadID := DllCall("GetWindowThreadProcessId", Ptr, WinExist("A"), UInt, 0)
	DllCall("AttachThreadInput", Ptr, ThreadID
						  , UInt, DllCall("GetCurrentThreadId")
						  , UInt, 1) 
	DllCall("GetKeyboardState", Ptr, &KeyState)
	
	Loop 256
		Tip .= (v := NumGet(&KeyState, A_Index, "Char")) < 0 ? GetKeyName("vk" A_Index) " " v "  " A_Index  "`n"  : ""
	ToolTip %  Tip  
	Sleep 11
}
По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru
Win10x64, AutoHotkey_L v1.1.32.00 (Unicode 32-bit). AhkSpy, Hotkey, ClockGui

17 (изменено: serzh82saratov, 2020-05-24 19:14:45)

Re: AHK: DllCall() и GetKeyboardState

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

+ открыть спойлер

SetFormat, IntegerFast, h
VarSetCapacity(KeyState, 256, 0)

Loop
{
	Tip =
	ThreadID := DllCall("GetWindowThreadProcessId", Ptr, WinExist("A"), UInt, 0)
	DllCall("AttachThreadInput", Ptr, ThreadID
						  , UInt, DllCall("GetCurrentThreadId")
						  , UInt, 1) 
	DllCall("GetKeyboardState", Ptr, &KeyState)
	
	Loop 256
		Tip .= (v := NumGet(&KeyState, A_Index, "UChar")) >> 7 ? GetKeyName("vk" A_Index) " " v "   " A_Index  "`n"  : ""
	ToolTip %  Tip  
	Sleep 11
}
По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru
Win10x64, AutoHotkey_L v1.1.32.00 (Unicode 32-bit). AhkSpy, Hotkey, ClockGui

18

Re: AHK: DllCall() и GetKeyboardState

По-моему нельзя. Можно было бы, если бы была возможность произвести логическое "и" между двумя такими байтовыми массивами:

VarSetCapacity(match, 256, 0x80)
VarSetCapacity(KeyState, 256, 0)

но вроде в winapi это не поддерживается.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

19

Re: AHK: DllCall() и GetKeyboardState

teadrinker
Тебе это наверняка известно, просто я впервые наткнулся, когда надо найти первое совпадение нужного значения байта.
Но в этом случае это не поможет.


VarSetCapacity(match, 256, 0) 
NumPut(0x80, match, 8, "UChar")

f := DllCall("msvcrt\memchr", "ptr", &match, "Int", 0x80, "Int", 256, "Cdecl UInt")
MsgBox % (f - &match) < 0 ? "not match" : "match"
По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru
Win10x64, AutoHotkey_L v1.1.32.00 (Unicode 32-bit). AhkSpy, Hotkey, ClockGui

20 (изменено: serzh82saratov, Вчера 11:21:32)

Re: AHK: DllCall() и GetKeyboardState

Хотя для пары значений подойдёт.
Работает намного шустрее чем:


		Loop 256
		{
			If NumGet(&KeyState, A_Index, "UChar") >> 7
				break
		}
+ открыть спойлер

VarSetCapacity(KeyState, 256, 0)

Loop
{ 
	DllCall("AttachThreadInput", Ptr, DllCall("GetWindowThreadProcessId", Ptr, WinExist("A"), UInt, 0)
	, UInt, DllCall("GetCurrentThreadId"), UInt, 1) 
	DllCall("GetKeyboardState", Ptr, &KeyState)
	
	press := DllCall("msvcrt\memchr", "ptr", &KeyState, "UChar", 0x80, "UInt", 256, "Cdecl UInt") 
		|| DllCall("msvcrt\memchr", "ptr", &KeyState, "UChar", 0x81, "UInt", 256, "Cdecl UInt") ? 1 : 0 
		
	ToolTip % press
	Sleep 1
}
По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru
Win10x64, AutoHotkey_L v1.1.32.00 (Unicode 32-bit). AhkSpy, Hotkey, ClockGui