Page 1 of 1

[Petty] PB5.30b2 wrong import of GetAsyncKeyState_()

Posted: Sun Jun 01, 2014 4:32 pm
by Regenduft
PS: I have marked the topic as "petty" on my own, not the PB-Team.

PB5.30b2 (x64/x86) on Windows 7 (x64)

The import of GetAsyncKeyState_() seems to be wrong. Due to MSDN the return value is defined as SHORT (link to MSDN). In PureBasic it seems to be defined as Integer which leads to some strange behaviour in some cases (see code and debugger output beyond).

Small additional info: Also due to MSDN the LSB is a legacy and not reliable. What counts is the (SHORT!) MSB. The official MSDN statement is that "ReturnValue & ~1" should be used to get the correct (non-legacy) result.

Code: Select all

Repeat
  Delay( 500 )
  Debug RSet( Bin( GetAsyncKeyState_( #VK_ESCAPE ) ) , 64 , "0" )
ForEver
Beyond I've added "trigger comments" and marked the MSB in red. This is the x64 output. The x86 one looks essentially the same.
Debugger wrote:1111111111111111111110101000000000000100111000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
1111111111111111111110101000000000000100111000000000000000000000 <- debugger stop button pressed
1111111111111111111110101000000000000100111000000000000000000000 <- debugger run button pressed
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
1111111111111111111110101000000000000100111000000000000000000000 <- debugger stop button pressed
1111111111111111111110101000000000000100111000000000000000000000 <- debugger run button pressed
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
1111111111111111111110101000000000000100111000000000000000000000 <- debugger stop button pressed
1111111111111111111110101000000000000100111000000000000000000000 <- debugger run button pressed
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
1111111111111111111110101000000000000100111111101000000000000001 <- key down
1111111111111111111110101000000000000100111111101000000000000001
1111111111111111111110101000000000000100111111101000000000000001
1111111111111111111110101000000000000100111111101000000000000001
1111111111111111111110101000000000000100111111101000000000000001 <- key up
1111111111111111111110101000000000000100111111100000000000000001
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
1111111111111111111110101000000000000100111111101000000000000001 <- key down
1111111111111111111110101000000000000100111111101000000000000001 <- key up
1111111111111111111110101000000000000100111111100000000000000001
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
1111111111111111111110101000000000000100111111101000000000000001 <- key down
1111111111111111111110101000000000000100111111101000000000000001
1111111111111111111110101000000000000100111111101000000000000001
1111111111111111111110101000000000000100111111101000000000000001
1111111111111111111110101000000000000100111111101000000000000001 <- key up
1111111111111111111110101000000000000100111111100000000000000001
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000

Re: PB5.30b1 wrong import of GetAsyncKeyState_()

Posted: Sun Jun 01, 2014 6:21 pm
by Danilo
You can only use 2 bits anyway, so ignore all others:

Code: Select all

; Get current key state:
GetAsyncKeyState_( #VK_ESCAPE ) & $8000
; Get pressed state since last call:
GetAsyncKeyState_( #VK_ESCAPE ) & 1

; However, you should not rely on this last behavior in a multi-tasking environment,
; because calls to GetAsyncKeyState_() by other applications remove this flag.
WinAPI messages are not type filtered anyway (AFAIK), as most return Long or Handles/Pointers (Integer).
C's 'int' is 32bit also in 64bit Windows.
I think you need to filter itself with '& $FF', '& $FFFF', '& $FFFFFFFF' - at least it has always been like this.
With 32bit compiler, it also returns 32bit, not only 16bits. It's just by accident that the other bits were
always 0, and now you see it with 64bit. Reliable is only GetAsyncKeyState_( key ) & $8000

Re: PB5.30b1 wrong import of GetAsyncKeyState_()

Posted: Mon Jun 02, 2014 5:45 am
by coco2
Sorry if Im hijacking slightly, why doesn't PB have a uint32?

Re: PB5.30b1 wrong import of GetAsyncKeyState_()

Posted: Mon Jun 02, 2014 8:10 am
by Regenduft
Danilo wrote:You can only use 2 bits anyway
No, only 1 bit. The least significant should not be used! E.g. in Windows 7 it shows a completely different behavior than in Windows XP.
Danilo wrote:It's just by accident that the other bits were always 0
That's the reason why I call it a bug. When using the API correctly, it doesn't work. As you can see in my first posting, also things like pausing the program execution using the debugger completely distorts the result.
coco2 wrote:Sorry if Im hijacking slightly, why doesn't PB have a uint32?
It's a design decision. Take a look into the feature request forum and you'll find miles long discussions on that one. :wink:

Re: PB5.30b2 wrong import of GetAsyncKeyState_()

Posted: Mon Jun 02, 2014 11:00 pm
by coco2
It's useful for endian swapping for network data, but I can just make a uint32 structure so no big deal :smile:

Re: PB5.30b2 wrong import of GetAsyncKeyState_()

Posted: Mon Jun 02, 2014 11:09 pm
by freak
> The official MSDN statement is that "ReturnValue & ~1" should be used to get the correct (non-legacy) result.

I can't find that on the page you linked. Where exactly does it say that?

If you use it like Danilo showed, there is no problem. Imho, this is the correct usage:

Code: Select all

; Get current key state:
GetAsyncKeyState_( #VK_ESCAPE ) & $8000
The fact is that almost no APIs return short value such as this one, which is why there is no support for it in the compiler. It makes no sense to add a special case for this one function when you have to use bit-masking in the end anyway to mask out the legacy behavior.

Long story short: Yes, it may not be 100% correct behavior, but it is just not worth the trouble to fix it.

Re: PB5.30b2 wrong import of GetAsyncKeyState_()

Posted: Tue Jun 03, 2014 7:46 pm
by Regenduft
freak wrote:> The official MSDN statement is that "ReturnValue & ~1" should be used to get the correct (non-legacy) result.

I can't find that on the page you linked. Where exactly does it say that?
Sorry, guess I've dreamed that up some how...
freak wrote:The fact is that almost no APIs return short value such as this one, which is why there is no support for it in the compiler. It makes no sense to add a special case for this one function when you have to use bit-masking in the end anyway to mask out the legacy behavior.

Long story short: Yes, it may not be 100% correct behavior, but it is just not worth the trouble to fix it.
Sounds reasonable. I thought this would be a "10 second fix".

A last question: Is Danilos statement correct that WinAPI messages are not type filtered in general? It sounds, like he is right... I can live with that, but IMHO it's quite important to keep in mind, when using API functions.

Re: PB5.30b2 wrong import of GetAsyncKeyState_()

Posted: Tue Jun 03, 2014 9:58 pm
by freak
Regenduft wrote:A last question: Is Danilos statement correct that WinAPI messages are not type filtered in general? It sounds, like he is right... I can live with that, but IMHO it's quite important to keep in mind, when using API functions.
Yes, this is true. But it usually does not matter because only few API functions return anything other than a pointer sized value anyway. You found one of the rare exceptions here :)