Recent

Author Topic: [Solved]Simulate keypress TProcess.  (Read 7177 times)

chrnobel

  • Sr. Member
  • ****
  • Posts: 283
[Solved]Simulate keypress TProcess.
« on: September 27, 2019, 12:23:19 pm »
Hi.

This might be a little OT, but I dare.

As I have written in another thread, I am playing with controlling Omxplayer from a command line program.

So far this works ok, I can start and kill Omxplayer on demand.

However I would like to control the actions of the Omxplayer from my program, meaning sending keystrokes like 'p' for pause, '<' for rewind, etc.

This can be done from command line by the use of a named pipe on Raspbian, but I am using Alpine Linux (a really cool distro, very small, and runs 100% out of RAM, so no usual trail of corrupted SD cards), and for some odd reason the Omxplayer in the Alpine package does not support named pipes, neither DBUS.

So I am left to find a method where I truly can simulate a keyboard stroke, like someone physically connected to the terminal that controls the Omxplayer - and btw. if I start the Omxplayer over SSH, the player plays as expected on the console, and reacts to keypresses in the terminal, so it should be possible to simulate this behaviour in software.

Anyone having a good idea?
« Last Edit: October 04, 2019, 10:14:02 am by chrnobel »

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 12601
  • FPC developer.
Re: Simulate keypress TProcess.
« Reply #1 on: September 27, 2019, 12:29:10 pm »
Note that many programs detect when they are piped (isatty()) and suddenly behave differently, e.g. turning off fullscreen options etc.

IOW you can't expect that omxplayer behaves the same in a TProcess pipe as on the terminal.

winni

  • Hero Member
  • *****
  • Posts: 3197
Re: Simulate keypress TProcess.
« Reply #2 on: September 27, 2019, 12:48:13 pm »
Hi!

Give the unit MouseAndKeyInput a try. It simulates every keystroke and mouseclick you like.

It is located in lazarus/components/mousandkeyinput/

Winni

Edson

  • Hero Member
  • *****
  • Posts: 1326
Re: Simulate keypress TProcess.
« Reply #3 on: September 28, 2019, 12:08:40 am »
If Omxplayer read the stdin/stdout just send the proper keys.

If Omxplayer requires a terminal (not a pipe), you need to control using a terminal o simulating a terminal.
Lazarus 2.2.6 - FPC 3.2.2 - x86_64-win64 on Windows 10

chrnobel

  • Sr. Member
  • ****
  • Posts: 283
Re: Simulate keypress TProcess.
« Reply #4 on: September 29, 2019, 05:19:27 pm »
If Omxplayer read the stdin/stdout just send the proper keys.
Sigh.

There is no keyboard attached, as said.
Quote
o simulating a terminal.
Which was exactly the question I asked:

How do I simulate a keyboard, without piping?

lucamar

  • Hero Member
  • *****
  • Posts: 4219
Re: Simulate keypress TProcess.
« Reply #5 on: September 29, 2019, 08:17:51 pm »
If Omxplayer read the stdin/stdout just send the proper keys.
Sigh.

There is no keyboard attached, as said.

It doesn't matter whether there is a keyboard or not. What matters is whether the program reads from/writes to stdin/stdout. If that's the case, then sending the proper characters to the player should work.

To test it, just start playing something and at some time send a "p" or a space to pause/resume playback

Of course, to do that you must use pipes, but they don't necessarilly need to be named ones; you can just assign streams to in/out and connect them to the process.
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus/FPC 2.0.8/3.0.4 & 2.0.12/3.2.0 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

jamie

  • Hero Member
  • *****
  • Posts: 7495
Re: Simulate keypress TProcess.
« Reply #6 on: September 29, 2019, 09:29:56 pm »
why not run a network connection and have it sit in a thread waiting for input from another source?
The only true wisdom is knowing you know nothing

chrnobel

  • Sr. Member
  • ****
  • Posts: 283
Re: Simulate keypress TProcess.
« Reply #7 on: September 29, 2019, 11:11:14 pm »
It doesn't matter whether there is a keyboard or not. What matters is whether the program reads from/writes to stdin/stdout. If that's the case, then sending the proper characters to the player should work.

To test it, just start playing something and at some time send a "p" or a space to pause/resume playback
Let me clarify:

If I use the Omxplayer compiled for Raspbian, I can control it by sending keystrokes like "p" or I can use a named pipe, end echo a "p" and it pauses.

If I try to do the same in the Omxplayer compiled for Alpine Linux, I can still control it by sending a "p" as a keystoke (and rewind, and pause again, etc.),  BUT it do not react to a "p" send via the named pipe - and to make it even more odd, it actually wait to see if something comes "out of the pipe", in that sense that, if started with a name pipe, it does not start playing until it sees something (anything) from the fifo, but then it is totally ignorant to what comes next from the pipe afterwards.

