Recent

Author Topic: GetKeyState(VK_SHIFT)  (Read 27503 times)

balazsszekely

  • Guest
Re: GetKeyState(VK_SHIFT)
« Reply #15 on: January 19, 2017, 06:25:22 pm »
What about this low level hook? It separately detects right/left shift. It's windows only, but since @pascal is under windows it should be ok.
Code: Pascal  [Select][+][-]
  1. uses windows;
  2.  
  3. var
  4.   llKeyboardHook: HHOOK = 0;
  5.  
  6. function LowLevelKeyboardHook(nCode: Integer; wParam: WPARAM; lParam: LPARAM): HRESULT; stdcall;
  7. const
  8.   LLKHF_UP = KF_UP shr 8;
  9. type
  10.   PKBDLLHOOKSTRUCT = ^TKBDLLHOOKSTRUCT;
  11.   TKBDLLHOOKSTRUCT = packed record
  12.     vkCode: DWORD;
  13.     scanCode: DWORD;
  14.     flags: DWORD;
  15.     time: DWORD;
  16.     dwExtraInfo: DWORD;
  17.   end;
  18. var
  19.   pkbhs: PKBDLLHOOKSTRUCT;
  20. begin
  21.   pkbhs := PKBDLLHOOKSTRUCT(Pointer(lParam));
  22.   if nCode = HC_ACTION then
  23.   begin
  24.     if (pkbhs^.vkCode = VK_LSHIFT) then
  25.     begin
  26.       if (pkbhs^.flags and LLKHF_UP) = LLKHF_UP then
  27.         Form1.label1.Caption := 'Left shift up'
  28.       else
  29.         Form1.label1.Caption := 'Left shift down';
  30.     end;
  31.  
  32.     if (pkbhs^.vkCode = VK_RSHIFT) then
  33.     begin
  34.       if (pkbhs^.flags and LLKHF_UP) = LLKHF_UP then
  35.         Form1.label2.Caption := 'Right shift up'
  36.       else
  37.         Form1.label2.Caption := 'Right shift down';
  38.     end;
  39.   end;
  40.   Result := CallNextHookEx(llKeyboardHook, nCode, wParam, lParam);
  41. end;
  42.  
  43. function TForm1.Start: boolean;
  44. const
  45.   WH_KEYBOARD_LL = 13;
  46. begin
  47.   if llKeyboardHook = 0 then
  48.     llKeyboardHook := SetWindowsHookEx(WH_KEYBOARD_LL, @LowLevelKeyboardHook, HInstance, 0);
  49.   Result := (llKeyboardHook <> 0)
  50. end;
  51.  
  52. function TForm1.Stop: Boolean;
  53. begin
  54.   Result := False;
  55.   if (llKeyboardHook <> 0) and UnhookWindowsHookEx(llKeyboardHook) then
  56.   begin
  57.     llKeyboardHook := 0;
  58.     Result := True;
  59.   end;
  60. end;
  61.  
  62. function TForm1.IsStarted: Boolean;
  63. begin
  64.   Result := (llKeyboardHook <> 0)
  65. end;
  66.  
  67. procedure TForm1.FormDestroy(Sender: TObject);
  68. begin
  69.   if IsStarted then
  70.     Stop;
  71. end;
  72.  
  73. procedure TForm1.FormCreate(Sender: TObject);
  74. begin
  75.   if not Start then
  76.     MessageDlg('Cannot start the hook!', mtError, [mbOk], 0)
  77. end;

Pascal

  • Hero Member
  • *****
  • Posts: 932
Re: GetKeyState(VK_SHIFT)
« Reply #16 on: January 19, 2017, 07:42:25 pm »
Weird... You are on Windows? What Lazarus version do you have?
(O, I already see, latest trunk)

What do you get with the following?
A TTimer and TMemo on your form and this as TimerEvent:
Code: Pascal  [Select][+][-]
  1. procedure TForm1.Timer1Timer(Sender: TObject);
  2. begin
  3.   Memo1.Lines.Add(IntToStr(GetKeyState(VK_SHIFT) and $8000));
  4. end;
