I'm trying to do a simple game (Pong) in C++. The game is a "Console-Game".
I've just write part of the code but now I found a trouble:
I create a _getch() and _kbhit() function
int _getch( ) {
struct termios oldt, newt;
int ch;
tcgetattr( STDIN_FILENO, &oldt );
newt = oldt;
newt.c_lflag &= ~( ICANON | ECHO );
tcsetattr( STDIN_FILENO, TCSANOW, &newt );
ch = getchar();
tcsetattr( STDIN_FILENO, TCSANOW, &oldt );
return ch;
}
int _kbhit() {
static const int STDIN = 0;
static bool initialized = false;
if (! initialized) {
termios term;
tcgetattr(STDIN, &term);
term.c_lflag &= ~ICANON;
tcsetattr(STDIN, TCSANOW, &term);
setbuf(stdin, NULL);
initialized = true;
}
int bytesWaiting;
ioctl(STDIN, FIONREAD, &bytesWaiting);
return bytesWaiting;
}
but when I press a key, that is printed on console. How I can prevent this?
My full code:
#include <iostream>
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <sys/select.h>
#include <stropts.h>
#include <sys/ioctl.h>
using namespace std;
void gotoxy(int x,int y){
printf("\x1b[%d;%df",y,x);
}
int _getch( ) {
struct termios oldt, newt;
int ch;
tcgetattr( STDIN_FILENO, &oldt );
newt = oldt;
newt.c_lflag &= ~( ICANON | ECHO );
tcsetattr( STDIN_FILENO, TCSANOW, &newt );
ch = getchar();
tcsetattr( STDIN_FILENO, TCSANOW, &oldt );
return ch;
}
int _kbhit() {
static const int STDIN = 0;
static bool initialized = false;
if (! initialized) {
// Use termios to turn off line buffering
termios term;
tcgetattr(STDIN, &term);
term.c_lflag &= ~ICANON;
tcsetattr(STDIN, TCSANOW, &term);
setbuf(stdin, NULL);
initialized = true;
}
int bytesWaiting;
ioctl(STDIN, FIONREAD, &bytesWaiting);
return bytesWaiting;
}
class Ball{
public:
};
class Game{
public:
void __init(){
this->pointL = 0;
this->pointR = 0;
}
void addScore(char side){
if(side == 'l') pointL++;
else if(side == 'r') pointR++;
else cout<< "ERROR-2";
return;
}
unsigned int getScore(char side){
if(side == 'l') return this->pointL;
else if (side == 'r') return this->pointR;
else return 0;
}
bool isPlaying(){
return this->playing;
}
bool stop(){
this->playing = false;
return true;
}
private:
unsigned int pointL, pointR;
bool playing;
};
class Player{
public:
int pos[5][2];
int maxX, maxY;
void __init(int maxX, int maxY, char side){
//create matrix with all cords of block of wall (r and l)
this->maxX = maxX;
this->maxY = maxY;
if(side == 'l')
for(int i = 0; i<5; i++){
pos[i][0] = 2;
pos[i][1] = 2+i;
gotoxy(pos[i][0],pos[i][1]);
cout<< "|";
}
else if(side == 'r')
for(int i = 0; i<5; i++){
pos[i][0] = maxX-4;
pos[i][1] = 2+i;
gotoxy(pos[i][0],pos[i][1]);
cout<< "|";
}
else
cout<<"ERRORE-1";
}
void moveUp(){
gotoxy(pos[4][0],pos[4][1]);
cout<< " ";
for(int i = 0; i<5; i++){
pos[i][1] = (pos[i][1] == 0)?pos[i][1]:pos[i][1]-1;
gotoxy(pos[i][0],pos[i][1]);
cout<< "|"; //solid rectangle
}
}
void moveDown(){
gotoxy(pos[4][0],pos[4][1]);
cout<< " ";
for(int i = 0; i<5; i++){
pos[i][1] = (pos[i][1] == this->maxY)?pos[i][1]:pos[i][1]+1;
gotoxy(pos[i][0],pos[i][1]);
cout<< "|"; //solid rectangle
}
}
};
int main(){
int a;
Game game;
Player pl1,pl2;
cout<< "Ridimensiona la finestra come meglio preferisci, quando hai fatto, premi un tasto per continuare";
_getch();
struct winsize size;
ioctl( 0, TIOCSWINSZ, (char *) &size );
printf("\e[2J\e[H");
pl1.__init(size.ws_row, size.ws_col, 'l');
pl2.__init(size.ws_row, size.ws_col, 'r');
//asap menu here
cout<< "TEST: " << size.ws_row;
char key;
while(game.isPlaying()){
if(_kbhit()){
key = _getch();
switch(key){ //when i press that keys, it's printed on terminal, how prevent?
case 'w':
pl1.moveUp();
break;
case 's':
pl2.moveDown();
break;
case 'q':
game.stop();
break;
}
}
}
return 0;
}
Here is a program which does not echo keystrokes but writes the characters to stderr instead. If you compile it, say, with g++ -o t t.cpp then you can start it with e.g. ./t 2>somefile, thus redirecting stderr to somefile.
In a second terminal you can do cat somefile after each keystroke in order to control what the program writes. (Warning: less somefile didn't work on my cygwin installation because the file growth appeared only in chunks in less (I told it to wait for input by pressing "F")).
Since all key strokes are forwarded to the controlling program Control-C or other means to send a signal to the running program via its controlling terminal doesn't work. You have to kill it from a different terminal.
The basic idea is that read() blocks in raw mode until input is available, so there is no need for a separate kbhit().
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
using namespace std;
int main()
{
struct termios oldt;
if( tcgetattr( 0, &oldt ) )
{
fprintf(stderr, "Error getting term attribs\n");
}
cfmakeraw(&oldt);
if( tcsetattr(0, TCSANOW, &oldt) )
{
fprintf(stderr, "Error setting term attribs\n");
}
char inp;
while(true)
{
int bytesRead = read(0, &inp, 1);
if( bytesRead <= 0)
{
fprintf(stderr, "oops, bytes read return val is %d\n", bytesRead);
}
else
{
write(2, &inp, 1);
}
}
}
You may use:
#include <iostream>
#include <stdexcept>
#include <termios.h>
#include <unistd.h>
// A class for mofdifying the behavour of a terminal.
class Terminal
{
// Types
// =====
public:
typedef speed_t speed_type;
// Terminal
// ========
public:
// Initialize the terminal file descriptor and store the attributes of the terminal.
Terminal(int fd)
: m_fd(fd), m_restore(get(fd))
{}
// Restore the orignal attributes of the terminal
~Terminal() {
set(m_fd, m_restore, false);
}
Terminal(const Terminal&) = delete;
const Terminal& operator = (const Terminal&) = delete;
int fd() const { return m_fd; }
void restore() { set(m_fd, m_restore); }
protected:
// Get attributes of a terminal
static termios get(const int fd) {
termios attributes;
if(tcgetattr(fd, &attributes) < 0) {
throw std::runtime_error("Terminal");
}
return attributes;
}
// Set attributes of a terminal
static void set(const int fd, const termios& attributes, bool exception = true) {
if(tcsetattr(fd, TCSANOW, &attributes) < 0 && exception) {
throw std::runtime_error("Terminal");
}
}
// Set attributes of a terminal
static void set(const int fd, int action, const termios& attributes, bool exception = true) {
if(tcsetattr(fd, action, &attributes) < 0 && exception) {
throw std::runtime_error("Terminal");
}
}
private:
int m_fd;
termios m_restore;
};
// A class for mofdifying the input behavour of a terminal.
class StdInputTerminal : public Terminal
{
// Constants
// =========
public:
enum Attributes {
Blocking = 0x01,
Echo = 0x02
};
// Static
// ======
public:
// Clear available input in std::cin
static void clear() {
termios attributes = disable_attributes(Blocking);
while(std::cin)
std::cin.get();
std::cin.clear();
set(fileno(stdin), attributes);
}
// StdInputTerminal
// ================
public:
// Initialize with 'stdin'
StdInputTerminal()
: Terminal(fileno(stdin))
{}
public:
// Disable attributes specified by any combination of Attributes flags
void disable(unsigned flags) { disable_attributes(flags); }
// Disable blocking
void disable_blocking() { disable_attributes(Blocking); }
protected:
// Set attributes of the terminal
static termios disable_attributes(unsigned flags) {
const int fd = fileno(stdin);
termios attributes = get(fd);
termios a = attributes;
if(flags & Blocking) {
a.c_lflag &= ~ICANON;
a.c_cc[VMIN] = 0;
a.c_cc[VTIME] = 0;
}
if(flags & Echo) {
a.c_lflag &= ~ECHO;
}
set(fd, a);
return attributes;
}
};
// Sample Usage
// ============
int kbhit() {
StdInputTerminal terminal;
terminal.disable(StdInputTerminal::Blocking | StdInputTerminal::Echo);
int result = 0;
char c;
if( ! std::cin.get(c))
std::cin.clear();
else
{
result = c;
std::cin.unget();
}
return result;
}
int getch() {
StdInputTerminal terminal;
terminal.disable(StdInputTerminal::Blocking | StdInputTerminal::Echo);
char result = 0;
while(true) {
std::cin.get(result);
if(std::cin.eof()) {
std::cin.clear();
usleep(100000);
}
else break;
}
if(std::cin.fail()) {
std::cin.clear();
result = 0;
}
return result;
}
// Test
// ====
int main()
{
std::cout << "Enter a single sample character: ";
char c;
std::cin.get(c);
std::cin.unget();
if(kbhit()) {
int ch = getch();
std::cout << "Entered character: " << char(ch);
if(kbhit()) {
int ch = getch();
std::cout << " Newline " << char(ch);
if(kbhit()) {
std::string line;
getline(std::cin, line);
std::cout << "\nToo many sample characters: " << line << '\n';
}
}
}
}
(Please excuse the incomplete classes, thy are experimental)
Related
When I compile ssh_client code from example folder of libssh source directory( I have wrote about building process of this library in this link : libssh's functions couldn't be found on qt):
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/select.h>
#include <sys/time.h>
#ifdef HAVE_TERMIOS_H
#include <termios.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_PTY_H
#include <pty.h>
#endif
#include <sys/ioctl.h>
#include <signal.h>
#include <errno.h>
#include <fcntl.h>
#include <libssh/callbacks.h>
#include <libssh/libssh.h>
#include <libssh/sftp.h>
#include "examples_common.h"
#define MAXCMD 10
static char *host = NULL;
static char *user = NULL;
static char *cmds[MAXCMD];
static char *config_file = NULL;
static struct termios terminal;
static char *pcap_file = NULL;
static char *proxycommand;
static int auth_callback(const char *prompt,
char *buf,
size_t len,
int echo,
int verify,
void *userdata)
{
(void) verify;
(void) userdata;
return ssh_getpass(prompt, buf, len, echo, verify);
}
struct ssh_callbacks_struct cb = {
.auth_function = auth_callback,
.userdata = NULL,
};
static void add_cmd(char *cmd)
{
int n;
for (n = 0; (n < MAXCMD) && cmds[n] != NULL; n++);
if (n == MAXCMD) {
return;
}
cmds[n] = strdup(cmd);
}
static void usage(void)
{
fprintf(stderr,
"Usage : ssh [options] [login#]hostname\n"
"sample client - libssh-%s\n"
"Options :\n"
" -l user : log in as user\n"
" -p port : connect to port\n"
" -d : use DSS to verify host public key\n"
" -r : use RSA to verify host public key\n"
" -F file : parse configuration file instead of default one\n"
#ifdef WITH_PCAP
" -P file : create a pcap debugging file\n"
#endif
#ifndef _WIN32
" -T proxycommand : command to execute as a socket proxy\n"
#endif
"\n",
ssh_version(0));
exit(0);
}
static int opts(int argc, char **argv)
{
int i;
while((i = getopt(argc,argv,"T:P:F:")) != -1) {
switch(i){
case 'P':
pcap_file = optarg;
break;
case 'F':
config_file = optarg;
break;
#ifndef _WIN32
case 'T':
proxycommand = optarg;
break;
#endif
default:
fprintf(stderr, "Unknown option %c\n", optopt);
usage();
}
}
if (optind < argc) {
host = argv[optind++];
}
while(optind < argc) {
add_cmd(argv[optind++]);
}
if (host == NULL) {
usage();
}
return 0;
}
#ifndef HAVE_CFMAKERAW
static void cfmakeraw(struct termios *termios_p)
{
termios_p->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
termios_p->c_oflag &= ~OPOST;
termios_p->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
termios_p->c_cflag &= ~(CSIZE|PARENB);
termios_p->c_cflag |= CS8;
}
#endif
static void do_cleanup(int i)
{
/* unused variable */
(void) i;
tcsetattr(0, TCSANOW, &terminal);
}
static void do_exit(int i)
{
/* unused variable */
(void) i;
do_cleanup(0);
exit(0);
}
static ssh_channel chan;
static int signal_delayed = 0;
static void sigwindowchanged(int i)
{
(void) i;
signal_delayed = 1;
}
static void setsignal(void)
{
signal(SIGWINCH, sigwindowchanged);
signal_delayed = 0;
}
static void sizechanged(void)
{
struct winsize win = {
.ws_row = 0,
};
ioctl(1, TIOCGWINSZ, &win);
ssh_channel_change_pty_size(chan,win.ws_col, win.ws_row);
setsignal();
}
static void select_loop(ssh_session session,ssh_channel channel)
{
ssh_connector connector_in, connector_out, connector_err;
int rc;
ssh_event event = ssh_event_new();
/* stdin */
connector_in = ssh_connector_new(session);
ssh_connector_set_out_channel(connector_in, channel, SSH_CONNECTOR_STDINOUT);
ssh_connector_set_in_fd(connector_in, 0);
ssh_event_add_connector(event, connector_in);
/* stdout */
connector_out = ssh_connector_new(session);
ssh_connector_set_out_fd(connector_out, 1);
ssh_connector_set_in_channel(connector_out, channel, SSH_CONNECTOR_STDINOUT);
ssh_event_add_connector(event, connector_out);
/* stderr */
connector_err = ssh_connector_new(session);
ssh_connector_set_out_fd(connector_err, 2);
ssh_connector_set_in_channel(connector_err, channel, SSH_CONNECTOR_STDERR);
ssh_event_add_connector(event, connector_err);
while (ssh_channel_is_open(channel)) {
if (signal_delayed) {
sizechanged();
}
rc = ssh_event_dopoll(event, 60000);
if (rc == SSH_ERROR) {
fprintf(stderr, "Error in ssh_event_dopoll()\n");
break;
}
}
ssh_event_remove_connector(event, connector_in);
ssh_event_remove_connector(event, connector_out);
ssh_event_remove_connector(event, connector_err);
ssh_connector_free(connector_in);
ssh_connector_free(connector_out);
ssh_connector_free(connector_err);
ssh_event_free(event);
}
static void shell(ssh_session session)
{
ssh_channel channel;
struct termios terminal_local;
int interactive=isatty(0);
channel = ssh_channel_new(session);
if (channel == NULL) {
return;
}
if (interactive) {
tcgetattr(0, &terminal_local);
memcpy(&terminal, &terminal_local, sizeof(struct termios));
}
if (ssh_channel_open_session(channel)) {
printf("Error opening channel : %s\n", ssh_get_error(session));
ssh_channel_free(channel);
return;
}
chan = channel;
if (interactive) {
ssh_channel_request_pty(channel);
sizechanged();
}
if (ssh_channel_request_shell(channel)) {
printf("Requesting shell : %s\n", ssh_get_error(session));
ssh_channel_free(channel);
return;
}
if (interactive) {
cfmakeraw(&terminal_local);
tcsetattr(0, TCSANOW, &terminal_local);
setsignal();
}
signal(SIGTERM, do_cleanup);
select_loop(session, channel);
if (interactive) {
do_cleanup(0);
}
ssh_channel_free(channel);
}
static void batch_shell(ssh_session session)
{
ssh_channel channel;
char buffer[1024];
size_t i;
int s = 0;
for (i = 0; i < MAXCMD && cmds[i]; ++i) {
s += snprintf(buffer + s, sizeof(buffer) - s, "%s ", cmds[i]);
free(cmds[i]);
cmds[i] = NULL;
}
channel = ssh_channel_new(session);
if (channel == NULL) {
return;
}
ssh_channel_open_session(channel);
if (ssh_channel_request_exec(channel, buffer)) {
printf("Error executing '%s' : %s\n", buffer, ssh_get_error(session));
ssh_channel_free(channel);
return;
}
select_loop(session, channel);
ssh_channel_free(channel);
}
static int client(ssh_session session)
{
int auth = 0;
char *banner;
int state;
if (user) {
if (ssh_options_set(session, SSH_OPTIONS_USER, user) < 0) {
return -1;
}
}
if (ssh_options_set(session, SSH_OPTIONS_HOST, host) < 0) {
return -1;
}
if (proxycommand != NULL) {
if (ssh_options_set(session, SSH_OPTIONS_PROXYCOMMAND, proxycommand)) {
return -1;
}
}
/* Parse configuration file if specified: The command-line options will
* overwrite items loaded from configuration file */
if (config_file != NULL) {
ssh_options_parse_config(session, config_file);
} else {
ssh_options_parse_config(session, NULL);
}
if (ssh_connect(session)) {
fprintf(stderr, "Connection failed : %s\n", ssh_get_error(session));
return -1;
}
state = verify_knownhost(session);
if (state != 0) {
return -1;
}
ssh_userauth_none(session, NULL);
banner = ssh_get_issue_banner(session);
if (banner) {
printf("%s\n", banner);
free(banner);
}
auth = authenticate_console(session);
if (auth != SSH_AUTH_SUCCESS) {
return -1;
}
if (cmds[0] == NULL) {
shell(session);
} else {
batch_shell(session);
}
return 0;
}
static ssh_pcap_file pcap;
static void set_pcap(ssh_session session)
{
if (pcap_file == NULL) {
return;
}
pcap = ssh_pcap_file_new();
if (pcap == NULL) {
return;
}
if (ssh_pcap_file_open(pcap, pcap_file) == SSH_ERROR) {
printf("Error opening pcap file\n");
ssh_pcap_file_free(pcap);
pcap = NULL;
return;
}
ssh_set_pcap_file(session, pcap);
}
static void cleanup_pcap(void)
{
if (pcap != NULL) {
ssh_pcap_file_free(pcap);
}
pcap = NULL;
}
int main(int argc, char **argv)
{
ssh_session session;
session = ssh_new();
ssh_callbacks_init(&cb);
ssh_set_callbacks(session,&cb);
if (ssh_options_getopt(session, &argc, argv)) {
fprintf(stderr,
"Error parsing command line: %s\n",
ssh_get_error(session));
usage();
}
opts(argc, argv);
signal(SIGTERM, do_exit);
set_pcap(session);
client(session);
ssh_disconnect(session);
ssh_free(session);
cleanup_pcap();
ssh_finalize();
return 0;
}
I got the following error:
/home/heydari.f/projects/ssh_client/ssh_client/main.c:100: error: config.h: No such file or directory
#include "config.h"
^~~~~~~~~~
Is there anything to do with configure or what?
I use Qt and my os is ubuntu 18.04.
Config headers as config.h normally aren't needed to compile a program against a library. Those are generated to compile the library, not the programs that link against them. If not, there will be lot of trouble as lots of software use them and there would be lots of collisions between them.
Being an example, it may be that it uses the config.h, but in that case I'm pretty sure you should compile with the system libssh uses to compile. (You may need to specify an option to compile examples when calling configure or specify something in DefineOptions.cmake or something in the same line.)
If you copied the sources (as it seems as the error states projects/ssh_client/) to build with Qt, you probably can remove that include unless it is a config from Qt itself.
Also, if you are compiling with Qt you surely need to install the lib and follow #Dmitry advice about -I, -L and -l flags to compiler.
I tried to write a program which hooks keyboard messages to pronounce the name of each key whenever it is pressed in Ubuntu (KDE); without interfering with normal action of keyboard in programs (just announcing the key name).
This is my program:
#include <X11/Xlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
using namespace std;
void SendPressKeyEvent(Display *display, XKeyEvent xkey)
{
Window current_focus_window;
int current_focus_revert;
XGetInputFocus(display, ¤t_focus_window, ¤t_focus_revert);
xkey.type = KeyPress;
xkey.display = display;
xkey.window = current_focus_window;
xkey.root = DefaultRootWindow(display);
xkey.subwindow = None;
xkey.time = 1000 * time(0);
xkey.x = 0;
xkey.y = 0;
xkey.x_root = 0;
xkey.y_root = 0;
xkey.same_screen = True;
XSendEvent(display, InputFocus, True, KeyPressMask, (XEvent *)(&xkey));
}
void SendReleaseKeyEvent(Display *display, XKeyEvent xkey)
{
Window current_focus_window;
int current_focus_revert;
XGetInputFocus(display, ¤t_focus_window, ¤t_focus_revert);
xkey.type = KeyRelease;
xkey.display = display;
xkey.window = current_focus_window;
xkey.root = DefaultRootWindow(display);
xkey.subwindow = None;
xkey.time = 1000 * time(0);
xkey.x = 0;
xkey.y = 0;
xkey.x_root = 0;
xkey.y_root = 0;
xkey.same_screen = True;
XSendEvent(display, InputFocus, True, KeyReleaseMask, (XEvent *)(&xkey));
}
void *TaskCode(void* arg)
{
switch(*(int*)arg)
{
case 38:
system("espeak -v en " "\"a\"");
}
return 0;
}
int main()
{
Display *display = XOpenDisplay(0);
if(display == 0)
exit(1);
XGrabKeyboard(display, DefaultRootWindow(display), True, GrabModeAsync, GrabModeAsync, CurrentTime);
XEvent event;
while(true)
{
XNextEvent(display, &event);
if(event.type == Expose)
{
}
if(event.type == KeyPress)
{
SendPressKeyEvent(display,event.xkey);
if(event.xkey.keycode == 38)
{
pthread_t thread;
int thread_arg = event.xkey.keycode;
pthread_create(&thread,0, TaskCode, (void*) &thread_arg);
}
}
if(event.type == KeyRelease)
SendReleaseKeyEvent(display,event.xkey);
}
XCloseDisplay(display);
}
This program is just for the key a which can be extended to other keys.
But when this program is running, some programs (e.g. Chromium) do not show the blinker (cursor) in their edit boxes. Also all KDE hotkeys become disabled.
How can this be fixed?
Here's my quick and dirty example
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <stdio.h>
#include <ctype.h>
int main ()
{
Display* d = XOpenDisplay(NULL);
Window root = DefaultRootWindow(d);
Window curFocus;
char buf[17];
KeySym ks;
XComposeStatus comp;
int len;
int revert;
XGetInputFocus (d, &curFocus, &revert);
XSelectInput(d, curFocus, KeyPressMask|KeyReleaseMask|FocusChangeMask);
while (1)
{
XEvent ev;
XNextEvent(d, &ev);
switch (ev.type)
{
case FocusOut:
printf ("Focus changed!\n");
printf ("Old focus is %d\n", (int)curFocus);
if (curFocus != root)
XSelectInput(d, curFocus, 0);
XGetInputFocus (d, &curFocus, &revert);
printf ("New focus is %d\n", (int)curFocus);
if (curFocus == PointerRoot)
curFocus = root;
XSelectInput(d, curFocus, KeyPressMask|KeyReleaseMask|FocusChangeMask);
break;
case KeyPress:
printf ("Got key!\n");
len = XLookupString(&ev.xkey, buf, 16, &ks, &comp);
if (len > 0 && isprint(buf[0]))
{
buf[len]=0;
printf("String is: %s\n", buf);
}
else
{
printf ("Key is: %d\n", (int)ks);
}
}
}
}
It's not reliable but most of the time it works. (It is showing keys I'm typing into this box right now). You may investigate why it does fail sometimes ;) Also it cannot show hotkeys in principle. Hotkeys are grabbed keys, and only one client can get a grabbed key. Absolutely nothing can be done here, short of loading a special X11 extension designed for this purpose (e.g. XEvIE).
Thanks to n.m.'s answer and parsa's comment, this is my final code:
#include <X11/Xlib.h>
#include <stdlib.h>
#include <iostream>
using namespace std;
void* TaskCode(void* parg)
{
int keycode = *((int*)parg);
cout<< "\n\n" << keycode << "\n\n";
if(keycode == XKeysymToKeycode(XOpenDisplay(0),'a'))
system("espeak -v en " "\"a\"");
delete (int*)parg;
return 0;
}
void Action(int keycode)
{
pthread_t thread;
pthread_attr_t attrs;
pthread_attr_init(&attrs);
pthread_attr_setdetachstate(&attrs,PTHREAD_CREATE_DETACHED);
pthread_attr_setstacksize(&attrs, 1000);
int* pthread_arg = new int;
*pthread_arg = keycode;
pthread_create(&thread,&attrs, TaskCode, (void*) pthread_arg);
}
int MyX11ErrorHandler(Display *, XErrorEvent *error_event)
{
cout << "\n\n" "An X11-Functions error occured. Probably the focused window was closed.""\n"
"This error will be ignored." "\n";
cout<< "error_code: " << (unsigned)error_event -> error_code << "\n";
cout<< "minor_code: " << (unsigned)error_event -> minor_code << "\n";
cout<< "request_code: " << (unsigned)error_event -> request_code << "\n";
cout<< "resourceid: " << error_event -> resourceid << "\n";
cout<< "serial; " << error_event -> serial << "\n";
cout<< "type: " << error_event -> type << "\n\n";
return 0;
}
int main()
{
Display* display = XOpenDisplay(0);
Window root = DefaultRootWindow(display);
Window current_focus_window;
int revert;
XSetErrorHandler(MyX11ErrorHandler);
XGetInputFocus(display, ¤t_focus_window, &revert);
XSelectInput(display,current_focus_window,KeyPressMask | KeyReleaseMask | FocusChangeMask);
while(true)
{
XEvent event;
XNextEvent(display, &event);
switch (event.type)
{
case FocusOut:
if(current_focus_window != root)
XSelectInput(display, current_focus_window, 0);
XGetInputFocus(display, ¤t_focus_window, &revert);
if(current_focus_window == PointerRoot)
current_focus_window = root;
XSelectInput(display, current_focus_window, KeyPressMask|KeyReleaseMask|FocusChangeMask);
break;
case KeyPress:
Action(event.xkey.keycode);
break;
}
}
}
Add these to a Qt Creator's project .pro file:
LIBS += -lX11
LIBS += -lpthread
LIBS += -lXtst
Any improvement suggestions is appreciated.
To archive I also add my final code with grabbing:
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
using namespace std;
void* TaskCode(void* parg)
{
int keycode = *((int*)parg);
cout<< "\n\n" << keycode << "\n\n";
system("espeak -v en " "\"a\"");
delete (int*)parg;
return 0;
}
void SendKeyEvent(Display *display, XEvent event)
{
Window current_focus_window;
XKeyEvent& xkey = event.xkey;
int current_focus_revert;
XGetInputFocus(display, ¤t_focus_window, ¤t_focus_revert);
xkey.state = Mod2Mask;
XSendEvent(display, InputFocus, True, xkey.type, (XEvent *)(&event));
}
int GrabKey(Display* display, Window grab_window, int keycode)
{
unsigned int modifiers = Mod2Mask; // numlock on
//Window grab_window = DefaultRootWindow(display);
Bool owner_events = True;
int pointer_mode = GrabModeAsync;
int keyboard_mode = GrabModeAsync;
XGrabKey(display, keycode, modifiers, grab_window, owner_events, pointer_mode, keyboard_mode);
return keycode;
}
void UngrabKey(Display* display, Window grab_window, int keycode)
{
unsigned int modifiers = Mod2Mask; // numlock on
// Window grab_window = DefaultRootWindow(display);
XUngrabKey(display,keycode,modifiers,grab_window);
}
void Action(int keycode)
{
pthread_t thread;
int* pthread_arg = new int;
*pthread_arg = keycode;
pthread_create(&thread,0, TaskCode, (void*) pthread_arg);
}
int main()
{
Display* display = XOpenDisplay(0);
Window root = DefaultRootWindow(display);
XEvent event;
int keycode = XKeysymToKeycode(display,'a');
GrabKey(display,root,keycode);
XSelectInput(display, root, KeyPressMask | KeyReleaseMask);
while(true)
{
XNextEvent(display, &event);
switch(event.type)
{
case KeyPress:
Action(event.xkey.keycode);
case KeyRelease:
SendKeyEvent(display,event);
default:
break;
}
}
XCloseDisplay(display);
}
Everything is good except that, unlike the code in question, it ignores language layout. Pressing a types a whatever regradless of language layout!
As an alternative to listening to X events, it's also possible to listen to Linux input events directly: https://stackoverflow.com/a/27693340/21501
This has the benefit that it's possible to modify the event stream in-flight, and block, edit or generate input events.
The proper way to listen to all events is using the X Record Extension Library, part of libXtst, apparently installed on pretty much every X system. It is documented here, but as the docs are patchy, you will need to browse previous implementations of this. Here is a nice working demo, and here is a more capable and complete implementation.
A simplified version of the first example is included below.
#include <stdio.h>
#include <X11/XKBlib.h>
#include <X11/extensions/record.h>
void key_pressed_cb(XPointer arg, XRecordInterceptData *d);
int scan(int verbose) {
XRecordRange* rr;
XRecordClientSpec rcs;
XRecordContext rc;
Display *dpy = XOpenDisplay(NULL);
rr = XRecordAllocRange();
rr->device_events.first = KeyPress;
rr->device_events.last = ButtonReleaseMask;
rcs = XRecordAllClients;
rc = XRecordCreateContext (dpy, 0, &rcs, 1, &rr, 1);
XFree (rr);
XRecordEnableContext(dpy, rc, key_pressed_cb, NULL);
}
void key_pressed_cb(XPointer arg, XRecordInterceptData *d) {
if (d->category != XRecordFromServer)
return;
int key = ((unsigned char*) d->data)[1];
int type = ((unsigned char*) d->data)[0] & 0x7F;
int repeat = d->data[2] & 1;
if(!repeat) {
switch (type) {
case KeyPress:
printf("key press %d\n", key);
break;
case KeyRelease:
printf("key release %d\n", key);
break;
case ButtonPress:
printf("button press %d\n", key);
break;
case ButtonRelease:
printf("button release %d\n", key);
break;
default:
break;
}
}
XRecordFreeData (d);
}
int main() {
scan(True);
return 0;
}
gcc -o x1 x1.c -lX11 -lXtst
A followup to this question.
How can I clear the input buffer?
sleep(2);
// clear cin
getchar();
I only want the character that was typed in last, I want to discard any input that was put in while the program was asleep. Is there a way to do that?
Also, I don't want to wait actively to clear cin, thus I can't use ignore().
My approach would have been to get the current size of the buffer and if it's not equal to 0, silently empty the buffer. However, I have not found a way to get the size of the buffer. std::cin.rdbuf()->in_avail() always returns 0 for me. peek() also waits actively.
I don't want to use ncurses.
Having a system supporting tcgetattr/tcsetattr:
#include <iostream>
#include <stdexcept>
#include <termios.h>
#include <unistd.h>
class StdInput
{
// Constants
// =========
public:
enum {
Blocking = 0x01,
Echo = 0x02
};
// Static
// ======
public:
static void clear() {
termios attributes = disable_attributes(Blocking);
while(std::cin)
std::cin.get();
std::cin.clear();
set(attributes);
}
// StdInput
// ========
public:
StdInput()
: m_restore(get())
{}
~StdInput()
{
set(m_restore, false);
}
void disable(unsigned flags) { disable_attributes(flags); }
void disable_blocking() { disable_attributes(Blocking); }
void restore() { set(m_restore); }
private:
static termios get() {
const int fd = fileno(stdin);
termios attributes;
if(tcgetattr(fd, &attributes) < 0) {
throw std::runtime_error("StdInput");
}
return attributes;
}
static void set(const termios& attributes, bool exception = true) {
const int fd = fileno(stdin);
if(tcsetattr(fd, TCSANOW, &attributes) < 0 && exception) {
throw std::runtime_error("StdInput");
}
}
static termios disable_attributes(unsigned flags) {
termios attributes = get();
termios a = attributes;
if(flags & Blocking) {
a.c_lflag &= ~ICANON;
a.c_cc[VMIN] = 0;
a.c_cc[VTIME] = 0;
}
if(flags & Echo) {
a.c_lflag &= ~ECHO;
}
set(a);
return attributes;
}
termios m_restore;
};
int main()
{
// Get something to ignore
std::cout << "Ignore: ";
std::cin.get();
// Do something
StdInput::clear();
std::cout << " Input: ";
std::string line;
std::getline(std::cin, line);
std::cout << "Output: " << line << std::endl;
return 0;
}
I have to write a simple sinthesizer at university which uses sdl_mixer to generate sine waves. I got a code from my teacher which work on windows correctly, but in ubuntu it exits with segmentation fault.
I installed both sdl_mixer1.2-dev and sdl1.2-dev packages.
I tried a code that generates tone with sdl_audio. It worked fine, but I heard that for multi-channel playback, sdl_mixer is the solution.
The getch() part of the code is working well, the problem is with the sound manager part.
Can somebody help me to solve this problem?
Here is my code:
#include <iostream>
#include <termios.h>
#include <stdio.h>
#include<cmath>
#include <SDL/SDL_mixer.h>
#include<vector>
using namespace std;
class SoundManager
{
int channelnum;
vector<Mix_Chunk*> chunks;
public:
void init()
{
if (Mix_OpenAudio(48000,AUDIO_S16, 2, 1024) == -1)
{
cerr << "audio hiba" << endl;
exit(1);
}
}
SoundManager(int asked_channelnum=64)
{
channelnum = Mix_AllocateChannels(asked_channelnum);
chunks.assign(channelnum, (Mix_Chunk*)0);
}
int get_channelnum() const
{
return channelnum;
}
void play_stereo(const vector<short int>& v, int volume=128)
{
const short int *p = &(v[0]);
// short int * p = new short int[v.size()];
// for (size_t i=0;i<v.size();i++) {
// p[i]=v[i];
// }
Mix_Chunk * ownsample = new Mix_Chunk;
ownsample->alen = v.size()*2;
ownsample->abuf = (Uint8*)p;
ownsample->allocated = 1;
ownsample->volume = volume;
int playchannel = Mix_PlayChannel(-1, ownsample, 0);
if (playchannel != -1 && chunks[playchannel])
{
delete[] chunks[playchannel]->abuf;
Mix_FreeChunk(chunks[playchannel]);
}
if (playchannel != -1)
chunks[playchannel] = ownsample;
}
};
Mix_Chunk *ownsample = 0;
Mix_Chunk *samples = 0;
void hang()
{
if (Mix_OpenAudio(48000,AUDIO_S16, 2, 1024) == -1)
{
cerr << "audio hiba" << endl;
exit(1);
}
vector<short> s(48000*2,0);
for (int i=0; i<s.size()/2; i++)
{
s[i*2] = sin(i/10.0+i*i/10000.0)*32000*(1/sqrt(i/100.0));
s[i*2+1] = sin(i/10.0)*32000*(1/sqrt(i/100.0));
}
samples = Mix_LoadWAV("ding.wav");
ownsample = new Mix_Chunk;
ownsample->alen = s.size()*2;
ownsample->abuf =(unsigned char*) &(s[0]);
ownsample->allocated = 0;
ownsample->volume = 128;
cout << samples->alen << endl;
if (!samples)
{
cerr << "wav 'ding.wav' open error" << endl;
exit(1);
}
int channelnum = Mix_AllocateChannels(64);
if (channelnum != 64)
{
cerr << "warning: not as many channels are reserved as attended"<<endl;
}
if (Mix_PlayChannel(-1, ownsample, 0)==-1 )
{
cerr << "error on play" << endl;
}
// if (Mix_PlayChannel(-1, samples, 0)==-1 ) {
// cerr << "error on play" << endl;
// }
}
void pitty(SoundManager &sm)
{
vector<short> s(48000*2,0);
for (int i=0; i<s.size()/2; i++)
{
s[i*2] = sin(i/10.0+i*i/10000.0)*32000*(1/sqrt(i/100.0));
s[i*2+1] = sin(i/10.0)*32000*(1/sqrt(i/100.0));
}
sm.play_stereo(s);
}
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)
{
int ch;
initTermios(echo);
ch = getchar();
resetTermios();
return ch;
}
/* Read 1 character without echo */
int getch(void)
{
return getch_(o);
}
/* Read 1 character with echo */
int getche(void)
{
return getch_(1);
}
int main(void)
{
SoundManager sm(16);
sm.init();
vector<short> s(48000*2,0);
for (int i=0; i<s.size()/2; i++)
{
s[i*2] = sin(i/10.0+i*i/10000.0)*32000*(1/sqrt(i/100.0));
s[i*2+1] = sin(i/10.0)*32000*(1/sqrt(i/100.0));
}
int c;
while (1)
{
c = getch();
cout <<"keycode:\n";
cout <<c;
sm.play_stereo(s);
}
return 0;
}
Thank you for your help in advance.
Greetings,
Istvan Velegi
(1) if you are getting a segmentation fault can you recompile the code with debugging symbols on (if you are using g++ or clang++); use -g3.
(2) run the program using a debugger and get a stack trace of where the code segmentation faults (use gdb).
This looks absolutely, totally bogus:
void play_stereo(const vector<short int>& v, int volume=128)
{
const short int *p = &(v[0]);
//...
ownsample->abuf = (Uint8*)p;
//...
delete[] chunks[playchannel]->abuf;
Yes, I realize chunks[playchannel] isn't ownsample yet, but you do put ownsample into the chunks queue, so eventually you will come back around and try to delete[] the internal array storage of a vector<short int>.
That's very bad.
This commented-out code actually seems to be the correct thing to have in place of const short int *p = &(v[0]):
// short int * p = new short int[v.size()];
// for (size_t i=0;i<v.size();i++) {
// p[i]=v[i];
// }
I want a infinit loop to break when I press "q" key on my keyboard.
Problems I did'nt realize: standard getchar waits for the user to make an
input and press enter, which halt the execution of the loop there.
I got around the "enter" problem, but the loop still halts and waits for the input.
here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <termios.h>
int getch(void); // Declare of new function
int main (void) { char x;
do
{
if (x = getch())
printf ("Got It! \n!);
else
{
delay(2000);
printf ("Not yet\n!);
}
}while x != 'q');
return 0;
}
int getch(void)
{
int ch;
struct termios oldt;
struct termios newt;
tcgetattr(STDIN_FILENO, &oldt);
newt = oldt;
newt.c_lflag &= ~(ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
ch = getchar();
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
return ch;
}
You could read them from the device:
#define INPUT_QUEUE "/dev/input/event0"
#define EVENT_LEN 16
void readEventLine(FILE * in, char * data) { //read input key stream
int i;
for(i = 0; i <= 15; i++) { //each key press will trigger 16 characters of data, describing the event
data[i] = (char) fgetc(in);
}
}
int readKeyPress() {
FILE * input;
char data[EVENT_LEN];
input = fopen(INPUT_QUEUE, "r+");
readEventLine(input, data);
}
Just call something like this instead of your getch.
Adapted from http://www.cplusplus.com/forum/unices/8206/
I had to do following to make it work correctly, thanks for input!!
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <termios.h>
#include <fcntl.h>
int getch(void); // Declare of new function
int main (void)
{
char x;
do
{
x = getch();
if (x != EOF)
{
printf ("\r%s\n", "Got something:");
printf ("it's %c!",x); // %c - for character %d - for ascii number
}else
{
delay(2000);
printf ("Not yet\n!);
}
}while x != 'q');
return 0;
}
int getch(void)
{
int ch;
struct termios oldt;
struct termios newt;
long oldf;
long newf;
tcgetattr(STDIN_FILENO, &oldt); /* Store old settings */
newt = oldt;
newt.c_lflag &= ~(ICANON | ECHO); /* Make one change to old settings in new settings */
tcsetattr(STDIN_FILENO, TCSANOW, &newt); /* Apply the changes immediatly */
oldf = fcntl(STDIN_FILENO, F_GETFL, 0);
newf = oldf | O_NONBLOCK;
fcntl(STDIN_FILENO, F_SETFL, newf);
ch = getchar();
fcntl(STDIN_FILENO, F_SETFL, oldf);
tcsetattr(STDIN_FILENO, TCSANOW, &oldt); /* Reapply the old settings */
return ch;
}