Lazarus

Using the Lazarus IDE => Designer => Topic started by: conray on September 20, 2007, 01:47:18 pm

Title: Sendkeys
Post by: conray on September 20, 2007, 01:47:18 pm
how can i perform the sendkey function in lazarus  :lol:
Title: RE: Sendkeys
Post by: Marc on September 20, 2007, 05:56:41 pm
not
Title: RE: Sendkeys
Post by: antonio on September 20, 2007, 05:59:06 pm
Do you want to simulate keyboard? Why?
Title: Sendkeys
Post by: conray on September 20, 2007, 06:44:47 pm
The reason why i need the sendkey to emulate the keyboard press is that instead of press the key board enter button a million times ,i can get it done via software or any other key on the keyboard
Title: RE: Sendkeys
Post by: antonio on September 20, 2007, 07:00:55 pm
http://www.lazarus.freepascal.org/index.php?name=PNphpBB2&file=viewtopic&t=1650&highlight=simulate+keyboard
Title: RE: Sendkeys
Post by: felipemdc on September 20, 2007, 09:25:38 pm
You can use the Windows API SendMessage. Of course this will only work on Windows.
Title: RE: Sendkeys
Post by: antonio on September 20, 2007, 09:28:09 pm
sekel: And which is the message, please?
Title: RE: Sendkeys
Post by: conray on September 20, 2007, 09:29:46 pm
Sekel i need it to work in linux as well
:mrgreen:
Title: RE: Sendkeys
Post by: antonio on September 20, 2007, 09:31:44 pm
Probably there is no way.
Title: RE: Sendkeys
Post by: conray on September 20, 2007, 09:36:07 pm
is it possible to import .pas fle from delphi , if that is possible then it can be done
 :mrgreen:
Title: RE: Sendkeys
Post by: antonio on September 20, 2007, 09:38:18 pm
Delphi implements this through Windows API.
Title: RE: Sendkeys
Post by: conray on September 20, 2007, 09:40:04 pm
Thanks :)
Title: RE: Sendkeys
Post by: felipemdc on September 20, 2007, 10:20:13 pm
It may be possible to do this using ifdefs. Use SendMessage on windows and a gtk function on linux. I have no idea which gtk function that would be, or even if there is one that does it.
Title: RE: Sendkeys
Post by: antonio on September 20, 2007, 10:21:48 pm
sendmessage(handle, wm_close, 0, 0) ?
Title: Re: Sendkeys
Post by: kris on December 03, 2017, 06:22:59 am
First of all, to all of you, but especially to: Marc and antonio:
PLEASE DO NOT say that something cannot be done just because you don't know how to do it!

Now, regarding the Linux part, I think the way to gou would be with gtk_main_do_event() from libgtk-x11-2.0.

The declaration in Lazarus would be:
  procedure gtk_main_do_event(GDKEvent : PGDKEvent); cdecl;external 'gtk-x11-2.0' name 'gtk_main_do_event';

The PGdkEvent type is declared in gdk2 unit;

The documentation mentions the call here: https://developer.gnome.org/gtk3/stable/gtk3-General.html#gtk-main-do-event

and someone has a code snipped on using it for sending key event (although not in Lazarus) here: https://mail.gnome.org/archives/gtk-app-devel-list/2004-July/msg00016.html

Btw, I just myself am tyring to implement this, and googled out this thread. People who comment on things not being possible without actually knowing, or questioning the asker's reason for wanting to do something in the first place ARE NOT HELPFUL !
Title: Re: Sendkeys
Post by: kris on December 03, 2017, 07:08:01 am
so far, I rewrote the code from https://mail.gnome.org/archives/gtk-app-devel-list/2004-July/msg00016.html into Lazarus, but I'm still getting crash error on gtk_main_do_event(Event);

I also learned that gtk_main_do_event is already defined in the unit gtk2.pas, so you do not need to define it yourself (i shared the declaration in the previous answer).

