Recent

Author Topic: GetKeyShiftState not working on Linux / GTK?  (Read 8151 times)

Alloc

  • New Member
  • *
  • Posts: 17
GetKeyShiftState not working on Linux / GTK?
« on: June 17, 2016, 05:53:17 pm »
Hi there,

have been successfully implementing a little launcher tool for a game. Made it so it only shows its own window when Shift is pressed at start up time, otherwise it directly starts the game and closes itself.

Now I ported it over to Linux but it does no longer show itself when shift is pressed when the program is started. I use the following in the application's main form's OnCreate event:
Code: Pascal  [Select][+][-]
  1. if ssShift in GetKeyShiftState() then
  2. // show launcher

Is that a known issue? Is there something else I could use instead to query the current state of the Shift key?

Kind regards,
Chris

RAW

  • Hero Member
  • *****
  • Posts: 871
Re: GetKeyShiftState not working on Linux / GTK?
« Reply #1 on: June 17, 2016, 07:52:42 pm »
For me it's working too... under Windows. But unfortunately I cannot test it under Linux right now...  :(

Code: Pascal  [Select][+][-]
  1. UNIT uShiftTest;
  2. {$MODE OBJFPC}{$H+}
  3. INTERFACE
  4. USES
  5.  Windows,Classes,SysUtils,Forms,Controls;
  6. TYPE
  7.  TForm1 = Class(TForm)
  8.   Procedure FormCreate (Sender:TObject);
  9.  PRIVATE
  10.   Const
  11.    ByeBye = WM_USER + 555;
  12.  PROTECTED
  13.   Procedure WndProc (Var MSG:TMessage);Override;
  14.  End;
  15. VAR
  16.  Form1: TForm1;
  17. IMPLEMENTATION
  18. {$R *.LFM}
  19.  
  20. Procedure TForm1.FormCreate(Sender:TObject);
  21. Begin
  22.   // MainForm = Application.ShowMainForm:= False;
  23.   If ssShift In GetKeyShiftState()
  24.   Then Show
  25.   Else SendMessage(Handle,ByeBye,0,0);
  26. End;
  27.  
  28. Procedure TForm1.WndProc(Var MSG:TMessage);
  29. Begin
  30.   If MSG.Msg = ByeBye
  31.   Then Close
  32.   Else Inherited WndProc(MSG);
  33. End;
  34.  
  35. END.
« Last Edit: June 06, 2020, 11:06:43 pm by RAW »

Alloc

  • New Member
  • *
  • Posts: 17
