Recent

Author Topic: unread input  (Read 1440 times)

freemind001

  • New Member
  • *
  • Posts: 35
unread input
« on: March 18, 2023, 09:34:00 am »
how do i discard unread input in console program?
need to clear everything before calling readln();

KodeZwerg

  • Hero Member
  • *****
  • Posts: 2088
  • Fifty shades of code.
    • Delphi & FreePascal
Re: unread input
« Reply #1 on: March 18, 2023, 10:42:53 am »
Code: Pascal  [Select][+][-]
  1. program Project1;
  2.  
  3. {$IFDEF MSWINDOWS}{$APPTYPE CONSOLE}{$ENDIF}
  4.  
  5. uses
  6.   CRT; // this must be included for oldschool console apps
  7.  
  8. begin
  9.   ClrScr; // this method "Clr = Clear / Scr = Screen" call whenever needed
  10. end.
« Last Edit: Tomorrow at 31:76:97 xm by KodeZwerg »

freemind001

  • New Member
  • *
  • Posts: 35
Re: unread input
« Reply #2 on: March 18, 2023, 11:40:33 am »
I'm not about about clearing the screen, I'm about standart input.
During execution of program the user is asked to press keys, that readln(); can't handle. (e.g. ENTER or PAUSE)
These keypresses are handled with direct '/dev/input' reading.

Then i need user to enter the string.
i do readln(str); but after that str also contains all the stuff that user entered before readln call.
how do i clear it?

jcmontherock

  • Full Member
  • ***
  • Posts: 236
Re: unread input
« Reply #3 on: March 18, 2023, 12:11:03 pm »
Did you try "Keyboard" ?
Windows 11 UTF8-64 - Lazarus 3.2-64 - FPC 3.2.2

Warfley

  • Hero Member
  • *****
  • Posts: 1499
Re: unread input
« Reply #4 on: March 18, 2023, 12:27:16 pm »
Simple do a non bocking read (or peak) to stdin, if there is something read it and discard what you have read

freemind001

  • New Member
  • *
  • Posts: 35
Re: unread input
« Reply #5 on: March 18, 2023, 12:54:41 pm »
Did you try "Keyboard" ?
what do you mean?

freemind001

  • New Member
  • *
  • Posts: 35
Re: unread input
« Reply #6 on: March 18, 2023, 12:57:45 pm »
Simple do a non bocking read (or peak) to stdin, if there is something read it and discard what you have read
How do i do that in pascal?

Warfley

  • Hero Member
  • *****
  • Posts: 1499
Re: unread input
« Reply #7 on: March 18, 2023, 01:07:33 pm »
Depends on your concrete situation, and what you want to do.

You need to first understand how console I/O is working. There are two modes of reading input, the first one is raw, the second one is buffered. The default configuration is buffered, then your terminal emulator will capture all the inputs and only send them to your programs stdin when you pressed enter/newline.
If you are operating in this configuration it's really easy, just check if input is available (e.g. using fpselect) and do readlines until no more input is available.

In raw mode each char (and keycode) is sent individually to your application, in this case you could read every char until the buffer is empty, or you do a non blocking read with a large buffer until you don't read any more bytes.

You may take a look at my LazTermUtils compatibility unit, which has a lot of the raw functionality: https://github.com/Warfley/LazTermUtils/blob/master/src/compatibility.pas#L175

KodeZwerg

  • Hero Member
  • *****
  • Posts: 2088
  • Fifty shades of code.
    • Delphi & FreePascal
Re: unread input
« Reply #8 on: March 18, 2023, 01:14:01 pm »
i do readln(str); but after that str also contains all the stuff that user entered before readln call.
how do i clear it?
Switch from ReadLn() to ReadKey() from unit CRT and filter there everything out what you not need in final string
(a simple while or repeat until loop would be okay for that scenario)
« Last Edit: Tomorrow at 31:76:97 xm by KodeZwerg »

freemind001

  • New Member
  • *
  • Posts: 35
Re: unread input
« Reply #9 on: March 18, 2023, 01:18:50 pm »
what you want to do

Code: Pascal  [Select][+][-]
  1. program project1;
  2. uses
  3.   sysutils;
  4. var
  5.   s:string;
  6. begin
  7.   writeln('Program is doing some job, emulating this with sleep');
  8.   sleep(5000); //input A while program is busy
  9.   //need to clear input here
  10.   writeln('Now input B');
  11.   Readln(s);
  12.   writeln('s contains A and B: ', s); // need s to contain B only
  13. end.
  14.        

Warfley

  • Hero Member
  • *****
  • Posts: 1499
Re: unread input
« Reply #10 on: March 18, 2023, 01:45:24 pm »
So you are in buffered mode, the problem here is a bit that this way you can only clear full lines. Take the following example:
Code: Pascal  [Select][+][-]
  1.   sleep(5000); // Type something without pressing enter
  2.   WriteLn('Test');
  3.   ReadLn(ln); // Now waits for enter but still has the things typed before
  4.   WriteLn(ln);