When holding shift I get 32768 and releasing it I get 0 in the Memo1.
Code: Pascal  [Select][+][-]
  1. Memo1
  2. 0
  3. 0
  4. 32768
  5. 32768
  6. 32768
  7. 0
  8. 0
  9. 0
  10. 32768
  11. 0
  12. 0
  13. 0
  14.  
laz trunk x64 - fpc trunk i386 (cross x64) - Windows 10 Pro x64 (21H2)

rvk

  • Hero Member
  • *****
  • Posts: 6952
Re: GetKeyState(VK_SHIFT)
« Reply #17 on: January 19, 2017, 07:50:31 pm »
So... GetKeyState(VK_SHIFT) and GetKeyShiftState just work fine for you.

I'd love to see your ORIGINAL code where you state it doesn't work in FormCreate. I think you might have made an error there.

Fungus

  • Sr. Member
  • ****
  • Posts: 354
Re: GetKeyState(VK_SHIFT)
« Reply #18 on: January 19, 2017, 07:50:46 pm »
32768 = $8000 = 1000000000000000.
32768 and $8000 = 32768.

It works as intended. GetKeyState(...) and $8000 must be non-zero if the key is pressed. If it does not work during startup it may be related to a message loop not initialized yet.

Pascal

  • Hero Member
  • *****
  • Posts: 932
Re: GetKeyState(VK_SHIFT)
« Reply #19 on: January 19, 2017, 07:51:30 pm »
@Pascal
Try to start a new project, drop a TLabel and put this code below to see if it work or not.

Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, Forms, StdCtrls, LCLIntf, LCLType;
  9.  
  10. type
  11.  
  12.   { TForm1 }
  13.  
  14.   TForm1 = class(TForm)
  15.     Label1: TLabel;
  16.     procedure FormActivate(Sender: TObject);
  17.   private
  18.     { private declarations }
  19.   public
  20.     { public declarations }
  21.   end;
  22.  
  23. var
  24.   Form1: TForm1;
  25.  
  26. implementation
  27.  
  28. {$R *.lfm}
  29.  
  30. { TForm1 }
  31.  
  32. procedure TForm1.FormActivate(Sender: TObject);
  33. begin
  34.   if (GetKeyState(VK_SHIFT) And $80) <> 0 then
  35.     Label1.Caption := 'It works!';
  36. end;
  37.  
  38. end.

Works with $8000 in OnCreate, OnShow, OnActivate  :(
But not in my complex prog.
laz trunk x64 - fpc trunk i386 (cross x64) - Windows 10 Pro x64 (21H2)

rvk

  • Hero Member
  • *****
  • Posts: 6952
Re: GetKeyState(VK_SHIFT)
« Reply #20 on: January 19, 2017, 07:52:56 pm »
Then you have something in your complex program that interferes.
Without being able to debug this (or code to look at), we can't tell what the problem exactly is.

Pascal

  • Hero Member
  • *****
  • Posts: 932
Re: GetKeyState(VK_SHIFT)
« Reply #21 on: January 19, 2017, 07:56:36 pm »
So... GetKeyState(VK_SHIFT) and GetKeyShiftState just work fine for you.

I'd love to see your ORIGINAL code where you state it doesn't work in FormCreate. I think you might have made an error there.

Here you are:
Code: Pascal  [Select][+][-]
  1. procedure TprimeGlobalData.CheckIgnoreFileList;
  2. begin
  3.   if (GetKeyState(VK_SHIFT) and $8000 <> 0) then begin
  4.     DebugLn('### SHIFT pressed');
  5.     fIgnoreFileList := true;
  6.   end;
  7. end;

CheckIgnoreFileList is called several times during startup and initialization of my prog.
2 times in OnCreate
2 times in OnShow
laz trunk x64 - fpc trunk i386 (cross x64) - Windows 10 Pro x64 (21H2)

Fungus

  • Sr. Member
  • ****
  • Posts: 354
Re: GetKeyState(VK_SHIFT)
« Reply #22 on: January 19, 2017, 07:59:21 pm »
In you "complex prog" please make sure that you are using the instance of GetKeyState from LCL by using "LCLIntf.GetKeyState(LCLType.VK_SHIFT) and $8000 <> 0"

OT: Wondering what causes the difference in return values of GetKeyState between Linux / Windows. Anyone knows?

Pascal

  • Hero Member
  • *****
  • Posts: 932
Re: GetKeyState(VK_SHIFT)
« Reply #23 on: January 19, 2017, 08:07:30 pm »
OT: Wondering what causes the difference in return values of GetKeyState between Linux / Windows. Anyone knows?
It's a widgetset funktion which is used in GetKeyShiftState the correct way.
laz trunk x64 - fpc trunk i386 (cross x64) - Windows 10 Pro x64 (21H2)

rvk

  • Hero Member
  • *****
  • Posts: 6952
Re: GetKeyState(VK_SHIFT)
« Reply #24 on: January 19, 2017, 08:08:10 pm »
Code: Pascal  [Select][+][-]
  1.   if (GetKeyState(VK_SHIFT) and $8000 <> 0) then begin
Wait... you do see you are missing () in the right spot !!

It should be
Code: Pascal  [Select][+][-]
  1.   if (GetKeyState(VK_SHIFT) and $8000) <> 0 then begin

Edit: Never mind. Doesn't make a difference. And has priority.
« Last Edit: January 19, 2017, 08:12:50 pm by rvk »

Pascal

  • Hero Member
  • *****
  • Posts: 932
Re: GetKeyState(VK_SHIFT)
« Reply #25 on: January 19, 2017, 08:08:15 pm »
In you "complex prog" please make sure that you are using the instance of GetKeyState from LCL by using "LCLIntf.GetKeyState(LCLType.VK_SHIFT) and $8000 <> 0"

I did. But no difference.  %)
laz trunk x64 - fpc trunk i386 (cross x64) - Windows 10 Pro x64 (21H2)

