Strange behavior of input and line input

Linux specific questions.
Post Reply
Kyle
Posts: 4
Joined: May 18, 2020 21:09

Strange behavior of input and line input

Post by Kyle »

I'm running some test code on a 32-bit ARM machine in a Linux terminal using the Orca screen reader, in case it helps. Testing this code snippit, I notice some very odd behavior of both Input and Line Input.

Code: Select all

dim as string lineIn
do
  line input ": ", lineIn
  if len (lineIn) > 0 then print "Your input was": print lineIn
loop while true
end
Yes, I know that code looks a little weird, but I'm just using it to run some tests. In any case, I break out of the program with control+c, which works great for the purposes of the test. So I compiled my test code and ran the resulting executable. My problem is that if I type too quickly or hold down any key, even the backspace key so that it repeats, my terminal seems to trip over itself in some way. By this I mean that only part of my input is displayed, and pressing the enter key just adds one more character. For example, I type "This is a test." on my prompt line. If I type it too quickly, I may get "This is a te," so I press enter to finish the line input, and the s is displayed. If I press any other key, I see the t, another and I see the period, and then one more key and the program finally gets the new line character that terminates the input and I see the output that says "Your output was This is a test." The program continues to show 3 characters behind, occasionally lagging further behind, until I terminate the program. I should note that the first couple of iterations through the loop seem to run without difficulty, and compiling with the -mt option seems to help slightly. But the first time it falls behind, sometimes it falls behind by only one key, while at other times it can fall behind immediately by 2 or three keys. In any case, as I mention above, it gets progressively worse until I terminate the program.

At first, I thought I may have spotted a bug in the latest git source, as this is the version that I built from a nightly bootstrap dated January 12. But I built the 1.07.1 release and still see the same issue. At one point I thought I may have caused my terminal to lag somehow with some other tests I was running, but closing the terminal and reopening it only works for a short time, and then the problem returns. Still trying to rule out a terminal bug, I rewrote the test code using another programming language and another compiler, but try as I may, I am unable to reproduce the problem using the new test code. I did try writing my own FreeBASIC subroutine to handle line input, but I couldn't figure out how to at least get backspace working. Did my crazy test somehow uncover a bug that only appears when doing crazy stuff like this? Is there a better way to handle multiple terminal line inputs? Any help is greatly appreciated.
Last edited by counting_pine on May 23, 2020 21:02, edited 1 time in total.
Reason: Fixup code block
badidea
Posts: 2586
Joined: May 24, 2007 22:10
Location: The Netherlands

Re: Strange behavior of input and line input

Post by badidea »

First thought: Try running it with a sleep 1 in the loop. Sorry, same behavior here, sleep 1 does not help.

It could be a bug, the linux terminal in freeBASIC can work very slow in other cases as well.
If I switch to graphic screen (e.g. screenres 800, 600) it works as expected here.

Custom input handlers have been posted before, in one of the 258972 posts :-)

Found one in my collection of stuff:

Code: Select all

function waitKey() as string
	dim as string key
	do
		key = inkey
		sleep 1
	loop while key = ""
	return key
end function

function getInput(labelStr as string, preStr as string, row as integer, col as integer) as string
	dim as string key, retStr = preStr
	dim as integer colCursor = col + len(labelStr) + len(retStr)
	locate row, col
	print labelStr + retStr;
	while 1
		key = waitKey()
		select case key
		case chr(8) 'bakcspace
			if len(retStr) > 0 then
				retStr = left(retStr, len(retStr) - 1)
				locate row, colCursor - 1
				print " ";
				colCursor -= 1
			end if
		case chr(13) 'enter
			exit while
		case chr(27) 'secape
			retStr = ""
			exit while
		case chr(32) to chr(127) 'printable char
			retStr += key
			print key
			colCursor += 1
		end select
		locate row, colCursor
	wend
	return retStr
end function

dim as string retStr = "Street xyz"
do
	locate 8, 20: print "type 'exit' for exit, <escape> to clear" 
	retStr = getInput("Address: ", retStr, 10, 20)
	cls
	locate 12, 20: print retStr
loop until lcase(retStr) = "exit"
robert
Posts: 169
Joined: Aug 06, 2019 18:45

Re: Strange behavior of input and line input

Post by robert »

No problem here on x86-64 Ryzen running Linux Fedora 32.

Line input code example compiled with FreeBASIC 1.0.8 and run on bash terminal.

No delay.
badidea
Posts: 2586
Joined: May 24, 2007 22:10
Location: The Netherlands

Re: Strange behavior of input and line input

Post by badidea »

Done some more testing (on Ubuntu Mate 18.04).
The problems here occurs when I keep a button pressed (for several seconds) and then try other keys.
Tested with 4 different terminals:
* MATE terminal: Not good
* XFCE terminal: Not good
* byobu: Good (I cannot remember installing this one)
* xterm: Good (very smooth but also very tiny font)
Kyle
Posts: 4
Joined: May 18, 2020 21:09

Re: Strange behavior of input and line input

Post by Kyle »