This is the code I have so far:
Code: Pascal  [Select][+][-]
  1.   Procedure TGtkTerm.SendKey(AKey: char);
  2.    var
  3.      Event      : PGdkEvent;
  4.      hw_keycode : ctypes.cuint16;
  5.      keys       : PGdkKeymapKey;
  6.      n_keys     : ctypes.cint;
  7.    begin
  8.      if(self.Vte=nil)then exit;
  9.      write('gdk_keymap_get_entries_for_keyval... ');
  10.      if gdk_keymap_get_entries_for_keyval(gdk_keymap_get_default(), ord(AKey), keys, @n_keys)
  11.         then try
  12.                hw_keycode                  := keys[0].keycode;
  13.                writeln('done.');
  14.                writeln('hw_keycode=',hw_keycode,'; keys freed.');
  15.              finally
  16.                g_free(keys);
  17.                writeln('failed.');
  18.              end
  19.         else exit;
  20.  
  21.      write('gdk_event_new (GDK_KEY_PRESS)... ');
  22.      Event := gdk_event_new(GDK_KEY_PRESS);
  23.      if(Event=nil)
  24.        then writeln('failed.')
  25.        else writeln('done.');
  26.      if(Event=nil)then exit;
  27.      try
  28.        Event^.key.window           := self.Vte^.window;
  29.        Event^.key.state            := 0;//GDK_MOD1_MASK; {alt}
  30.        Event^.key.hardware_keycode := hw_keycode;
  31.  
  32.        Event^.key.keyval           := gdk_unicode_to_keyval(ord(AKey));
  33.        Event^.key.length           := 1;
  34.        writeln('key.keyval=',Event^.key.keyval);
  35.  
  36.        Event^.key.send_event       := 0;
  37.        Event^.key.time             := GDK_CURRENT_TIME;
  38.  
  39.        write('gtk_main_do_event(Event);... ');
  40.        try
  41.          gtk_main_do_event(Event);
  42.          writeln('done.');
  43.        except
  44.          writeln('failed.');
  45.        end;
  46.      finally
  47.        gdk_event_free(Event);
  48.      end;
  49.    end;
  50.  