So to repeat:

mkfifo /tmp/omxcontrol
omxplayer -ohdmi mymedia.avi < /tmp/omxcontrol
echo -n p > /tmp/omxcontrol       

On the Raspbian Omxplayer  this starts the player, and immediately it pauses.
On the Alpine Omxplayer this starts the player.

echo -n p > /tmp/omxcontrol    #a second time.
On the Raspbian Omxplayer  this starts the player instantly, as it is loaded in the buffer, and paused at first frame.
On the Alpine Omxplayer absolutely nothing happens.

So I need at way to make the Omxplayer think it is controlled by at keyboard.

Quote
Of course, to do that you must use pipes, but they don't necessarilly need to be named ones; you can just assign streams to in/out and connect them to the process.
Which stream, streams of what?

chrnobel

  • Sr. Member
  • ****
  • Posts: 283
Re: Simulate keypress TProcess.
« Reply #8 on: September 29, 2019, 11:21:15 pm »
why not run a network connection and have it sit in a thread waiting for input from another source?
How should this change the behaviour of Omxplayer?

My big problem is not starting Omxplayer as such, but synchronizing my players, which I hope to do by loading Omxplayer, and immediately pause it with a "p", and then wait some 500ms, until I am sure all players are loaded, and ready at first frame, and then send another "p" to start them - and for that I need at way to send the "p", which as said do not work by piping.

Network controlling is no problem, that is very simple to do with Synapse, and multicasting.   

Edson

  • Hero Member
  • *****
  • Posts: 1326
Re: Simulate keypress TProcess.
« Reply #9 on: September 30, 2019, 03:18:30 am »
So I need at way to make the Omxplayer think it is controlled by at keyboard.

Have you tested "expect" utility?

You can always write yout own terminal and control any process as controlled by keyboard. I wrote a sample code like this: https://github.com/t-edson/Titty
Lazarus 2.2.6 - FPC 3.2.2 - x86_64-win64 on Windows 10

lucamar

  • Hero Member
  • *****
  • Posts: 4219
Re: Simulate keypress TProcess.
« Reply #10 on: September 30, 2019, 10:45:50 am »
Quote
Of course, to do that you must use pipes, but they don't necessarilly need to be named ones; you can just assign streams to in/out and connect them to the process.
Which stream, streams of what?