OK, so it appears there is a bug of some sort with the implementations of Input and Line Input in some terminals, especially mate-terminal, which is the one I generally use. I tried byobu, but I was running it in mate-terminal, and eventually did see the problem there as well, although it did take longer to appear. Thanks to the handlers for key and line input shared above, I have adapted something that works for my testing, and can now exit the main loop without using control+c, although this was an added bonus. The main part I needed that I didn't have already was a way of correctly handling the backspace and escape cases. Thanks to @badidea for the code that filled in the missing pieces of this puzzle for me. I did notice that even my handlers did trip just a little, as an extra space was removed via backspace at one point ... it actually looks like the wrong character was removed at some point. But it looks like adding Sleep 1 did solve that problem. After adding that, the problem didn't appear again, and this test code runs really smoothly now. I may dig around in the fbc code to see if I can understand things well enough to know what exactly is happening. I'll report my findings in any case. Thanks very much for the help.
Kyle
Posts: 4
Joined: May 18, 2020 21:09

Re: Strange behavior of input and line input

Post by Kyle »

It seems the code that handles Input and Line Input is in rtlib/con_readline.c. I can understand pretty much what is supposed to be happening; it seems to be a simple line editor. It's doing a little more than what my implementation is doing, but not so much that it should be causing a problem like this, even on a slow terminal like mate-terminal. I have been able to trigger my issue 100% by placing

Code: Select all

fb_Delay( 500 );
inside of the main loop. It can go just about anywhere in the main loop and have the same effect, but I put it right below

Code: Select all

s = fb_Inkey( );
My problem now is that I can't find anything that should be causing the problem. The input seems to be blocking once the key buffer contains too many keys at once, from my tests, about 3 to 4 keys block it. This block causes the function to wait for a key press before adding the first key in the buffer into the input string. My guess is that it's not the fb_Inkey() function that causes this, as using the Inkey() function in an FB program doesn't cause this block. All I can say at this point is that the expected behavior is to keep processing input as it comes into the key buffer, rather than blocking or hanging if there is too much input at once. Unfortunately, I haven't yet found the code responsible for this, as the main loop in con_readline.c doesn't appear to be waiting for anything.
Kyle
Posts: 4
Joined: May 18, 2020 21:09

Re: Strange behavior of input and line input

Post by Kyle »

I can confirm that there is no block on FB's inkey() function. I added

Code: Select all

sleep 500, 1
to my implementation of a line input. I ended up with a key buffer with more than 15 keys stuck in it. Each character began appearing in half second intervals, exactly as expected, until the last character was processed, which was the new line character, which exited my function loop and correctly returned the input string. So there is a block or wait that is getting triggered somewhere in the Input and Line Input implementations, I just need to find it.
MrSwiss
Posts: 3910
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: Strange behavior of input and line input

Post by MrSwiss »

Kyle wrote:So there is a block or wait that is getting triggered somewhere in the Input and Line Input implementations, I just need to find it.
I don't agree with your conclusion (so far, at least).

The evidence supplied by testing different Terminal-implementations suggests clearly:
you seem to be concentrating on "the wrong place" because, the Terminal used, seems
to be the responsible "cause" and not the FB implementation.

Reason: if it was FB that causes the "issue", then that whould mean that "all" Terminals
whould be equally affected. Which is clearly NOT the case.
speedfixer
Posts: 606
Joined: Nov 28, 2012 1:27
Location: CA, USA moving to WA, USA
Contact:

Re: Strange behavior of input and line input

Post by speedfixer »

I think you are running into several problems at once.

It just isn't good practice to set up any loop without a sleep OR an expectation that the loop will exit very quickly. But that is not the problem you are observing. (Also, set a key trap test - example: chr(27) - escape - to terminate your loop.)

Line input will properly sit and wait for your input - and while waiting the system will continue running its own processes NOT under any control of yours. It will even decide your program can be swapped out while waiting. The system has several levels of buffers working, and being parked in a service loop too long lets the key into the systems buffer, but the line input routine was parked while the system was doing other stuff.
Key data sits in system buffer waiting while the event trigger was missed by line input. Each successive key after the missed events will release single keys on each new event trigger. Not a new problem, nor is it unique to FreeBASIC. Fortunately, there are multiple ways to get keys from the system.

While Line input is a nice display of how a computer can do work for you, it is really poor to use as a user key input function. The input data ALWAYS must be validated/confirmed if used in a real program.

To get consistent key input, you almost always have to write your own key capture loop. There are MANY examples in the forums from simple to complex. You need the system to *not* be held by a loop that doesn't release some time. If you don't, the system will either puppy paws up or take longer than expected doing its chores when it DOES get time. It makes the system look unpredictable and unreliable.

In the routine you decide to use, besides capturing and processing any keys you want, you have to be aware of key bounce and/or reading the key events too quickly. How much time required by your routine to process the data. Whether you want repeating keys or not. Raw or processed keys (caps/alts/function keys etc.) How and when to clear the input buffers/events. Threaded or non-threaded. These all make even a simple good key input routine an excellent learning exercise. And teaches respect for the really nice editors out there.

Not a bug.
Simple function, just not the best for user input.

david
Post Reply