Will try to make it work, but at least this is what I have for now, and at least i translated the lnked sample code into Lazarus for your convenience. If any of you ever get to this point and solves the error, pls share. If I fix the error, I'll share as well.
Title: Re: Sendkeys
Post by: taazz on December 03, 2017, 12:01:39 pm
Will try to make it work, but at least this is what I have for now, and at least i translated the lnked sample code into Lazarus for your convenience. If any of you ever get to this point and solves the error, pls share. If I fix the error, I'll share as well.
A 10 year old excavation. Nice! Assuming you are looking for a way to send keys, I recommend to take a look on the mouseandkeyInput (http://wiki.freepascal.org/MouseAndKeyInput) package. It claims to support sending keys.
Title: Re: Sendkeys
Post by: kris on December 03, 2017, 04:41:28 pm
Thank you VERY much for the hint on http://wiki.freepascal.org/MouseAndKeyInput (http://wiki.freepascal.org/MouseAndKeyInput) !!
I just wanted to share that before I saw your reply, I already followed similar solution on my own. Also depending on a 3rd party library, but in my case I used libxdo, used by xdotool:
Also on the wiki about MouseAndKeyInput, under Gtk chapter it reads:
Quote
(...) ALT key pressing is not supported (...)
and libxdo does not have that limitation.

For my needs I only had to be able to send keyboard key events, no mouse. libxdo has plenty of exported functions, but I only ported these:
Code: Pascal  [Select][+][-]
  1.  
  2.   function xdo_new(display:Pchar): pxdo_t;cdecl;external 'xdo' name 'xdo_new';
  3.   function xdo_send_keysequence_window(xdo:Pxdo_t; window: window_t; keysequence:Pchar; delay:useconds_t):longint; cdecl;external 'xdo' name 'xdo_send_keysequence_window';
  4.   function xdo_send_keysequence_window_up(xdo:Pxdo_t; window: window_t; keysequence:Pchar; delay:useconds_t):longint;cdecl;external 'xdo' name 'xdo_send_keysequence_window_up';
  5.   function xdo_send_keysequence_window_down(xdo:Pxdo_t; window: window_t; keysequence:Pchar; delay:useconds_t):longint;cdecl;external 'xdo' name 'xdo_send_keysequence_window_down';
  6.  
and then I added my own wrapper function:
Code: Pascal  [Select][+][-]
  1. (...)
  2. implementation
  3. { API }
  4.   var
  5.     FXDO : pxdo_t = nil;
  6.  
  7.   Function SendKey(const WindowId: longint; const sequence: string): Boolean;
  8.    var
  9.      pc : pchar;
  10.    begin
  11.      if(FXDO=nil)then FXDO := xdo_new(nil);
  12.      if(FXDO=nil)then exit;
  13.      pc := pchar(sequence);
  14.      Result := xdo_send_keysequence_window(FXDO, WindowId, pc, 0)=0;
  15.    end;
  16. (...)
  17.  

As you can see in the external functions headers, there are some proprietary types, but I used FPC included h2pas tool to auto-convert the xdo.h file (https://github.com/jordansissel/xdotool/blob/master/xdo.h (https://github.com/jordansissel/xdotool/blob/master/xdo.h)) from c to pascal, and it did the job. I had to:

it really works flawlessly!!!
Title: Re: Sendkeys
Post by: kris on December 03, 2017, 04:53:08 pm
I thought that if someone would like to also use libxdo, I should extend this info by how to pass valid WindowId to the calls I shared.

Manually, when using xdotool from terminal, I usually find window id with "wmctrl -l" command. Wmctrl is not installed in Ubuntu by default, so: $ sudo apt-get install wmctrl.

"wmctrl -l" will list all the windows currently managed by the x11 window manager, and the very first column will be window id. The Id is a number, wmctrl prints it in hex. The format used is to prefix hex number with "0x", but Object Pascal uses '$' as default hex prefix. So, for example, "0xfefe" in Object Pascal would be:
Code: Pascal  [Select][+][-]
  1. const
  2.   C_HEX_VALUE = $fefe; //0xfefe
  3.  
also, the last column of "wmctrl -l" output is the window's title. So I wrote a function that can return window's id by window's title:
Code: Pascal  [Select][+][-]
  1. (...)
  2. uses
  3.   (...), Process, (...);
  4.  
  5.   Procedure grep(var s: string; const grepstr: string);
  6. implementation
  7.   Procedure grep(var s: string; const grepstr: string);
  8.    var
  9.      SL : TStringList;
  10.    begin
  11.      if(grepstr='')then
  12.        begin
  13.          s := '';
  14.          exit;
  15.        end;
  16.      SL := TStringList.Create;
  17.      try
  18.        SL.Text := s; s := '';
  19.        while(SL.Count>0)do
  20.          begin
  21.            if Pos(grepstr,SL[0])>0 then s := s+SL[0]+sLineBreak;
  22.            SL.Delete(0);
  23.          end;
  24.      finally
  25.        FreeAndNil(SL);
  26.        s := trim(s);
  27.      end;
  28.    end;
  29.  
  30. (...)
  31.  
  32. Procedure TForm1.cmdButtonClick(Sender: TObject);
  33.   var
  34.     WindowId : longint;
  35.     s,c            : string;
  36.     p              : integer;
  37.   begin
  38.      if not Process.RunCommand('wmctrl',['-l'],s)then exit;
  39.      grep(s,'VTE Terminal');
  40.      { because the window I wanted the Id of has that title, you should use whatever applies to your case }
  41.      p := Pos(' ',s);
  42.      if(p>0)
  43.        then s := trim(Copy(s,1,p-1))
  44.        else s := '';
  45.      if Copy(s,1,2)='0x'
  46.        then Delete(s,1,2)
  47.        else exit;
  48.      WindowId := StrToIntDef('$'+s,0);
  49.      if(WindowId<=0)then exit;
  50.      writeln('WindowId='+s);
  51.      while(c<>'')do
  52.        begin
  53.          libXDO.SendKey(WindowId, Copy(c,1,1));
  54.          Delete(c,1,1);
  55.        end;
  56.      libXDO.SendKey(WindowId, 'KP_Enter');}
  57.   end;
  58.  

just remember that this depends on wmctrl being installed on the system, which it is not by default on Ubuntu. That's just one way though, you could use x11 APIs from lazarus, but this way was faster for me.
I once found lazarus units that have functions for listing windows and their Id, so it is definitely possible not to depend on wmctrl, but there it is, as a reference.
Title: Re: Sendkeys
Post by: kris on December 03, 2017, 06:05:32 pm
I published the library: https://sourceforge.net/p/all-things-ubuntu-library/code/HEAD/tree/trunk/libxdo.pas
Title: Re: Sendkeys
Post by: bytebites on December 03, 2017, 06:19:11 pm

Also on the wiki about MouseAndKeyInput, under Gtk chapter it reads:
Quote
(...) ALT key pressing is not supported (...)


Code: Pascal  [Select][+][-]
  1.   VK_MENU: Result := XK_VoidSymbol; // alt key crashes app, XK_Alt_R;

Actually  Alt-left works, if you change code in xkeyinput-file:

Code: Pascal  [Select][+][-]
  1. VK_MENU: Result := XK_Alt_L;
Title: Re: Sendkeys
Post by: kris on December 03, 2017, 06:40:44 pm
very interesting how this topic came back to life after all these years.
Kudos to bytebites for sharing the patch ;)

I could only wish for someone knowledgeable to find this thread and also help me to figure out why the approach using gtk_main_do_event did not work for me.
Title: Re: Sendkeys
Post by: Zoran on December 03, 2017, 11:11:22 pm
A 10 year old excavation. Nice! Assuming you are looking for a way to send keys, I recommend to take a look on the mouseandkeyInput (http://wiki.freepascal.org/MouseAndKeyInput) package. It claims to support sending keys.

Or better don't take a look at it, unless you want to license your code under GPL (and you will have to, if you take any piece of code from it).
MouseAndKeyInput package is under GPL (http://wiki.freepascal.org/MouseAndKeyInput#License), which makes it unusable for many Lazarus users.
So, another solution with more permissive license will be welcomed.
Title: Re: Sendkeys
Post by: Thaddy on January 20, 2018, 12:33:15 pm
Kris, you are responding to an 11 year old thread.

Better to look at the wiki under keupress http://wiki.lazarus.freepascal.org/LCL_Key_Handling

That's cross-platform.
TinyPortal © 2005-2018