Re: GetKeyShiftState not working on Linux / GTK?
« Reply #2 on: June 18, 2016, 02:24:02 pm »
Even working on OSX, just not Linux it seems :(

Abelisto

  • Jr. Member
  • **
  • Posts: 91
Re: GetKeyShiftState not working on Linux / GTK?
« Reply #3 on: June 18, 2016, 03:04:02 pm »
Even working on OSX, just not Linux it seems :(

Works fine with the simple test:

Code: Pascal  [Select][+][-]
  1. procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
  2. var
  3.     st: TShiftState;
  4.     sts: string[3];
  5. begin
  6.     st := GetKeyShiftState;
  7.     sts := '   ';
  8.     if ssShift in st then
  9.         sts[1] := 'S';
  10.     if ssCtrl in st then
  11.         sts[2] := 'C';
  12.     if ssAlt in st then
  13.         sts[3] := 'A';
  14.     Caption := sts;
  15. end;

Linux Mint.
Probably the problem somewhere else.
« Last Edit: June 18, 2016, 03:06:20 pm by Abelisto »
OS: Linux Mint + MATE, Compiler: FPC trunk (yes, I am risky!), IDE: Lazarus trunk

Alloc

  • New Member
  • *
  • Posts: 17
Re: GetKeyShiftState not working on Linux / GTK?
« Reply #4 on: June 19, 2016, 02:12:26 am »
Yeah, it seems like it works when used with the form being visible, but not when used within the OnCreate event of the main form :(

Windsurfer

  • Sr. Member
  • ****
  • Posts: 368
    • Windsurfer
Re: GetKeyShiftState not working on Linux / GTK?
« Reply #5 on: June 19, 2016, 11:53:41 am »
Try using the OnShow event, rather than the OnCreate event. The form does exist to accept key strokes until after it has been created.

Alloc

  • New Member
  • *
  • Posts: 17
Re: GetKeyShiftState not working on Linux / GTK?
« Reply #6 on: June 19, 2016, 01:21:51 pm »
Same issue ... added an OnShow handler and checked GetKeyShiftState and it doesn't return any of the modifiers.

Also, if I would do it in the OnShow the window would always flash up, even if Shift isn't pressed (and thus the launcher should not show).

Windsurfer

  • Sr. Member
  • ****
  • Posts: 368
    • Windsurfer
Re: GetKeyShiftState not working on Linux / GTK?
« Reply #7 on: June 19, 2016, 04:49:58 pm »
This works in Linux using LCL and GTK2 and avoids a lot of complexity.

Code: Pascal  [Select][+][-]
  1. Procedure TForm1.FormActivate(Sender: TObject);
  2.   begin
  3.     If ssShift In GetKeyShiftState()
  4.     Then Form1.Show
  5.     Else
  6.       begin
  7.         Form1.visible := False;
  8.         ShowMessage('Bye');
  9.         Application.Terminate;
  10.       end;
  11.   end;

RAW

  • Hero Member
  • *****
  • Posts: 871
Re: GetKeyShiftState not working on Linux / GTK?
« Reply #8 on: June 19, 2016, 04:56:47 pm »
I've never used it but what about directly talking to Xlib (xGrabKey or xGrabKeyboard...) ???
Or is GetKeyShiftstate doing it already?
There must be a similar way that is functioning... :)

Alloc

  • New Member
  • *
  • Posts: 17
Re: GetKeyShiftState not working on Linux / GTK?
« Reply #9 on: June 19, 2016, 11:49:32 pm »
@Windsurfer: This might work but even if so it shows the same issue as OnShow: It would show the window and then close it again (i.e. "flash" it) :(

@SoE: Yeah, using system APIs most likely would do the trick but I'm not to keen to go any direct-lib-access route here. Already fearing that the precompiled executables won't work on a lot of other systems (unlike with Pascal executables on Windows where you can be almost 100% sure they will run on anything ...).

Still hoping there's a proper solution for this with "built-in" stuff ;)

RAW

  • Hero Member
  • *****
  • Posts: 871
Re: GetKeyShiftState not working on Linux / GTK?
« Reply #10 on: June 20, 2016, 03:23:31 am »
Try this.... :)

EDIT:
Maybe it's a good idea to give the user a little bit more time ...

Code: Pascal  [Select][+][-]
  1. UNIT uGetShift;
  2. {$MODE OBJFPC}{$H+}
  3. INTERFACE
  4. USES
  5.  Classes,SysUtils,Forms,Controls,ExtCtrls;
  6. TYPE
  7.  TForm1 = Class(TForm)
  8.   Procedure FormCreate          (Sender:TObject);
  9.   Procedure FormCloseQuery      (Sender:TObject;Var CanClose:Boolean);
  10.   Procedure OnKeyDownWndShift   (Sender:TObject;Var Key:Word;Shift:TShiftState);
  11.   Procedure OnCloseQueryWndShift(Sender:TObject;Var CanClose:Boolean);
  12.   Procedure OnTimer             (Sender:TObject);
  13.  PRIVATE
  14.   WndShift:TForm;Timer:TTimer;
  15.  End;
  16. VAR
  17.  Form1:TForm1;
  18. IMPLEMENTATION
  19. {$R *.LFM}
  20.  
  21. Procedure TForm1.FormCreate(Sender:TObject);
  22. Begin
  23.   // main wnd = Application.ShowMainForm:= False;
  24.   // create wnd to recognize SHIFT on keydown
  25.   WndShift:= TForm.Create(Self);
  26.   WndShift.AlphaBlend:= True;
  27.   WndShift.AlphaBlendValue:= 1;
  28.   WndShift.KeyPreview:= True;
  29.   WndShift.BorderStyle:= bsNone;
  30.   WndShift.FormStyle:= fsSystemStayOnTop;
  31.   WndShift.OnKeyDown:= @OnKeyDownWndShift;
  32.   WndShift.OnCloseQuery:= @OnCloseQueryWndShift;
  33.   WndShift.SetBounds(0,0,1,1);
  34.   // create timer
  35.   Timer:= TTimer.Create(wndShift);
  36.   Timer.Interval:= 4000;  // 4 seconds to press SHIFT
  37.   Timer.OnTimer:= @OnTimer;
  38.   Timer.Enabled:= True;
  39.   // "show" wnd
  40.   WndShift.Show;
  41. End;
  42.  
  43. Procedure TForm1.OnKeyDownWndShift
  44. (Sender:TObject;Var Key:Word;Shift:TShiftState);
  45. Begin
  46.   If ssShift In Shift
  47.   Then
  48.    Begin
  49.     Timer.Enabled:= False;
  50.     Show;
  51.     WndShift.Release; // optional
  52.    End;
  53. End;
  54.  
  55. Procedure TForm1.OnTimer(Sender:TObject);
  56. Begin
  57.   Timer.Enabled:= False;
  58.   Application.Terminate;
  59. End;
  60.  
  61. Procedure TForm1.OnCloseQueryWndShift(Sender:TObject;Var CanClose:Boolean);
  62. Begin
  63.   // deny closing
  64.   CanClose:= False;
  65. End;
  66.  
  67. Procedure TForm1.FormCloseQuery(Sender:TObject;Var CanClose:Boolean);
  68. Begin
  69.   If Visible
  70.   Then CanClose:= True
  71.   Else CanClose:= False;
  72. End;
  73.  
  74. END.
« Last Edit: June 07, 2020, 04:18:43 am by RAW »

Windsurfer

  • Sr. Member
  • ****
  • Posts: 368
    • Windsurfer
Re: GetKeyShiftState not working on Linux / GTK?
« Reply #11 on: June 20, 2016, 02:39:12 pm »
Try setting Visible := false in the Object Inspector. I just checked and mine was set that way. I did not see any screen flashes on my system. (Linux rather than Windows.)

Alloc

  • New Member
  • *
  • Posts: 17
Re: GetKeyShiftState not working on Linux / GTK?
« Reply #12 on: June 20, 2016, 04:55:08 pm »
@Windsurfer: If Visible is set to false the OnActivate event won't trigger (unless you use Form.Show somewhere but that again will set Visible to true).

@SoE: Interesting solution. Actually I probably wouldn't even need the timer but instead could use OnActivate on that new form. Issue is though, that AlphaBlend doesn't seem to have any effect on forms at all. So it will always be at least a 1x1 pixel left :(
But this could still be better than it completely not working at all :)

RAW

  • Hero Member
  • *****
  • Posts: 871
Re: GetKeyShiftState not working on Linux / GTK?
« Reply #13 on: June 20, 2016, 10:23:11 pm »
Quote
..that AlphaBlend doesn't seem to have any effect on forms at all...
Really ? On Windows 7 I can see absolutely nothing even when I set the color to clfuchsia. Is that a LINUX bug or a feature ???

If you ask me, why not showing the second window in the middle of the screen and telling the user how much seconds he had left to press shift to enter the configuration menu or whatever... (counting the seconds and telling him that the window will automatically close after 3 or 4 seconds).

That will also work as a good reminder for the user. Feels a little bit more like the normal way... showing him the options he got... :)

Alloc

  • New Member
  • *
  • Posts: 17
Re: GetKeyShiftState not working on Linux / GTK?
« Reply #14 on: June 20, 2016, 10:27:26 pm »
Quote
..that AlphaBlend doesn't seem to have any effect on forms at all...
Really ? On Windows 7 I can see absolutely nothing even when I set the color to clfuchsia. Is that a LINUX bug or a feature ???
Could also be Xfce, Xubuntu, GTK2, theme ... ;)

If you ask me, why not showing the second window in the middle of the screen and telling the user how much seconds he had left to press shift to enter the configuration menu or whatever... (counting the seconds and telling him that the window will automatically close after 3 or 4 seconds).

That will also work as a good reminder for the user. Feels a little bit more like the normal way... showing him the options he got... :)
Well, there's the option to show the launcher by a command line argument (and that is passed by one of the Steam launch options so not that hard to get ;) ). I don't really like delaying the start of the actual program.

But the current workaround with a second 1x1 px window just to check GetKeyShiftState in its OnActivate seems to work fine. Not the nicest solution but working.

Of course if anyone still comes up with a way to get the shift-state without such a hack (and without pulling in further library dependencies ;) ) I would be happy.

Thank you guys again a lot for all your input.

 

TinyPortal © 2005-2018