It should be also noted that there are big differences between windows and Linux, I am currently under Windows so I can't just test it out for you.
But if you want to avoid this, I think what should work is changing the mode to raw mode (see EnableDirectRead in my Compatibility.pas https://github.com/Warfley/LazTermUtils/blob/master/src/compatibility.pas#L143)
Then read the data, as this now does not need to be buffered anymore, and then restore to buffered mode when reading the line (see RestoreDirectRead right below EnableDirectRead).

Or with my TermUtils Unit:
Code: Pascal  [Select][+][-]
  1. program Project1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. uses
  6.   SysUtils, Terminal;
  7.  
  8. var
  9.   term: TTerminal;
  10.   ln: String;
  11.   dummy: Char;
  12. begin
  13.   term := TTerminal.Create;
  14.   try
  15.     Sleep(1000);
  16.     term.Input.DirectRead := True; // Enable raw mode for consuming buffer
  17.     try
  18.       while term.Input.ReadCharNonBlocking(dummy) do; // Consume all buffer
  19.     finally
  20.       term.Input.DirectRead := false; // Disable raw mode for normal readln behavior
  21.     end;
  22.     WriteLn('Please enter text');
  23.     ln := term.input.ReadLn; // Or plain old readln if you want to
  24.     WriteLn(ln);
  25.   finally
  26.     term.Free;
  27.   end;
  28.   ReadLn;
  29. end.
  30.  

Warfley

  • Hero Member
  • *****
  • Posts: 1499
Re: unread input
« Reply #11 on: March 18, 2023, 01:50:06 pm »
Switch from ReadLn() to ReadKey() from unit CRT and filter there everything out what you not need in final string
(a simple while or repeat until loop would be okay for that scenario)
But you should be aware that including crt into the project will completely alter the behavior of input reading and buffering (well, not just input but also output behavior will be completely altered). This means that most low level OS operations like ioctl might not work as expected, select, or non blocking reads don't work anymore, etc.
If you choose to use CRT you must know that you can't use any non CRT terminal functionality anymore. It especially detaches from the low level OS APIs, which might make it incompatible with other code.

My personal recommendation is to avoid the CRT unit whenever possible

KodeZwerg

  • Hero Member
  • *****
  • Posts: 2088
  • Fifty shades of code.
    • Delphi & FreePascal
Re: unread input
« Reply #12 on: March 18, 2023, 02:02:01 pm »
Switch from ReadLn() to ReadKey() from unit CRT and filter there everything out what you not need in final string
(a simple while or repeat until loop would be okay for that scenario)
My personal recommendation is to avoid the CRT unit whenever possible
I do fully second that but since I do know as much as you, nothing about target OS, nothing about real purpose, IMHO my answer was legit.
« Last Edit: Tomorrow at 31:76:97 xm by KodeZwerg »

jamie

  • Hero Member
  • *****
  • Posts: 6131
Re: unread input
« Reply #13 on: March 18, 2023, 02:22:52 pm »
SeekEof;

?
The only true wisdom is knowing you know nothing

freemind001

  • New Member
  • *
  • Posts: 35
Re: unread input
« Reply #14 on: March 18, 2023, 02:34:03 pm »
nothing about target OS, nothing about real purpose, IMHO my answer was legit.
target os is linux, the purpose is writing config file for app.
user runs app --config and follows instructions:
Key "A" will be used for "Action A". Press key "A" 
Key "B" will be used for "Action B". Press key "B"
keys A and B may not be readable by readln, so they are read directly from '/dev/input/'
while user presses A and B, they are kept in buffer, and this is a problem for further readln

EnableDirectRead in my Compatibility.pas
what is oldState in your EnableDirectRead?
this
Code: Pascal  [Select][+][-]
  1. program project1;
  2.  
  3. uses
  4.   SysUtils, termio,  BaseUnix;
  5.  
  6. var
  7.   s: string;
  8.   newTIO, oldTIO: Termios;
  9. begin
  10.   TCGetAttr(0, oldTIO);
  11.   TCGetAttr(0, newTIO);
  12.   CFMakeRaw(newTIO);
  13.   TCSetAttr(0, TCSANOW, newTIO);
  14.   writeln('Program is doing some job, emulating this with sleep');
  15.   sleep(5000); //press A
  16.   TCSetAttr(0, TCSANOW, oldTIO);
  17.   writeln('Now input B');
  18.   Readln(s);
  19.   writeln('s contains', s);
  20. end.  
doesn't work, or maybe I do not understand the idea :)
« Last Edit: March 18, 2023, 02:40:39 pm by freemind001 »

 

TinyPortal © 2005-2018