Lazarus

Programming => General => Topic started by: TBMan on June 06, 2025, 04:37:36 am

Title: What happened to boolean(GetAsyncKeyState(VK_NUMPAD8))?
Post by: TBMan on June 06, 2025, 04:37:36 am
I recompiled a game I wrote after upgrading to the new Lazarus and now the GetAsynckeyState calls are not working. Is it my system or has this happened to others?

Here's a code section that no longer executes:

Code: Pascal  [Select][+][-]
  1.  if boolean(GetAsyncKeyState(VK_NUMPAD4)) or boolean(GetAsyncKeyState(VK_NUMPAD1))
  2.      or  boolean(GetAsyncKeyState(VK_NUMPAD7)) or boolean(GetAsyncKeyState(VK_LEFT))
  3.      then  // rotate left
  4.     begin
  5.       degrees := -1;
  6.       rotating := true;
  7.     end;      
  8.  

It isn't the end of the world, I just added a readkey and a case statement for the fix, but why did this happen?

Code: Pascal  [Select][+][-]
  1. Key := '-';
  2. if keypressed then key := readkey;
  3. case Key of
  4. '4','2','7':begin
  5.                  degrees := -1;
  6.                  rotating := true;
  7.            end;
  8. end;
  9.  
  10.  
Title: Re: What happened to boolean(GetAsyncKeyState(VK_NUMPAD8))?
Post by: Fibonacci on June 06, 2025, 05:12:11 am
Boolean(GetAsyncKeyState(VK_NUMPAD8)) is incorrect. It would work if you cast to WINBOOL, but thats not how GetAsyncKeyState is meant to be used.

The correct way is:

Code: Pascal  [Select][+][-]
  1. (GetAsyncKeyState(VK_NUMPAD8) and $8000) <> 0

This checks the high bit which indicates if the key is currently down.
Title: Re: What happened to boolean(GetAsyncKeyState(VK_NUMPAD8))?
Post by: TBMan on June 06, 2025, 06:07:44 am
Boolean(GetAsyncKeyState(VK_NUMPAD8)) is incorrect. It would work if you cast to WINBOOL, but thats not how GetAsyncKeyState is meant to be used.

The correct way is:

Code: Pascal  [Select][+][-]
  1. (GetAsyncKeyState(VK_NUMPAD8) and $8000) <> 0

This checks the high bit which indicates if the key is currently down.

Thanks, I get it, but it used to work.
Title: Re: What happened to boolean(GetAsyncKeyState(VK_NUMPAD8))?
Post by: Leledumbo on June 06, 2025, 06:36:06 am
Thanks, I get it, but it used to work.
Yeap, the typing was loose, it is strict now. In other words, the was allowed typecast was wrong.
Title: Re: What happened to boolean(GetAsyncKeyState(VK_NUMPAD8))?
Post by: jamie on June 06, 2025, 12:18:32 pm
Thanks, I get it, but it used to work.
Yeap, the typing was loose, it is strict now. In other words, the was allowed typecast was wrong.

They call it retardation of a language campaign
Title: Re: What happened to boolean(GetAsyncKeyState(VK_NUMPAD8))?
Post by: Martin_fr on June 06, 2025, 12:30:59 pm
Thanks, I get it, but it used to work.

No, it did not.
It did just accidentally behave as if it worked.

There is a difference between:
- "works" which means the code is correct.
- exposes the expected behaviour (in a very specific case)

The 2nd looks exactly like it works. Even though the code is not correct. But by chance the generated code still deals with all value, the way its desired. Just the important difference is "by chance" => "by random accident". That should not be called "works". (if you want to describe it is correct).

"By chance", is like rolling a dice, and once you got 3 times the "6 dots" that you wanted, you say "I can always at will roll a 6", it has worked.

"boolean(somevalue)" has always only been guaranteed for somevalue being either exactly 0 or 1.
For any other value, that behaviour has always been undefined.
In your case this undefined may have just been the way you wanted it. But it was not guaranteed to stay.
Title: Re: What happened to boolean(GetAsyncKeyState(VK_NUMPAD8))?
Post by: TBMan on June 06, 2025, 03:02:43 pm
Thanks, I get it, but it used to work.

No, it did not.
It did just accidentally behave as if it worked.

There is a difference between:
- "works" which means the code is correct.
- exposes the expected behaviour (in a very specific case)

The 2nd looks exactly like it works. Even though the code is not correct. But by chance the generated code still deals with all value, the way its desired. Just the important difference is "by chance" => "by random accident". That should not be called "works". (if you want to describe it is correct).

