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

Just starting out? Need help? Post your questions and find answers here.
User avatar
Regenduft
Enthusiast
Enthusiast
Posts: 121
Joined: Mon Mar 02, 2009 9:20 pm
Location: Germany

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

Post 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
Last edited by Regenduft on Tue Jun 03, 2014 5:50 pm, edited 5 times in total.
User avatar
Danilo
Addict
Addict
Posts: 3036
Joined: Sat Apr 26, 2003 8:26 am
Location: Planet Earth

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

Post 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
coco2
Enthusiast
Enthusiast
Posts: 461
Joined: Mon Nov 25, 2013 5:38 am
Location: Australia

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

Post by coco2 »

Sorry if Im hijacking slightly, why doesn't PB have a uint32?
User avatar
Regenduft
Enthusiast
Enthusiast
Posts: 121
Joined: Mon Mar 02, 2009 9:20 pm
Location: Germany

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

Post 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:
coco2
Enthusiast
Enthusiast
Posts: 461
Joined: Mon Nov 25, 2013 5:38 am
Location: Australia

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

Post by coco2 »

It's useful for endian swapping for network data, but I can just make a uint32 structure so no big deal :smile:
freak
PureBasic Team
PureBasic Team
Posts: 5941
Joined: Fri Apr 25, 2003 5:21 pm
Location: Germany

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

Post 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.
quidquid Latine dictum sit altum videtur
User avatar
Regenduft
Enthusiast
Enthusiast
Posts: 121
Joined: Mon Mar 02, 2009 9:20 pm
Location: Germany

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

Post 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.
freak
PureBasic Team
PureBasic Team
Posts: 5941
Joined: Fri Apr 25, 2003 5:21 pm
Location: Germany

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

Post 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 :)
quidquid Latine dictum sit altum videtur
Post Reply