C in 2048,problems with moving [duplicate] - c

This question already has answers here:
How to avoid pressing Enter with getchar() for reading a single character only?
(14 answers)
Closed 5 years ago.
I am making 2048 game in C and I need help. Moves are made by pressing W,A,S,D keys e.g. W is for moving up, S for down.
However, after every letter you have to press enter to accept it. How can I make it work without pressing enter?

There is no standard library function in c to accomplish this; instead you will have to use termios functions to gain control over the terminal and then reset it back after reading the input.
I came across some code to read input from stdin without waiting for a delimiter here.
If you are on linux and using a standard c compiler then getch() will not be easily available for you. Hence i have implemented the code in the link and you just need to paste this code and use the getch() function normally.
#include <termios.h>
#include <stdio.h>
static struct termios old, new;
/* Initialize new terminal i/o settings */
void initTermios(int echo)
{
tcgetattr(0, &old); /* grab old terminal i/o settings */
new = old; /* make new settings same as old settings */
new.c_lflag &= ~ICANON; /* disable buffered i/o */
new.c_lflag &= echo ? ECHO : ~ECHO; /* set echo mode */
tcsetattr(0, TCSANOW, &new); /* use these new terminal i/o settings now */
}
/* Restore old terminal i/o settings */
void resetTermios(void)
{
tcsetattr(0, TCSANOW, &old);
}
/* Read 1 character - echo defines echo mode */
char getch_(int echo)
{
char ch;
initTermios(echo);
ch = getchar();
resetTermios();
return ch;
}
/* Read 1 character without echo */
char getch(void)
{
return getch_(0);
}
int main()
{
int ch;
ch = getch();//just use this wherever you want to take the input
printf("%d", ch);
return 0;
}

what you are asking for is function named kbhit() which returns true if user presses a key on the keyboard. you can use this function to get input from the use too like see
char c= ' ';
while(1){
if(kbhit())
c=getch();
if(c=='q')// condition to stop the infinite loop
break;
}

Related

Implementing a KeyPress Event in C

I have a infinite loop like the following one, and within this loop, I want to continuously check the keyboard to see if the escape key (ESC) has been pressed or not. If it is pressed, then the loop should be broken. How I can do this in C? (I am using gcc, and do access to pthreads as well in case this must be done via threads)
while(1){
//do something
//check for the ESC key
}
This is heavily system dependent. In Unix/Linux systems, the default terminal handler gathers lines and only notifies the program when a full line is available (after Enter is hit.) If you instead want keystrokes immediately, you need to put the terminal into non-canonical mode:
#include <termios.h>
struct termios info;
tcgetattr(0, &info); /* get current terminal attirbutes; 0 is the file descriptor for stdin */
info.c_lflag &= ~ICANON; /* disable canonical mode */
info.c_cc[VMIN] = 1; /* wait until at least one keystroke available */
info.c_cc[VTIME] = 0; /* no timeout */
tcsetattr(0, TCSANOW, &info); /* set immediately */
Once you've done that, you can use any calls that read from stdin and they will return keys without waiting for the end of the line. You can in addition set c_cc[VMIN] = 0 to cause it to not wait for keystrokes at all when you read from stdin.
If, however, you're reading stdin with stdio FILE related calls (getchar, etc), setting VMIN = 0 will make it think you've reached EOF whenever there are no keys available, so you'll have to call clearerr after that happens to try to read more characters. You can use a loop like:
int ch;
while((ch = getchar()) != 27 /* ascii ESC */) {
if (ch < 0) {
if (ferror(stdin)) { /* there was an error... */ }
clearerr(stdin);
/* do other stuff */
} else {
/* some key OTHER than ESC was hit, do something about it? */
}
}
After you're done, you probably want to be sure to set the terminal back into canonical mode, lest other programs (such as your shell) get confused:
tcgetattr(0, &info);
info.c_lflag |= ICANON;
tcsetattr(0, TCSANOW, &info);
There are also other things you can do with tcsetattr -- see then manual page for details. One thing that might suffice for your purposes is setting an alternative EOL character.
If the main job you're doing can be placed within this main loop, you could go for using STDIN in non-blocking mode. You still have a problem with the terminal which does line-buffering normally. You shall put the terminal to raw mode as well.
What about using Ctrl-C (interrupt)?
Non-blocking means that the read() system call always returns immediately even if there are no new bytes in the file. On Linux/Unix you can make STDIN nonblocking this way:
#include <unistd.h>
#include <fcntl.h>
fcntl(0, F_SETFL, O_NONBLOCK); /* 0 is the stdin file decriptor */
This is what you want:
#include <stdio.h>
#include <conio.h>
void main() {
int c;
while((c = getch()) != EOF )
if(c == 27) break;
/* 27 is the ASCII code for Esc */
}