My mistake, sorry. I meant the TOutputPipeStream/TInputPipeStream (unit Pipes of the FCL) that are assigned to TProcess.Input and TProcess.OutPut (+ TProcess.StdErr if you don't redirect it to Output) when you set poUsePipes in TProcess.Options.

Acording to the docs they are automaticaly instantiated so you need do nothing to assign them; just send the translated keystrokes to Input and read from Output/StdErr.
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus/FPC 2.0.8/3.0.4 & 2.0.12/3.2.0 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

Thaddy

  • Hero Member
  • *****
  • Posts: 18712
  • To Europe: simply sell USA bonds: dollar collapses
Re: Simulate keypress TProcess.
« Reply #11 on: September 30, 2019, 12:06:48 pm »
Correct.
If Europe sells their USA bonds the USD will collapse. Europe can affort that given average state debts. The USA can't affort that. Just an advice...

garlar27

  • Hero Member
  • *****
  • Posts: 652
Re: Simulate keypress TProcess.
« Reply #12 on: September 30, 2019, 05:28:35 pm »
Code: Pascal  [Select][+][-]
  1. uses
  2.    MouseAndKeyInput, LCLType, dateutils, strutils;
  3.  
  4. procedure SendChar(const Value: Char; const GenerarNoImprimibles: Boolean = False);
  5. begin
  6.    try
  7.       if Value in ['A'..'Z'] then begin
  8.          //KeyInput.Apply([ssShift]);
  9.       end;
  10.       {$IFDEF LINUX}Write(Value);{$ENDIF}
  11.       if GenerarNoImprimibles then begin
  12.          case Value of
  13.             #8:  begin
  14.                KeyInput.Press(VK_BACK);
  15.                KeyInput.Up(VK_BACK);
  16.             end;
  17.             #9: begin
  18.                KeyInput.Press(VK_TAB);
  19.                KeyInput.Up(VK_TAB);
  20.             end;
  21.             #13: begin
  22.                KeyInput.Press(VK_RETURN);
  23.                KeyInput.Up(VK_RETURN);
  24.             end;
  25.             #32: begin
  26.                KeyInput.Press(VK_SPACE);
  27.                KeyInput.Up(VK_SPACE);
  28.             end;
  29.          end;
  30.       end;
  31.       case Value of
  32.          '*': KeyInput.Press(VK_MULTIPLY);
  33.          '/': KeyInput.Press(VK_DIVIDE);
  34.          '+': KeyInput.Press(VK_ADD);
  35.          '.': KeyInput.Press(VK_DECIMAL);
  36.          '-': KeyInput.Press(VK_SUBTRACT);
  37.          '0': KeyInput.Press(VK_NUMPAD0);
  38.          '1': KeyInput.Press(VK_NUMPAD1);
  39.          '2': KeyInput.Press(VK_NUMPAD2);
  40.          '3': KeyInput.Press(VK_NUMPAD3);
  41.          '4': KeyInput.Press(VK_NUMPAD4);
  42.          '5': KeyInput.Press(VK_NUMPAD5);
  43.          '6': KeyInput.Press(VK_NUMPAD6);
  44.          '7': KeyInput.Press(VK_NUMPAD7);
  45.          '8': KeyInput.Press(VK_NUMPAD8);
  46.          '9': KeyInput.Press(VK_NUMPAD9);
  47.          'a', 'A': KeyInput.Press(VK_A);
  48.          'b', 'B': KeyInput.Press(VK_B);
  49.          'c', 'C': KeyInput.Press(VK_C);
  50.          'd', 'D': KeyInput.Press(VK_D);
  51.          'e', 'E': KeyInput.Press(VK_E);
  52.          'f', 'F': KeyInput.Press(VK_F);
  53.          'g', 'G': KeyInput.Press(VK_G);
  54.          'h', 'H': KeyInput.Press(VK_H);
  55.          'i', 'I': KeyInput.Press(VK_I);
  56.          'j', 'J': KeyInput.Press(VK_J);
  57.          'k', 'K': KeyInput.Press(VK_K);
  58.          'l', 'L': KeyInput.Press(VK_L);
  59.          'm', 'M': KeyInput.Press(VK_M);
  60.          'n', 'N': KeyInput.Press(VK_N);
  61.          'o', 'O': KeyInput.Press(VK_O);
  62.          'p', 'P': KeyInput.Press(VK_P);
  63.          'q', 'Q': KeyInput.Press(VK_Q);
  64.          'r', 'R': KeyInput.Press(VK_R);
  65.          's', 'S': KeyInput.Press(VK_S);
  66.          't', 'T': KeyInput.Press(VK_T);
  67.          'u', 'U': KeyInput.Press(VK_U);
  68.          'v', 'V': KeyInput.Press(VK_V);
  69.          'w', 'W': KeyInput.Press(VK_W);
  70.          'x', 'X': KeyInput.Press(VK_X);
  71.          'y', 'Y': KeyInput.Press(VK_Y);
  72.          'z', 'Z': KeyInput.Press(VK_Z);
  73.       end;
  74.    finally
  75.       if Value in ['A'..'Z'] then begin
  76.          //KeyInput.Unapply([ssShift]);
  77.       end;
  78.    end;
  79. end; {<--- SendLetra }
  80.  
  81.  
  82. procedure SendKey(const Value: Word);
  83. begin
  84.    KeyInput.Press(Value);
  85. end;
  86.  

To use this fake-keyboard-event is very awkward I would go by a Simple Inter Process Communication or a network connection as suggested by jamie.

why not run a network connection and have it sit in a thread waiting for input from another source?
How should this change the behaviour of Omxplayer?

My big problem is not starting Omxplayer as such, but synchronizing my players, which I hope to do by loading Omxplayer, and immediately pause it with a "p", and then wait some 500ms, until I am sure all players are loaded, and ready at first frame, and then send another "p" to start them - and for that I need at way to send the "p", which as said do not work by piping.

Network controlling is no problem, that is very simple to do with Synapse, and multicasting.   
Don't know the code of Omxplayer. But if you can modify it I would add something to synchronize it with other players...

chrnobel

  • Sr. Member
  • ****
  • Posts: 283
Re: Simulate keypress TProcess.
« Reply #13 on: September 30, 2019, 06:50:30 pm »
Give the unit MouseAndKeyInput a try. It simulates every keystroke and mouseclick you like.
As far as I can see, the MouseAndKeyInput is for GUI applications only.

chrnobel

  • Sr. Member
  • ****
  • Posts: 283
Re: Simulate keypress TProcess.
« Reply #14 on: September 30, 2019, 06:58:26 pm »
But if you can modify it I would add something to synchronize it with other players...
If I was able to modify it, I would not have any problem, as it then would be easy to control it by a named pipe.

Therefore there is the same problem with Simple Inter Process Communication (which is a named pipe) or a network connection (which still needs at way to communicate with the omxplayer).

I need to play a bit with Tprocess, maybe that could be a solution - however I have not found any examples how I can use Tprocess as a kind of wrapper (meaning have the pipe open and controlling the executable) for an application.

Otherwise uinput could be a solution, but I have not found any pascal examples for that. 

 

TinyPortal © 2005-2018