[try Beta version]
Not logged in

 
unix C++ solution to getch() question

Feb 10, 2020 at 9:34pm
This post asks about the equivalent of getch() from <conio.h>.
http://www.cplusplus.com/forum/unices/264588/#msg1140069

As was mentioned in that thread (now archived), there's no portable way to do it that will work for windows and linux/unix. But it can be done for any recent linux. This might work on mac's too, depending on the availability of cfmakeraw

The underlying problem is that C++ doesn't know anything about the underlying OS. If we want to change the way the OS feeds us input, we have to tell it. Thus there's no portable way to do this.

file rawterm.h:
1
2
3
4
5
6
7
8
9
#include <termios.h>

class rawTerm
{
    termios initState; // the intial state of the terminal
public:
    rawTerm();
    ~rawTerm();
};


file rawterm.cpp:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <fcntl.h>
#include <termios.h>

#include "rawterm.h"


rawTerm:: rawTerm() {
    tcgetattr(0, &initState); // get term attrributes on fd 0 (cin/stdin)
    termios workios = initState;  // make a copy to work with;
    cfmakeraw(&workios);      // set flags to put term in 'raw' mode
    tcsetattr(0, TCSANOW, &workios);  // tell the OS to put change the term attributes
}

rawTerm::~rawTerm() {
    // put the term back into 'cooked mode
    tcsetattr(0, TCSANOW, &initState);
}



example of use:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
#include <cctype>
#include "rawterm.h"

void getinput()
{
    rawTerm rt;
    char ch;
    while( (ch = std::cin.get()) != 'q' ) {
        std::cout << static_cast<char>(toupper(ch)) << std::flush;
    }
}

int main()
{
    getinput();
    std::cout << std::endl;
}


cfmakeraw() sets the terminal into raw mode: no echo, no line buffering, and turns off processing of control chars.
Last edited on Feb 10, 2020 at 9:54pm
Feb 12, 2020 at 7:40pm
Actually Some macros are supplied I’m pretty sure...

You can put the function def in a .h file with the .cpp have a bunch of preprocessor checks.

I remember I found this somewhere, I forget exactly how, but it should work maybe take it for a spin.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

#ifndef PORTABLE_H
#define PORTABLE_H


#if defined(unix) || defined(__unix__) || defined(__unix)
#define typeCheck

// Unix code
    
#endif
  
#ifndef typeCheck 
#ifdef __linux__
    
 // Linux code
    
#endif
#endif
  
#ifndef typeCheck
#ifdef _WIN32
#define typeCheck
    
// windows code
    
#endif
#endif

#endif 
Feb 21, 2020 at 8:55pm
I think you can do a getch with just a couple of lines of assembly, and its gonna be non portable anyway, may as well make it that way without all the hoops.
Feb 22, 2020 at 8:14am
You need to test if the input stream has anything to read. You can do that with select().
Topic archived. No new replies allowed.