Linux, XGrabKey, Fenster minimieren

Antworten
wennerer
Beiträge: 507
Registriert: Di 19. Mai 2015, 20:05
OS, Lazarus, FPC: Linux Mint 20 Cinnamon,Lazarus 2.2.6 (rev lazarus_2_2_6) FPC 3.2.2 x86_64-linux-
CPU-Target: x86_64-linux-gtk2

Linux, XGrabKey, Fenster minimieren

Beitrag von wennerer »

Hallo,
ich bastle seit einiger Zeit an einem Programm (unter LINUX UBUNTU) mit dem ich einen Ausschnitt des Bildschirms kopieren möchte. Anschließend möchte ich den Ausschnitt als Bitmap in mein Programm einfügen. Das heisst also mein Programm starten, dann meine "snipping procedure" starten, mein Programm minimiert sich, als Auslöser Tastenkombination drücken und Ausschnitt aufnehmen, mein Programm wird wieder normal groß. So der Idealfall.
Ich bin jetzt soweit das mit Xlib und XGrabKey das mit der Tastenkombi funktioniert. Ich schaffs aber nicht das mein Programm automatisch minimiert/maximiert wird. In welche Richtung muss ich da denken? Da XGrabKey nur geht wenn der Modifier genau stimmt ( Numlock oder Capslock aktiv) frag ich den jetzt ab, aber weiß Jemand wie ich eine Taste "drücken" kann. Hab da was mit XTestFakeKeyEvent gelesen, dazu find ich in FPC aber keine unit. Im Beispiel unten ist Strg+Shift+P die Tastenkombi.

Viele Grüße Bernd

Code: Alles auswählen

 
unit unit_TestHotkey;
 
{$mode objfpc}{$H+}
 
interface
 
uses
  Classes,SysUtils,FileUtil,Forms,Controls,Graphics,Dialogs,StdCtrls,LCLIntf,LCLType,
  { diese Units brauch ich für xgrabkey}
  x,Xlib,KeySym,XKBlib,XKB;
 
type
 
  { TForm1 }
 
  TForm1 = class(TForm)
    Button1 : TButton;
    Frame1  : TFrame;
    Bmp1    : TBitmap;
    procedure FormCreate(Sender: TObject);
    procedure StartHotKeyTest(Sender: TObject);
    procedure Frame1Paint(Sender: TObject);
 
  private
    { private declarations }
  public
    { public declarations }
  end;
 
var
  Form1: TForm1;
 
implementation
 
{$R *.lfm}
function pruefeState:boolean;
var
  dpy   : PDisplay;
  stateC : cardinal;
  stateN : cardinal;
  keycode      : Integer;
begin
 dpy     := XOpenDisplay(nil);
 (XkbGetIndicatorState (dpy, XkbUseCoreKbd, @stateC));
 if (stateC and 1) = 1 then showmessage('Achtung!CapsLock ist ein');
   //if (stateC and 1) = 0 then showmessage('Caps ist aus');
 (XkbGetIndicatorState (dpy,XkbUseCoreKbd, @stateN));
 if (stateN and 2) = 2 then showmessage('Achtung!NumLock ist ein');
   //if (stateN and 2) = 0 then showmessage('Num ist aus');
 if ((stateC and 1=1) or (stateN and 2 =2)) then pruefeState:=false else pruefeState:=true;
 XCloseDisplay(dpy);
end;
 
function  HotKey:TBitmap;
var
  dpy          : PDisplay;
  root         : TWindow;
  ev           : TXEvent;
  modifiers    : LongInt;
  keycode      : Integer;
  grab_window  : TWindow;
  owner_events : LongInt;
  pointer_mode : Integer;
  keyboard_mode: Integer;
  HK           : boolean;
  ScreenDC     : HDC;