"By chance", is like rolling a dice, and once you got 3 times the "6 dots" that you wanted, you say "I can always at will roll a 6", it has worked.

"boolean(somevalue)" has always only been guaranteed for somevalue being either exactly 0 or 1.
For any other value, that behaviour has always been undefined.
In your case this undefined may have just been the way you wanted it. But it was not guaranteed to stay.

Ah, in other words, it "worked", but it wasn't supposed to. lmao, Thanks.
Title: Re: What happened to boolean(GetAsyncKeyState(VK_NUMPAD8))?
Post by: Thaddy on June 06, 2025, 05:09:05 pm
The cause was that a Pascal Boolean is either 0 (false) or 1 (true)
The compiler previously wrongly assumed it could interpret true as any other value than 0.
To mitigate that, indeed use the <> operator, which will translate to Pascal false or true. (0/1)




Title: Re: What happened to boolean(GetAsyncKeyState(VK_NUMPAD8))?
Post by: TBMan on June 06, 2025, 05:30:08 pm
The cause was that a Pascal Boolean is either 0 (false) or 1 (true)
The compiler previously wrongly assumed it could interpret true as any other value than 0.
To mitigate that, indeed use the <> operator, which will translate to Pascal false or true. (0/1)

Thanks Thaddy.

Title: Re: What happened to boolean(GetAsyncKeyState(VK_NUMPAD8))?
Post by: Remy Lebeau on June 06, 2025, 08:03:51 pm
GetAsyncKeyState() returns a 16-bit bitmask with 2 possible bits set:

- the high bit if the key is currently down

- the low bit if the key was pressed since the last time GetAsyncKeyState() was called.

Your code assumed that any non-zero return value would evaluate as true. The correct way to do that is to use the <> inequality operator instead, eg:

Code: Pascal  [Select][+][-]
  1. if (GetAsyncKeyState(VK_NUMPAD4) <> 0)
  2.     or (GetAsyncKeyState(VK_NUMPAD1) <> 0)
  3.     or (GetAsyncKeyState(VK_NUMPAD7) <> 0)
  4.     or (GetAsyncKeyState(VK_LEFT) <> 0) then
  5.  begin
  6.     // rotate left
  7.     degrees := -1;
  8.     rotating := true;
  9.  end;      
  10.  

If you are only interested if whether the key is currently held down, use the bitwise AND operator instead, eg:

Code: Pascal  [Select][+][-]
  1. if ((GetAsyncKeyState(VK_NUMPAD4) and $8000) <> 0)
  2.     or ((GetAsyncKeyState(VK_NUMPAD1) and $8000) <> 0)
  3.     or ((GetAsyncKeyState(VK_NUMPAD7) and $8000) <> 0)
  4.     or ((GetAsyncKeyState(VK_LEFT) and $8000) <> 0) then
  5.  begin
  6.     // rotate left
  7.     degrees := -1;
  8.     rotating := true;
  9.  end;      
  10.  

Or, you can use the < comparison operator, since the return value is signed, eg:

Code: Pascal  [Select][+][-]
  1. if (GetAsyncKeyState(VK_NUMPAD4) < 0)
  2.     or (GetAsyncKeyState(VK_NUMPAD1) < 0)
  3.     or (GetAsyncKeyState(VK_NUMPAD7) < 0)
  4.     or (GetAsyncKeyState(VK_LEFT) < 0) then
  5.  begin
  6.     // rotate left
  7.     degrees := -1;
  8.     rotating := true;
  9.  end;      
  10.  
Title: Re: What happened to boolean(GetAsyncKeyState(VK_NUMPAD8))?
Post by: 440bx on June 06, 2025, 08:40:27 pm
when the test is for something being zero or not zero, in general I prefer to typecast the argument to the properly sized BOOL.

In the case of GetAsyncKeyState(<SomeKey>) <> 0, I'd prefer WordBool(GetAsyncKeyState(<SomeKey>)) which should be equivalent and doesn't run the risk of messing up the equality operator in the comparison. Of course, this also applies when the argument is and-ed.

Title: Re: What happened to boolean(GetAsyncKeyState(VK_NUMPAD8))?
Post by: jamie on June 07, 2025, 01:39:29 am
the Boolean(whatever) will focus on the Byte size return which is ok since the first bit will be reflected.

However, that function can misbehave in a threaded process whereas if another thread is also using it the bit will be cleared.

 Does the now built in debugger poll keys?

Jamie
TinyPortal © 2005-2018