Pascal

  • Hero Member
  • *****
  • Posts: 932
Re: GetKeyState(VK_SHIFT)
« Reply #26 on: January 19, 2017, 08:12:33 pm »
Code: Pascal  [Select][+][-]
  1.   if (GetKeyState(VK_SHIFT) and $8000 <> 0) then begin
Wait... you do see you are missing () in the right spot !!

It should be
Code: Pascal  [Select][+][-]
  1.   if (GetKeyState(VK_SHIFT) and $8000) <> 0 then begin

Also, no difference.

Code: Pascal  [Select][+][-]
  1. procedure TprimeGlobalData.CheckIgnoreFileList;
  2. begin
  3.   DebugLn('### GetKeyState(VK_SHIFT)=%d', [LCLIntf.GetKeyState(VK_SHIFT)]);
  4.   if (LCLIntf.GetKeyState(VK_SHIFT) and $8000) <> 0 then begin
  5.     DebugLn('### SHIFT pressed');
  6.     fIgnoreFileList := true;
  7.   end;
  8. end;
  9.  

This outputs 0 or 1
laz trunk x64 - fpc trunk i386 (cross x64) - Windows 10 Pro x64 (21H2)

rvk

  • Hero Member
  • *****
  • Posts: 6952
Re: GetKeyState(VK_SHIFT)
« Reply #27 on: January 19, 2017, 08:15:46 pm »
Do you have a FormKeyDown or any other key related event in your form/program?

(where you might mess up the state)

Pascal

  • Hero Member
  • *****
  • Posts: 932
Re: GetKeyState(VK_SHIFT)
« Reply #28 on: January 19, 2017, 08:18:18 pm »
This is driving me nuts %)

My program uses Anchordocking and a splash screen.
CheckIgnoreFileList is called during OnCreate and OnShow of the main dock site (while the splash screen is still visible).

Thanks everyone for time you have spend helping me. I do not have the leisure to investigate this any further.
Maybe on an other day  :)
laz trunk x64 - fpc trunk i386 (cross x64) - Windows 10 Pro x64 (21H2)

Fungus

  • Sr. Member
  • ****
  • Posts: 354
Re: GetKeyState(VK_SHIFT)
« Reply #29 on: January 19, 2017, 08:18:41 pm »
If one program correctly outputs 32768 or 0 and another wrongly outputs 1 or 0 for the same function call, then there must be some sort of issue in the second program.

 

TinyPortal © 2005-2018