begin
 dpy     := XOpenDisplay(nil);
 root    := DefaultRootWindow(dpy);
 
 HK              := false;
 modifiers       := ControlMask or ShiftMask;
 keycode         := XKeysymToKeycode(dpy,XK_P);
 grab_window     :=  root;
 owner_events    := 0;//false;
 pointer_mode    := GrabModeAsync;
 keyboard_mode   := GrabModeAsync;
 
 XGrabKey(dpy, keycode, modifiers, grab_window, owner_events, pointer_mode,
             keyboard_mode);
 
 XSelectInput(dpy, root, KeyPressMask );
 
 while (HK=false) do
  begin
   XNextEvent(dpy,@ev);
    case ev._type of KeyPress:
     begin
      ScreenDC := GetDC(0);
      HotKey.LoadFromDevice(ScreenDC);
      ReleaseDC(0,ScreenDC);
      XUngrabKey(dpy,keycode,modifiers,grab_window);
      HK:=true;
     end;
    end;
  end;
 XCloseDisplay(dpy);
end;
 
 
{ TForm1 }
 
procedure TForm1.FormCreate(Sender: TObject);
begin
  Form1.Caption    :='HotKeyTest --- Drücke Strg+Shift+P';
  Form1.Top        :=  50;
  Form1.Left       :=(Screen.DesktopWidth div 2)-400;
  Form1.Height     := 550;
  Form1.Width      := 800;
  Form1.Color      := clScrollBar;
 
  Button1          := TButton.Create(nil);
  Button1.Parent   := Form1;
  Button1.Top      :=  25;
  Button1.Left     :=  25;
  Button1.Height   :=  25;
  Button1.Width    := 150;
  Button1.Caption  := 'Start HotKeyTest';
  Button1.OnClick  := @StartHotKeyTest;
 
  Frame1           := TFrame.Create(nil);
  Frame1.Parent    := Form1;
  Frame1.Top       :=  75;
  Frame1.Left      :=  50;
  Frame1.Height    := 450;
  Frame1.Width     := 700;
  Frame1.Color     := clwhite;
  Frame1.OnPaint   := @Frame1Paint;
 
  Bmp1             := TBitmap.Create;
  Bmp1.SetSize(700,450);
  Bmp1.Canvas.Rectangle(0,0,700,450);
end;
 
procedure TForm1.StartHotKeyTest(Sender: TObject);
begin
 
 if pruefeState then
   begin
    Bmp1.Canvas.StretchDraw(Rect(0,0,700,450),HotKey);
    Frame1.Invalidate;
   end;
end;
 
procedure TForm1.Frame1Paint(Sender: TObject);
begin
  Frame1.Canvas.Draw(0,0,Bmp1);
end;
 
end.         
 

Benutzeravatar
theo
Beiträge: 10468
Registriert: Mo 11. Sep 2006, 19:01

Re: Linux, XGrabKey, Fenster minimieren

Beitrag von theo »

Verstehe zwar mehrheitlich Bahnhof, aber das mit dem Fenster Minimieren etc. geht so.

Code: Alles auswählen

 
if WindowState=wsMinimized then WindowState:=wsMaximized else WindowState:=wsMinimized;     

wennerer
Beiträge: 507
Registriert: Di 19. Mai 2015, 20:05
OS, Lazarus, FPC: Linux Mint 20 Cinnamon,Lazarus 2.2.6 (rev lazarus_2_2_6) FPC 3.2.2 x86_64-linux-
CPU-Target: x86_64-linux-gtk2

Re: Linux, XGrabKey, Fenster minimieren

Beitrag von wennerer »

Hallo Theo,
danke für deine Antwort. Das hab ich natürlich probiert. Mein Fenster reagiert aber nicht mehr darauf. Ich kann mein Fenster aber mit der Maus ganz normal minimieren, wo auch immer hin wechseln, dann den Schnappschuss machen und mit einem Mausclick wieder maximieren. Ich schaffs aber nicht im Programm meine Form anzusprechen.
Viele Grüße Bernd

Benutzeravatar
theo
Beiträge: 10468
Registriert: Mo 11. Sep 2006, 19:01