Reading a Stop Signal within a loop

I am using a while loop which doesnt terminate, for reproducing Tail command of unix using C code. I need a way to stop the loop apart from Ctrl + C which quits the process i believe. Is there any way to read Keyboard commands when used within the code ? The problem with using getchar() is that it stops the loop from running until a char is entered. Is there any alternative solution to this issue ?
You need to turn off blocking and line buffering. Turn off blocking so getc() returns right away. It will return -1 until it has a real character. Turn off line buffering so the OS sends the char right away instead of buffering it up until it has a full line which occurs when you press return.
#include <unistd.h> /* UNIX standard function definitions */
#include <fcntl.h> /* File control definitions */
#include <termios.h> /* POSIX terminal control definitions */
int main(void) {
// Turn off blocking
fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK);
struct termios options, oldoptions;
tcgetattr(STDIN_FILENO, &options);
// Disable line buffering
options.c_lflag &= ~( ICANON);
// Set the new options for the port...
tcsetattr(STDIN_FILENO, TCSANOW, &options);
while(1) {
char c = getc(stdin);
if(c != -1) break;
}
// Make sure you restore the options otherwise you terminal will be messed up when you exit
tcsetattr(STDIN_FILENO, TCSANOW, &oldoptions);
return 0;
}
I agree with the other posters that you should use signals, but this is the answer to what you asked.
This sounds very much like this question from the comp.lang.c FAQ.
Q: How can I read a single character from the keyboard without waiting for the RETURN key? How can I stop characters from being echoed on the screen as they're typed?

Capturing input without \n

I am making a simple 2d game in the terminal, and I have been wondering how I could get stdin without having to return. So, instead of the user having to press w\n (\n for return), they would just press 'w' and it would go forwards.
scanf, gets, and getchar cannot do this, but I have seen it be done before in programs such as Vi. How would I achieve this?
You need to set your terminal to non-canonical mode. You can use functions like tcsetattr, and tcgetattr to set and get terminal attributes. Here is a trivial example:
int main(int argc, const char *argv[])
{
struct termios old, new;
if (tcgetattr(fileno(stdin), &old) != 0) // get terminal attributes
return 1;
new = old;
new.c_lflag &= ~ICANON; // turn off canonical bit.
if (tcsetattr(fileno(stdin), TCSAFLUSH, &new) != 0) // set terminal attributes
return 1;
// at this point, you can read terminal without user needing to
// press return
tcsetattr(fileno(stdin), TCSAFLUSH, &old); // restore terminal when you are done.
return 0;
}
For more info about these functions, see glibc documentation. Especially this part.

getchar and putchar

