开发者

Getting raw input from console using C or C++

开发者 https://www.devze.com 2023-03-20 14:49 出处:网络
/* Initialize new terminal i/o settings */ static struct termios old, new1; void initTermios(int echo) {
/* Initialize new terminal i/o settings */
static struct termios old, new1;
void initTermios(int echo) {
    tcgetattr(0, &old); /* grab old terminal i/o settings */
    new1 = old; /* make new settings same as old settings */
开发者_运维百科    new1.c_lflag &= ~ICANON; /* disable buffered i/o */
    new1.c_lflag &= echo ? ECHO : ~ECHO; /* set echo mode */
    tcsetattr(0, TCSANOW, &new1); /* use these new terminal i/o settings now */
}

/* Restore old terminal i/o settings */
void resetTermios(void) {
    tcsetattr(0, TCSANOW, &old);
}

How can I get arrow key as input (possibly as a single character), the current code works good for all other things I need... Please no solution with ncurses


There is a great tutorial about writing text editors for Unix terminals, with raw input, syntax coloring etc., which uses only the standard C library and standard headers available on Unix-like systems:

https://viewsourcecode.org/snaptoken/kilo/02.enteringRawMode.html

This chapter of the tutorial explains how to switch the terminal input to raw mode and process it with standard IO functions from C (read() & stuff). Then you can handle things like cursor movement, scrolling, colours etc. by writing to the output with certain escape sequences of the VT100 terminal. You can find more in this tutorial, including the links to all the documentations required, and sample source codes. There's also a GitHub repository with all the samples from the tutorial, as well as the final product, which is based on the Kilo editor written by antirez.

As for reading the special keys, like the arrow keys, Home ,End, PgUp, PgDown etc., try outputting the raw characters you get from the input and just press the keys you want to see what codes they map to. For the arrow keys, for example, they usually map to the escape sequences <ESC>[A through <ESC>[D, where <ESC> is the special control character with ASCII code 27 decimal or 0x1B hexadecimal. Those are the VT100 terminal escape codes that instruct the terminal to move the cursor one character into one of these four directions. More on handling these keystrokes in the next chapter of the aforementioned tutorial:

https://viewsourcecode.org/snaptoken/kilo/03.rawInputAndOutput.html


Have you tried the read function?

This works for me with cygwin g++, don't have linux handy to test:

#include <unistd.h>
#include <termios.h>
#include <stdio.h>

/* Initialize new terminal i/o settings */
static struct termios old, new1;
void initTermios(int echo) {
    tcgetattr(0, &old); /* grab old terminal i/o settings */
    new1 = old; /* make new settings same as old settings */
    new1.c_lflag &= ~ICANON; /* disable buffered i/o */
    new1.c_lflag &= echo ? ECHO : ~ECHO; /* set echo mode */
    tcsetattr(0, TCSANOW, &new1); /* use these new terminal i/o settings now */
}

/* Restore old terminal i/o settings */
void resetTermios(void) {
    tcsetattr(0, TCSANOW, &old);
}

int main(void)
{
    char c;
    initTermios(0);
    while (1) { read(0, &c, 1); printf("%d\n", c); }
}

As @Fiktik noted, the echo setup is broken, but I'm using the code in the question without changes.


You can't do this in standard C++/C, you need the nonstandard conio.h file and the getch() extension. Then you can call getch() twice to get the key code for the arrows

#include <conio.h>
using namespace std;

int main() 
{
    cout << "press up arrow;" << endl;
    int control = getch(); //gets the escape character
    int keycode = getch(); //gets the code
    cout << control << endl; 
    cout << keycode << endl;
}


As a single character this is not possible (the input is a sequence of characters). What you can do is make it look like a single character by implementing your own input function. Something like:

struct key_data {
   enum key_type kt; /* ARROW, FUNCTION, REGULAR, etc */
   unsigned char key; /* depends on kt */
};

int get_key_press (struct key_data * kd) {
   int c = getc(stdin);
   switch (c) {
      /*
        If c is a control character, process further characters to see what needs to happen
       */
   }
   return 0;
}

/* later, in main */
   struct key_data kd;
   get_key_press (&kd);
   if (kd.kt == ARROW_KEY) {
      switch (kd.key) {
         case ARROW_RIGHT: 
            printf("Right Arrow Pressed\n");
            break;
         /* and so on */

So after implementing that you can use get_key_press to act like it is getting a single character.

Although, this work is already done for you elsewhere; why the aversion to ncurses?

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号