Re: Linux, XGrabKey, Fenster minimieren

Beitrag von theo »

Wie gesagt, Bahnhof.
Warum machst du es nicht so? http://wiki.lazarus.freepascal.org/Deve ... the_screen

wennerer
Beiträge: 507
Registriert: Di 19. Mai 2015, 20:05
OS, Lazarus, FPC: Linux Mint 20 Cinnamon,Lazarus 2.2.6 (rev lazarus_2_2_6) FPC 3.2.2 x86_64-linux-
CPU-Target: x86_64-linux-gtk2

Re: Linux, XGrabKey, Fenster minimieren

Beitrag von wennerer »

Hallo Theo,
den Schnappschuss selbst mach ich ja so. Aber ich steh jetzt auf dem Schlauch wie ich den Rest machen soll. Ich muss ja mein Fenster erst minimieren (das wäre kein Problem) aber dann brauch ich etwas um den Schnappschuss auszulösen (bei mir die Tastenkombination). Ansonsten kann ich ja nur den Bildschirm mit dem Fenster meiner eigenen Anwendung aufnehmen.
Viele Grüße

Benutzeravatar
theo
Beiträge: 10468
Registriert: Mo 11. Sep 2006, 19:01

Re: Linux, XGrabKey, Fenster minimieren

Beitrag von theo »

Warum nicht einen Timer verwenden?

wennerer
Beiträge: 507
Registriert: Di 19. Mai 2015, 20:05
OS, Lazarus, FPC: Linux Mint 20 Cinnamon,Lazarus 2.2.6 (rev lazarus_2_2_6) FPC 3.2.2 x86_64-linux-
CPU-Target: x86_64-linux-gtk2

Re: Linux, XGrabKey, Fenster minimieren

Beitrag von wennerer »

Ja wäre eine Möglichkeit. Damit hab ich auch schon etwas herum probiert. Aber da passt halt das Timing nicht immer so 100%ig. Ich denke auch das mit der Tastenkombi ist bei meinem Code nicht das Problem, ich weiß nur nicht wie ich wieder Zugriff auf mein Fenster bekomm. Eingefroren kann es ja nicht komplett sein sonst würde ja nach dem drücken der Tasten-Kombi der Schnappschuss auch nicht gehen. Ich denke mein Fenster verliert den Fokus und ich müsste es mit irgendeiner ID ansprechen. Oder so ähnlich???
Viele Grüße

wennerer
Beiträge: 507
Registriert: Di 19. Mai 2015, 20:05
OS, Lazarus, FPC: Linux Mint 20 Cinnamon,Lazarus 2.2.6 (rev lazarus_2_2_6) FPC 3.2.2 x86_64-linux-
CPU-Target: x86_64-linux-gtk2

Re: Linux, XGrabKey, Fenster minimieren

Beitrag von wennerer »

Hallo,
ich habe jetzt nochmal etwas herum probiert. Das Minimieren am Anfang hab ich mit einem Timer in den Griff bekommen (vielen Dank an Theo, hat mich auf die Idee gebracht). Ich minimiere erst und mach dann nach dem Timerevent weiter.
Beim Maximieren hab ich irgendwann gemerkt wenn ich eine showmessage zwischen durch angezeigt und dann weggeklickt habe ging das Maximieren. Es wird nun nach der Tastenkombination ein Dialogfenster erzeugt das immer im Vordergrund angezeigt wird. Beim wegklicken kommt meine Anwendung wieder in den "Fokus". Ist vielleicht nicht sehr elegant aber funktioniert. Ich hab jetzt noch ein paar Anmerkungen eingefügt. Die Xlib Sachen sind hier: http://openbook.rheinwerk-verlag.de, gut und in deutsch erklärt.
Kennt Jemand eine bessere Lösung in Linux um einen Tasten- oder Mausklick in die Form zu simulieren (anstelle des Dialogfenster)?
Viele Grüße
Bernd