My C code:
int c;
c = getchar();
while (c != EOF) {
putchar(c);
c = getchar();
}
Why does this program react like this on inputting hello?
hello
hello
and not like:
hheelloo
Your input is hello and not h e l l o right?
So the input you give is buffered until you press enter.
When you type, a console grabs the output from the keyboard, echoing it back to you.
getchar() operates on an input stream, which is typically configured with "Canonical input" turned on. Such a configuration reduces the CPU time spend polling the input for a buffering scheme where the input is buffered, until certain events occur which signal the buffer to expand. Pressing the enter key (and hitting control D) both tend to flush that buffer.
#include <unistd.h>
int main(void){
int c;
static struct termios oldt;
static struct termios newt;
/* Fetch the old io attributes */
tcgetattr( STDIN_FILENO, &oldt);
/* copy the attributes (to permit restoration) */
newt = oldt;
/* Toggle canonical mode */
newt.c_lflag &= ~(ICANON);
/* apply the new attributes with canonical mode off */
tcsetattr( STDIN_FILENO, TCSANOW, &newt);
/* echo output */
while((c=getchar()) != EOF) {
putchar(c);
fflush(STDOUT_FILENO);
}
/* restore the old io attributes */
tcsetattr( STDIN_FILENO, TCSANOW, &oldt);
return 0;
}
Your terminal probably only writes your input to stdin when you press enter. Try typing something, backspace and write something else; if you don't see the originally typed characters, it means that your terminal was waiting for you to compose the line before sending the data to the program.
If you want raw terminal access (e.g. react to key-down and key-up), you should try some terminal library like ncurses.
Because the default for stdin when it refers to the keyboard is to be line buffered.
That means you only get to see full lines, and not single characters.
Imagine you ask a friend of yours what his phone number is ... but he must write it down on a piece of paper. You don't get the number digit-by-digit as he writes them: you get all of the number when he gives you the piece of paper :)
The standard input/output streams can be buffered which means your input may not be echo'd to the screen until a whitespace character (for example) is encountered.
getchar reads the input from input stream which is available only after ENTER key is pressed. till then you see only the echoed result from the console To achieve the result you want you could use something like this
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
int getCHAR( ) {
struct termios oldt,
newt;
int ch;
tcgetattr( STDIN_FILENO, &oldt );
newt = oldt;
newt.c_lflag &= ~( ICANON | ECHO );
tcsetattr( STDIN_FILENO, TCSANOW, &newt );
ch = getchar();
putchar(ch);
tcsetattr( STDIN_FILENO, TCSANOW, &oldt );
return ch;
}
void main() {
int c;
c = getCHAR();
while (c != 'b') {
putchar(c);
c = getCHAR();
}
}

I'm trying to use getche() in linux over gcc on the terminal

I need to know how to compile a program in C with the getche() function, but isn't compilling because it needs a reference. Some one know what reference is missing?
im using this comand:
gcc filename.c -o exec
For Linux and other Unix platforms you probably want to be using ncurses instead of just trying to emulate getch[e]. It's a slightly more involved API but it'll take care of all kinds of gotchas for you, which the simple emulation Dan D. posted won't. (For instance, it does the Right Thing if the user types ^C or ^Z.)
From http://wesley.vidiqatch.org/code-snippets/alternative-for-getch-and-getche-on-linux/
/*
getch() and getche() functionality for UNIX,
based on termios (terminal handling functions)
This code snippet was written by Wesley Stessens (wesley#ubuntu.com)
It is released in the Public Domain.
*/
#include <termios.h>
#include <stdio.h>
static struct termios old, new;
/* Initialize new terminal i/o settings */
void initTermios(int echo) {
tcgetattr(0, &old); /* grab old terminal i/o settings */
new = old; /* make new settings same as old settings */
new.c_lflag &= ~ICANON; /* disable buffered i/o */
new.c_lflag &= echo ? ECHO : ~ECHO; /* set echo mode */
tcsetattr(0, TCSANOW, &new); /* use these new terminal i/o settings now */
}
/* Restore old terminal i/o settings */
void resetTermios(void) {
tcsetattr(0, TCSANOW, &old);
}
/* Read 1 character - echo defines echo mode */
char getch_(int echo) {
char ch;
initTermios(echo);
ch = getchar();
resetTermios();
return ch;
}
/* Read 1 character without echo */
char getch(void) {
return getch_(0);
}
/* Read 1 character with echo */
char getche(void) {
return getch_(1);
}
/* Let's test it out */
int main(void) {
char c;
printf("(getche example) please type a letter: ");
c = getche();
printf("\nYou typed: %c\n", c);
printf("(getch example) please type a letter...");
c = getch();
printf("\nYou typed: %c\n", c);
return 0;
}

Resources