Window bottom
Some applications like vim, mutt, aptitude contain
a top window section for output and
a bottom section for the user to type in or for status display.
(Suppose there is one child process to output and another one to take user input. The purpose is to allow for updated output at the same time as you are typing the input or viewing the status.)
Actions Undo Package Resolver Search Options Views Help
C-T: Menu ?: Help q: Quit u: Update g: Download/Install/Remove Pkgs
|
|
|
|
|
┌─────────────┐ |
│Loading cache│ |
└─────────────┘ |
|
|
|
|
|
|
|
--------------------------------------------------------------------------- |
Initialising package states 100% |
+-------------------------------------------------------+
| some output here |
| |
| |
| |
| |
| |
|-------------------------------------------------------+
|:input here |
+-------------------------------------------------------+
Ncurses tutorial does not mention this to be obviously possible.
A query on "c print to {window,screen,terminal,console} bottom" at StackOverflow or at a web search engine isn't helpful.
Can this be done in C programmatically?
Discarding input
While some of the solutions below can move character to a given position, there is the problem that it may be needed to discard user input rather than leaving it on screen. Like in vim's case, typing ":w" and pressing Enter does not leave a ":w" on the screen.
Update. This is found here: How to delete text after getstr() c++ ncurses
Window focus - the UNSOLVED PART OF THE PROBLEM
While you are typing the input at window bottom and the text at the top changes, we see the problem of moving the focus back to the bottom. This is absent in the solutions as of December 29.
Update 1. Just attempting to
remember the previous cursor position, then
display the output, and then
restore the position
is not an easy solution: as these are different processes, attempts to retrieve cursor position don't affect the changes that happened during the other process execution.
Eg if parent takes input then the child doesn't know how the cursor position changed and can't restore the cursor position after performing a line of output at another part of the console.
Implementing this would involve some inter process communication and if there are other solutions they could be preferable.
Related
Get Input from keyboard without waiting for input Related, but not specific enough.
How to make a chat like UI using Python Urwid? Urwid for Python which does the job (per J.F. Sebastian in the comment below). Unfortunately not in C.
Using the standard libraries, there's no way to do that; using ncurses, as you already suggest, it is easily possible; I think this tutorial explains it quite nicely.
Using ANSI escape sequence it's possible to control the position of the cursor:
void gotoxy(int x, int y) {
printf("\033[%d;%dH",x,y);
}
So once you figure out the terminal height and width then you can use that function to position the cursor wherever you like and print stuff.
This answer suggests a slightly different approach, but it avoids a lot of complication you'd introduce by using the current method. I hope it is possible to implement these simplifications.
Use termio to turn off canonical mode.
Sample code (here) will show you exactly how to set up such an input loop. This sample 'polls-and-sleeps' which could mean a delay unless you reduce the sleep. Also I think you can use termio to set a timeout (wait a second and return 'no input' or give me the input NOW if it comes earlier). But if you are really going to monitor another process, polling might be the more flexible option.. You can really poll 30x a second and live with the .00001% processor hit it is going to cause, but you will love the simplicity and bug prevention it gives.
Avoid multiple threads and processes like the plague
You don't need to use 2 processes/threads if the only problem you are trying to solve is the fact that getch() blocks. That would be required if it were impossible to prevent the input functions from blocking. 'Canonical' (rules based) means all sorts of handy 'rules' are in effect, like, 'don't give the input to the program until ENTER is hit'. For a full screen console app you want to turn off all the rules and do everything yourself.
Put the main thread in charge of the window...
... Then you can just use the ansi escape csi codes to position the cursor back to where you want it. Caveat: you can't write to the lower-right box in the screen. Everything will scroll.
There is an annoying thing in MS windows programming where only the thread that creates a window can safely update it. There is actually a reason for this. Whether you're talking console, or windowing system. sooner or later, if you have multiple threads/processing hitting one output device, you'll interrupt an escape sequence (or have to make extra code to manage this which is a bad thing), be fighting for the output 'port', etc. you need one thread to manage the output.
if you really care about what some other thread or process is doing, just check it in your main console management loop. For example of you have another process that you just want to report its progress, start it from your program and capture its stdouput and look at that; another thread, just lock something shared you can check in your polling routine. Heck if it's just a byte and it's only used for statuses, don't even lock the damn thing. You can throw in a couple of GOTO's too, just to show your individuality :-)
caveat I don't know that ncurses would play well with you if you are manually messing with termio? I would guess it wants to do that itself. Never tried mixing. If your app is simple you could go it alone without the help, especially if you can wrestle ncurses into doing what you want. I'm no expert on those apps you mention but I'd bet they are micromanaging everything.
I had a similar issue a few weeks ago while writing an IRC client that runs in the terminal. I wrote it using the Windows conio library, but I'm fairly sure this should be applicable to curses. The idea is that console output is handled by a single thread, and console input is handled in a separate thread. Basically, all you need is a loop that pushes the return of getch() onto a mutexed FIFO that runs for the duration of the program. In the display thread, you can pop the keypresses off the FIFO and handle them however you like. You can't use a standard function like fgets(), but it's a very solid solution to your problem. I can provide the full (messy) source on request.
Edit: alright, well here's the relevant code from the FIFO pushing:
bool keyqueuewriting = false;
std::deque<int> keyqueue;
void grabkey( void* in )
{
int t;
while( true ){
t = getch();
#ifdef _WIN32
if( t == 224 || t == 0 )
{
t += getch() << 8;
}
#else
int off = 8;
if( t == 27 ){
int e = getch();
t += e << off;
off += 8;
while( e ==91 || (e >= '0' && e <= '9') || e == ';' )
{
e = getch();
t += e << off;
off += 8;
}
}
#endif
while( keyqueuewriting ){}
keyqueuewriting = true;
keyqueue.push_back( t );
keyqueuewriting = false;
}
}
And Handling:
while( keyqueuewriting ){}
keyqueuewriting = true;
while( keyqueue.size() > 0 )
{
shouldsleep = false;
int t = keyqueue.front();
keyqueue.pop_front();
switch( t )
{
case K_BACKSPACE:
if( pos > 0 ){
for( int i = pos-1; input[i] != 0; i++ ){input[i] = input[i+1];}
movecursorback( 1 );
pos -= 1;
} break;
case K_LEFT: if( pos > 0 ){ movecursorback( 1 ); pos -= 1; } break;
case K_RIGHT: if( input[pos] != 0 ) {movecursorforward( 1 ); pos += 1;} break;
case K_HOME: { gotoxy(0,SCREENHIG-1); pos = 0; } break;
case K_END: { int a = strlen( input ); /*gotoxy( 79,39 );*/ pos = a;} break;
case 3: exit(3); break;
default: if( t >= 0x20 && t < 0x80 ){
int a = strlen( input );
if( a > 998 )
a = 998;
int deadcode = 1;
input[999] = 0;
for( int i = a+1; i > pos; i-- ){input[i] = input[i-1];}
input[ pos ] = t;
movecursorforward( 1 );
pos++;
} break;
}
change = bufpos[curroom] - bufprev;
if( pos > 998 ) pos = 998;
if( pos - mescroll < 1 ) {mescroll += (pos-mescroll-1); gotoxy( pos-mescroll, SCREENHIG-1 );}
if( pos - mescroll > 78 ) {mescroll += (pos-mescroll-78); gotoxy( pos-mescroll, SCREENHIG-1 );}
if( mescroll < 0 ) {mescroll = 0; gotoxy( 0, SCREENHIG-1 ); }
savexy();
gotoxy( 0, SCREENHIG-1 );
char y = (input+mescroll)[79];
(input+mescroll)[79] = 0;
printf( "%s ", input+mescroll );
(input+mescroll)[79] = y;
returntosaved();
change2 = change;
bufprev = bufpos[curroom];
}
keyqueuewriting = false;
Yes, it uses std::deque. That should be the only C++ specific thing though. Just replace it with a C compatible FIFO.
The entire client can be found here.
Yes, it DOES compile in Linux, but it doesn't work. I never bothered to figure out how ncurses should be used before I started work on it.
Related
So i'm very much a beginner and this is an assignment for class, but i'm not looking to have someone do the assignment for me or anything. Just help on a part i'm having trouble with.
I'm not posting my code as it's an ongoing assignment and I don't want someone to happen upon it and copy it ): But the gist of it is I need to display a menu to the user and create a switch statement. Each case has a corresponding function prototype that executes the choice the user made from the menu.
1 Enter 3 grades
2 Show average (with 3 grades) and letter grade
3 Show highest grade
4 Show lowest grade
5 Exit
I've done pretty much all of the assignment, but the one requirement I can't figure out is how to initialize the 3 grade variables to random numbers between 50 and 100, so if the user chooses menu options 2 3 or 4 first then those random #'s are what is used in my prototypes. But if the user chooses menu option 1, my functions should use the 3 values input by the user from that point until exit, or if they hit 1 again to input new values.
Since I couldnt figure it out I just had each prototype prompt the user to insert 3 grades then proceed to do its assigned task using those values.
We were also instructed to not use arrays as we havent gotten to that yet.
If no one is able to figure it out without seeing the code i'll wait until after the due date and post what I was able to do. i'm honestly just wanting to learn and my professor doesn't really post any videos or lectures (online class) so we just go off our textbook and good ol google.
Thank you to whoever can help(:
If you want a variable with a random standard value, initialize it with a random value. You can generate a random integer between two numbers using the random() function in the stdlib.h header.
Your code can be structured like this.
#include<stdlib.h>
#include<time.h>
int random_range(int start, int end) {
return start + (int) ((double) random() / RAND_MAX * (end - start));
}
int main() {
srandom(time());
int grade1 = random_range(50, 100);
int grade2 = random_range(50, 100);
int grade3 = random_range(50, 100);
...
}
Now the three grade variables are always initialized and can be used. I recommend, you also read the man page for the random() function.
Not a good idea, doing processing with some randomly assigned data simply to not do the work of controlling the user's options. Imagine that one option is to write the current record into persistent storage. Do you want to risk random valued records polluting the company's database? There are stories of "test versions" that have been released "into the wild" (on the day the coder was home with a cold, but management applied pressure to ship) that... well, that would curl your toes.
Here is a sketch whereby the user has two options only: enter the data or quit the program. Presuming valid data has been accepted, the menu features more options.
Do not process junk. It'll come back to bite you.
/* Usual header files */
int main() {
char buf[ 64 ];
int hiMenuOpt = 1;
do {
printf(
"Here's menu options\n"
"0: Quit\n"
"1: Enter data\n"
);
if( hiMenuOpt > 1 )
printf(
"2: Something\n"
"3: Something else\n"
"4: Something other\n"
);
printf( "Select 0-%d : ", hiMenuOpt );
fgets( buf, sizeof buf, stdin );
int val = strtol( buf, NULL, 10 ); // Edit fix. Thanks to Lundin
if( val < 0 || hiMenuOpt < val ) {
printf( "Bad entry\n" );
continue;
}
switch( val ) {
case 0:
hiMenuOpt = 0;
break;
case 1:
puts( "Hi from one\n" );
/* yadda yadda */
hiMenuOpt = 4;
break;
/* More stuff */
}
} while( hiMenuOpt );
return 0;
}
Here's menu options
0: Quit
1: Enter data
Select 0-1 : 1
Hi from one
Here's menu options
0: Quit
1: Enter data
2: Something
3: Something else
4: Something other
Select 0-4 :
Notice that Quit is now item 0. New menu items may be added, and old ones removed. The only constant is exiting the program. It makes sense, imo, to make that the first item on the list.
I'm making an ASCII art game in c (windows), but for some reason when i play it is all flickering at apparently random intervals, and for most of the time i can't see anything. can anyone explain why or how to solve it?
this is my code:
const int WIDTH = 20, HEIGTH = 5;
const int AREA = (WIDTH) * HEIGTH;
const int gl = HEIGTH - 2; //Ground level
const float delta = 0.1f; //Frame rate
char scr[AREA]; //String for displaying stuff
char input;
int posx = 10, posy = gl - 1; //Player position
int vel = 0; //player velocity
while(1)
{
//TODO: player input
for(i = 0; i < AREA; i++) //Rendering part
{
if(i % WIDTH == 0 && i != 0)
{
scr[i] = '\n';
continue;
}
if(floor(i / WIDTH) >= gl) //i is on ground
{
scr[i] = '.';
continue;
}
scr[i] = ' ';
}
//Set player position
scr[posy * WIDTH + posx + 1] = '#';
scr[(posy + 1) * WIDTH + posx + 1] = '#';
system("cls");// Clear terminal
printf(scr);// Print screen
usleep(delta * 1000);//Sleep
}
output:
#
..........#........
...................►↓#
It works, but it flickers...
One possible reason for your problem is that there may be output waiting in the output buffer when you call your sleep function usleep. In that case, you should always flush all output before sleeping, by calling the function fflush( stdout );.
Also, using system("cls"); is highly inefficient. It is generally better to use the Console Functions API, or, if you are targetting platforms with Windows 10 or later, you can also use Console Virtual Terminal Sequences instead.
If you decide to use the Console Functions API, then the main functions that you will be needing in order to replace system("cls"); are GetStdHandle to obtain the output handle, and SetConsoleCursorPosition. That way, you won't have to clear the whole screen, but will only have to overwrite the parts of the screen that are changing. I also recommend that you replace printf with WriteConsole, otherwise you may run into buffering issues.
If this does not solve your flickering problem, then there also is the possibility of using double-buffering. Both the Console Functions API and Console Virtual Terminal Sequences support this.
When using the Console Functions API, you can use the function CreateConsoleScreenBuffer to create a new buffer to write to, without it being displayed immediately. This will allow you to first finish building the next screen, without any flickering occuring while doing so (because it is not being displayed yet). Once you have finished building the next screen, you can display it using the function SetConsoleActiveScreenBuffer.
Console Virtual Terminal Sequences offer similar functionality by supporting an alternate screen buffer.
Update my code
So i am working on a 2d game in c, now i am using threads to do different stuff in the same time, to move the player, cars etc.
But somehow i don't get it how can i move my player just one step, i know that the problem lays in my global variable movement. But can figure it how to do it the right way. So i hope someone can help me.
The code is huge so i will not passt all of it but the parts that are interesting for the player movement.
void moveFroggy() {
// froggy.y = SCREEN_HEIGHT - OUTER_BORDER;
if((movement == 'a') && (froggy.x > OUTER_BORDER))
froggy.x--;
if((movement == 'd') && (froggy.x < (SCREEN_WIDTH - OUTER_BORDER)))
froggy.x++;
if ((movement == 'w') && (froggy.y >= (SCREEN_HEIGHT - NUM_LANES - OUTER_BORDER - GRASS_BORDER)))
froggy.y--;
if ((movement == 's') && (froggy.y < (SCREEN_HEIGHT - OUTER_BORDER)))
froggy.y++;
if(movement == 'q')
quit = 1;
if(froggy.y <= (SCREEN_HEIGHT - NUM_LANES - OUTER_BORDER - GRASS_BORDER))
player_won = 1;
movement = '0';
}
Now inside the main we have a while loop that runs all the time, till the player complete the game or quit it.
pthread_create(&input_t, NULL, input_runner, NULL);
while(!quit && !error && !player_lost && !player_won) {
moveFroggy();
moveCarsOnMotorway();
startCar((SCREEN_WIDTH - OUTER_BORDER));
drawScreen();
usleep(GAME_SPEED);
}
pthread_join(input_t, NULL);
So my input_t thread is calling the input_runner function inside that function i get the user input.
void *input_runner(void* arg) {
char input;
if(!player_lost || !player_won){
while((input = getchar()) != EOF){
movement = input;
}
}
pthread_exit(0);
}
Just to know movement is a global variable so i can use it for moveFroggy function. but that is the problem to because it stores "w" and it just repeat itself till the user hit any other command. But it should move the player just one step ahead, so how can i reset the value and how to do proper clean up for threads if one is needed.
I am new in using thread,
Well, it seems the simple way to only move one step would be, at the bottom of moveFroggy() to clear movement value.
As an aside, it looks like you're creating an input-processing thread on every iteration of your game loop; is that really what you intend? If you want an input-processing thread, why not have it run its own loop to constantly read input until the game is over?
I'm also not sure of this overall multithreading strategy, but perhaps it will work for you...
This is not a good use of threads, and will be prone to synchronization errors.
Variables that are accessed by multiple threads must be protected by a mutex or accessed using atomic methods. Failing to do so will result in unpredictable behavior.
In any case, you don't need threads for this. If you want to read from the keyboard without blocking, there are a number of ways of doing that, including:
If on Linux, use the ncurses library, which natively provides non-blocking keyboard input through getch().
If on Windows, use kbhit().
Use fcntl() with F_SETFL to set standard input as non-blocking.
Use select() or poll() to check for input before trying to read.
Avoid the console entirely, and use a graphics library such as SDL.
Hey all I've asked this question a few times in the past few days but I just don't get it...I basically want to have the while loop for the Beep command executed in the background while the user can interact with the available case statements (only one shown..there are others)....i keep getting blocked and everytime i want the beep to make a sound constantly i block the rest of my program...I have to use Beep so please don't suggest any other functionality..
here's a sample code...
while( keypress != 'q' || keypress != 'Q')
{
x = Beep(x);
while (x == 1)
Beep(350,300);
alarm_t current;
keypress = _getch();
switch(keypress){
case 'h':
sprintf_s(current.message,"high alarm");
current.timeOfEvent = time(NULL);
recordEvent(current);
break;
Now...my issue is with the while loop and the Beep command....here is what i call to Beep(x)
int Beep(int y)
{
return y;
}
So basically i am trying to call a function outside of my current cpp file to just compare x and y, and return y as being equivalent to x...i thought this might avoid blocking but it doesn't...
Your while loop around beep just won't work and _getch is blocking. So it will just block until there's a character.
Depending what platform you are on, you need something like kbhit (and if you google that you will find alternatives for other platforms). ie it's not standard C functionality and platform specific.
kbhit will return true or false depending if there is a character or not.
So you can do:
while(!key_is_quit(ch))
{
Beep();
if(kbhit())
{
ch = getch();
// switch....
}
}
have wrote this app which reads input from console.
for(; ; )
{
GetNumberOfConsoleInputEvents(stdinInput, &numEvents);
if (numEvents != 0) {
INPUT_RECORD eventBuffer;
ReadConsoleInput(stdinInput, &eventBuffer, 1, &numEventsRead);
if (eventBuffer.EventType == KEY_EVENT) {
if(eventBuffer.Event.KeyEvent.bKeyDown)
{
printf("%c",eventBuffer.Event.KeyEvent.uChar.AsciiChar);
dataBuffer[bufferLen++] = eventBuffer.Event.KeyEvent.uChar.AsciiChar;
dataBuffer[bufferLen] = '\0';
if ( dataBuffer[bufferLen] == 99 || eventBuffer.Event.KeyEvent.uChar.AsciiChar == '\r' ) {
printf("User Wrote: %s\n",dataBuffer);
memset(dataBuffer,0,sizeof(dataBuffer));
bufferLen = 0;
}
}
}
}
}
It puts the data on a buffer and then it prints out the buffer. The problem occurs when im using Shift or CapsLock to write Capital letters or ! # # $ % characters. Then it prints out NOTHING.
Ive tried something with the VK_LSHIFT code but didn't worked.
Also if try to write something in other language than English it prints out something like this ▒├╞▒├╞▒├│▒├│ It cannot recognize the other language.
Can someone give me a hint on how to fix those problems ?
Thanks!
ReadConsoleInput returns events for each keystroke. For example, if you type SHIFT+A to get a capital A then you'll receive four key events: SHIFT down, A down, A up, SHIFT up.
The SHIFT key does not have a corresponding ASCII code so eventBuffer.Event.KeyEvent.uChar.AsciiChar is set to zero. This zero terminates the string you are building in dataBuffer so you don't see anything typed after the SHIFT key.
The simplest fix is to ignore any key event with an ASCII code of zero.
Additionally, if you want this to work well with foreign languages you might do better to use ReadConsoleInputW and eventBuffer.Event.KeyEvent.uChar.UnicodeChar. Better yet, compile it all as a Unicode app.