Code: Alles auswählen

 
unit unit_TestHotkey;
 
{$mode objfpc}{$H+}
 
interface
 
uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
  LCLIntf, LCLType, ExtCtrls,
  { diese Units brauch ich für xgrabkey}
  x,Xlib,KeySym,XKBlib,XKB;
 
type
 
  { TForm1 }
 
  TForm1 = class(TForm)
    Button1 : TButton;
    Frame1  : TFrame;
    Bmp1    : TBitmap;
    Timer1  : TTimer;
    Button2 : TButton;
    procedure Danach;
    procedure Oeffnen(sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure StartHotKeyTest(Sender: TObject);
    procedure Frame1Paint(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
  end;
 
var
  Form1          : TForm1;
  win            : hwnd;
  DialogFenster  : TForm;
implementation
 
{$R *.lfm}
function pruefeState:boolean;   //hier wir überprüft ob Num oder Caps aktiv ist,
var                                         //ist da was aktiv geht die Tastenkombi nicht!
  dpy   : PDisplay;
  stateC : cardinal;
  stateN : cardinal;
 
begin
 dpy     := XOpenDisplay(nil);
 (XkbGetIndicatorState (dpy, XkbUseCoreKbd, @stateC));
 if (stateC and 1) = 1 then showmessage('Achtung!CapsLock ist ein');
   //if (stateC and 1) = 0 then showmessage('Caps ist aus');
 (XkbGetIndicatorState (dpy,XkbUseCoreKbd, @stateN));
 if (stateN and 2) = 2 then showmessage('Achtung!NumLock ist ein');
   //if (stateN and 2) = 0 then showmessage('Num ist aus');
 if ((stateC and 1=1) or (stateN and 2 =2)) then pruefeState:=false else pruefeState:=true;
 XCloseDisplay(dpy);
end;
 
function  HotKey:TBitmap;   //setzt den Hotkey hier strg+shift+P, kopiert den Desktop
var                                     //und liefert die Aufnahme als Bitmap zurück
  dpy          : PDisplay;
  root         : TWindow;
  ev           : TXEvent;
  modifiers    : LongInt;
  keycode      : Integer;
  grab_window  : TWindow;
  owner_events : LongInt;
  pointer_mode : Integer;
  keyboard_mode: Integer;
  HK           : boolean;
  ScreenDC     : HDC;
 
begin
 dpy     := XOpenDisplay(nil);
 root    := DefaultRootWindow(dpy);
 
 
 
 HK              := false;
 modifiers       := ControlMask or ShiftMask;                //legt strg und shift fest
 keycode         := XKeysymToKeycode(dpy,XK_P);     //legt P fest
 grab_window     :=  root;
 owner_events    := 0;//false;
 pointer_mode    := GrabModeAsync;
 keyboard_mode   := GrabModeAsync;
 
 XGrabKey(dpy, keycode, modifiers, grab_window, owner_events, pointer_mode,        //setzt den Hotkey
             keyboard_mode);
 
 XSelectInput(dpy, root, KeyPressMask);
 
 while (HK=false) do
  begin
    HK:=true;
    XNextEvent(dpy,@ev);
    case ev._type of KeyPress:
     begin
      ScreenDC := GetDC(0);                                        //hier wird das gemacht was man möchte
      HotKey.LoadFromDevice(ScreenDC);                   //ich kopiere den Desktop
      ReleaseDC(0,ScreenDC);
      XUngrabKey(dpy,keycode,modifiers,grab_window);   //Hotkey löschen
      HK:=true;
     end;
    end;
  end;
 
 XCloseDisplay(dpy);
 Form1.Danach;
 
end;
 
 
{ TForm1 }
 
procedure TForm1.FormCreate(Sender: TObject);
begin
  Form1.Caption    :='HotKeyTest --- Drücke Strg+Shift+P';
  Form1.Top        :=  50;
  Form1.Left       :=(Screen.DesktopWidth div 2)-400;
  Form1.Height     := 550;
  Form1.Width      := 800;
  Form1.Color      := clScrollBar;
 
  Button1          := TButton.Create(nil);
  Button1.Parent   := Form1;
  Button1.Top      :=  25;
  Button1.Left     :=  25;
  Button1.Height   :=  25;
  Button1.Width    := 150;
  Button1.Caption  := 'Start HotKeyTest';
  Button1.OnClick  := @StartHotKeyTest;
 
  Frame1           := TFrame.Create(nil);
  Frame1.Parent    := Form1;
  Frame1.Top       :=  75;
  Frame1.Left      :=  50;
  Frame1.Height    := 450;
  Frame1.Width     := 700;
  Frame1.Color     := clwhite;
  Frame1.OnPaint   := @Frame1Paint;
 
  Bmp1             := TBitmap.Create;
  Bmp1.SetSize(700,450);
  Bmp1.Canvas.Rectangle(0,0,700,450);
 
  Timer1            := TTimer.Create(nil);
  Timer1.Enabled    := false;
  Timer1.Interval   := 1000;
  Timer1.OnTimer    := @Timer1Timer;
 
end;
 
procedure TForm1.StartHotKeyTest(Sender: TObject);
begin
 win:=form1.Handle;
 ShowWindow(win,SW_minimize);
 Form1.Timer1.Enabled:=true;
end;
 
procedure TForm1.Frame1Paint(Sender: TObject);
begin
  Frame1.Canvas.Draw(0,0,Bmp1);
end;
 
procedure TForm1.Timer1Timer(Sender: TObject);
begin
  Form1.Timer1.Enabled:=false;
  if pruefeState then
   begin
    Bmp1.Canvas.StretchDraw(Rect(0,0,700,450),HotKey);
    Frame1.Invalidate;
   end;
end;
 
procedure TForm1.Danach;
begin
 Form1.WindowState:=wsnormal;
 DialogFenster          := TForm.Create(Form1);
 DialogFenster.Left     :=  (Screen.Width div 2) - 100;
 DialogFenster.Top      :=  (Screen.Height div 2) - 300;
 DialogFenster.Width    := 200;
 DialogFenster.Height   := 100;
 DialogFenster.Caption  := 'TestHotKey';
 DialogFenster.Color    := clwhite;
 DialogFenster.FormStyle:= fsStayOnTop;
 
 Button2          := TButton.Create(nil);
 Button2.Parent   := DialogFenster;
 Button2.Top      :=  25;
 Button2.Left     :=  25;
 Button2.Height   :=  25;
 Button2.Width    := 150;
 Button2.Caption  := 'Anwendung öffnen';
 Button2.OnClick  := @Oeffnen;
 
 DialogFenster.ShowModal;
 Form1.Show;
end;
 
procedure TForm1.Oeffnen(sender: TObject);
begin
 DialogFenster.Close;
end;
 
 
end.         
 

Frank Ranis
Beiträge: 201
Registriert: Do 24. Jan 2013, 21:22

Re: Linux, XGrabKey, Fenster minimieren

Beitrag von Frank Ranis »

Hi,

warum die Form minimieren , maximieren.

Nutz doch einfach das Alpha-Blending der Form ,
0 für unsichtbar machen , dann Screenshot , dann 255 für sichtbar machen.
Funzt unter Linux und Windows .

Code: Alles auswählen

unit unit2;
 
{$mode objfpc}{$H+}
 
interface
 
uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ExtCtrls,
  LCLType,LCLIntf, StdCtrls;
type
 
  { TForm2 }
 
  TForm2 = class(TForm)
    Timer1: TTimer;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
    procedure FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
    procedure FormPaint(Sender: TObject);
  private
  public
   MyBitmap: TBitmap;
   procedure screenshot;
  end;
 
var
  Form2: TForm2;
 
implementation
 
{$R *.lfm}
 
{ TForm2 }
 
// Foto vom ganzen Bildschirm machen
procedure TForm2.screenshot;
var
  ScreenDC: HDC;
begin
  ScreenDC := GetDC(0);
  MyBitmap.LoadFromDevice(ScreenDC);
  ReleaseDC(0,ScreenDC);
end;
 
// Bitmap erzeugen
// Form2.AlphaBlend := True;
// Form2.AlphaBlendValue:=255;    die Form 100% sichtbar
procedure TForm2.FormCreate(Sender: TObject);
begin
 MyBitmap := TBitmap.Create;
 Form2.AlphaBlendValue:=255;
 Form2.AlphaBlend := True;
end;
 
// Bitmap killen
procedure TForm2.FormDestroy(Sender: TObject);
begin
 freeandnil(MyBitmap);
end;
 
// Tastenkombi shift-ctrl-P für Screenshot
// und
// shift-ctrl-C für Bitmap clear
procedure TForm2.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState
  );
begin
 // Bildschirmfoto machen
 if (ssCtrl in Shift) and (ssshift in Shift) and (key=80)
  then
   begin
    Form2.AlphaBlendValue := 0; // Die Sichbarkeit des Forms auf 0 setzen
    screenshot; // Screenshot-Procedure aufrufen
   end;
 
 // Bitmap clear
 if (ssCtrl in Shift) and (ssshift in Shift) and (key=67)
  then
   begin
    MyBitmap.free;
    MyBitmap := TBitmap.Create;
   end;
end;
 
// Taste loslassen
procedure TForm2.FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
 Form2.AlphaBlendValue := 255; // Form wieder voll sichtbar
 invalidate; // Form2 neu zeichnen
end;
 
// Bitmap zeichnen
procedure TForm2.FormPaint(Sender: TObject);
begin
 Form2.Canvas.Draw(0,0,mybitmap);
end;
 
end.
 


Gruß

Frank
www.flz-vortex.de

wennerer
Beiträge: 507
Registriert: Di 19. Mai 2015, 20:05
OS, Lazarus, FPC: Linux Mint 20 Cinnamon,Lazarus 2.2.6 (rev lazarus_2_2_6) FPC 3.2.2 x86_64-linux-
CPU-Target: x86_64-linux-gtk2

Re: Linux, XGrabKey, Fenster minimieren

Beitrag von wennerer »

Hallo Frank,
habs grad mal probiert. Geht echt gut!!! Das mit Alpha-Blending kannte ich nicht. Bin aber nur Hobby Programmierer. Vielen Dank für dein Beispiel.
Gruß Bernd

Frank Ranis
Beiträge: 201
Registriert: Do 24. Jan 2013, 21:22

Re: Linux, XGrabKey, Fenster minimieren

Beitrag von Frank Ranis »

Hallo Bernd,

wennerer hat geschrieben:Hallo Frank,
habs grad mal probiert. Geht echt gut!!! Das mit Alpha-Blending kannte ich nicht. Bin aber nur Hobby Programmierer. Vielen Dank für dein Beispiel.
Gruß Bernd


ja und so einfach mit LAZ-Standard-Komponenten .

Müsste man nun nur noch was proggen , um einen ausgewählten Bereich des Bildschirmes zu scannen.
Z.B. die Außenkontur des Form's selber als Bereich nutzen und dann die Werte Top, Left , Width , Heigth für die Größe des Scann-Ausschnittes nehmen.

Man könnte den Grund-AlphaBlendValue z.B. auch auf einen Wert so um 200 setzen.
Dann ist das Form noch sichtbar und läßt sich mit der Maus anpacken und verschieben und auch in der Größe ändern.
Das lässt dann den Hintergrund noch durchschimmern und man kann so den Wunschbereich gut auswählen .
So ne Art Picture-Picker für Anleitungen o.ä.

Wenn Du dein Programm fertig hast und es kein Geheimnis ist , dann veröffentliche es doch hier .

Gruß

Frank
www.flz-vortex.de

Antworten