Detect KeyDown KeyPress and KeyUp events in g++ - c++

I am editing a very old question of mine when I used to use turbo c++. So now I may not be able to explain exact behaviour of turboc++ compiler and hence will make some assumptions.
I know turbo c/c++ is not standard but am trying to achieve similar behaviour in g++ ubuntu.
Before I ask my question, it is necessary to quote the meaning of KeyDown, KeyPress and KeyUp event taken from one of the answers from Difference between the KeyDown Event, KeyPress Event and KeyUp Event in Visual Studio
The MSDN documentation states the order in which the three events occur fairly clearly:
Key events occur in the following order:
KeyDown
KeyPress
KeyUp
KeyDown is raised as soon as the user presses a key on the keyboard, while they're still holding it down.
KeyPress is raised for character keys (unlike KeyDown and KeyUp, which are also raised for noncharacter keys) while the key is pressed. This is a "higher-level" event than either KeyDown or KeyUp, and as such, different data is available in the EventArgs.
KeyUp is raised after the user releases a key on the keyboard.
Generally, you should handle the KeyUp event in your application. Actions should not be initiated in the UI until after the user releases the key. And since KeyUp is a lower-level event than KeyPress, you'll always have plenty of information at your fingertips about the key that was pressed, and it will even work for handling non-character keys.
NOTE : My question has nothing to do with MSDN. It was quoted only to get familiar with the KeyDown KeyPress and KeyUp events.
Now, getch in turbo c/c++ does not need the key to be released. The execution of getch(); gets completed as soon as one touches/presses any keyboard key(most probably only alphanumeric keys(assumption)).
Now a number of questions like this(Detecting when a key is released) and many other focus on windows plateform and not on g++ linux environment.
This question
C++ mutiple key input or key press/release events seems closest to my question but the question seems incomplete with information about neither the methodologies/code used to take input nor any error message(s).
Answer by Stephen Veiss with 29 up votes in the following question says that it is probably the closest equivalent.
https://stackoverflow.com/questions/1377403/alternative-function-in-iostream-h-for-getch-of-conio-h#:~:text=For%20getch()%2C%20int%20ch,getch%20does%20an%20unbuffered%20read.]
But it still needs the enter key to be pressed after typing input at the input terminal.
The first answer of the following question seems to correctly simulate getch() equivalent in g++(gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.12) ).
What is the equivalent to getch() & getche() in Linux?
#include<iostream>
using namespace std;
#include <termios.h>
#include <stdio.h>
static struct termios old, current;
/* Initialize new terminal i/o settings */
void initTermios(int echo)
{
tcgetattr(0, &old); /* grab old terminal i/o settings */
current = old; /* make new settings same as old settings */
current.c_lflag &= ~ICANON; /* disable buffered i/o */
if (echo) {
current.c_lflag |= ECHO; /* set echo mode */
} else {
current.c_lflag &= ~ECHO; /* set no echo mode */
}
tcsetattr(0, TCSANOW, &current); /* 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;
}
I have tested the above code. Touching any alphanumeric key completes execution of getch function but keystrokes of keys like CAPS_LOCK, SHIFT, CONTROL, ALT etc doesn't. Moreover, it forces us to use .h versions of header(stdio.h and termios.h), which I don't find commendable.
The following code
#include<iostream>
#include<ncurses.h>
using namespace std;
int main() {
cout<<"NIRBHAY KUMAR PANDEY"<<endl;
getch();
return 0;
}
compiles(g++ filename.cpp -lncurses) and runs successfully in my (Linux Mint 18.2 Cinnamon 64-bit, g++(gcc-5.4.0)) but gives following compilation errors in geeksforgeeks and hakerrank online compilers.
IN GEEKSFORGEEKS :
geeksforgeeks prog.cpp:2:20: fatal error: ncurses.h: No such file or directory.
IN HACKERRANK :
hakerrank /cc1ZsEbF.o: In function main': solution.cc:7: undefined reference to stdscr' solution.cc:7: undefined reference to `wgetch' collect2: error: ld returned 1 exit status Exit Status 255
Now my question is "are there any standard functions in standard headers in (Linux, g++) for detecting - KeyDown KeyPress and KeyUp events of all keys(including control keys and any key combination) of the keyboard - at the input terminal while waiting for input from the user ?
If yes, then a complete full running program will be appreciated.
(Note : I have achieved all this almost 12 years ago very easily by reading let us C 6th edition on turbo c/c++ compiler. I can recall that there were concept of ascii code and scan code. The book C++ primer 5th edition by Stanley B. Lippman has nothing to say anything about ascii code and scan code)

Related

How do I get char directly from keyboard not through buffer?

I am making a game which has a character moves in 4 directions: up, down, left, right corresponding to W,S,A,D on the keyboard. The problem is when using getch() to get input from buffer, it always has a pause time after the first single keypress. For instance, when I hold 'A' button, it acts like: A(a short period of time)AAAAAAAAA.
How do I get rid of that delay time?
Any help would be appreciated.
(Answers in either C or C++ are all acceptable, since I am using graphics.h for this program, which requires C++ to run, but I mainly code in C).
I am using windows 10 64 bits.
For a non-blocking getch method I personally use this piece of code (in C):
#include <conio.h>
int getch_noblock(){
return _kbhit() ? _getch() : -1;
}
the _kbhit() method returns 0 if no key are pressed, otherwise returns a number if the keyboard input buffer is not empty.
the _getch() method read a char from the keyboard buffer.
It works only for Windows.
Documentation:
_khbit(): https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/kbhit?view=msvc-170
_getch(): https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/getch-getwch?view=msvc-170
By the way, surfing on the web I found an interesting method, but I've never tried or seen it:
https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/getch-nolock-getwch-nolock?view=msvc-170
getch() already bypasses buffer:
Prototype
int _getch(void);
Description
_getch obtains a character from stdin. Input is unbuffered, and this
routine will return as soon as a character is available without
waiting for a carriage return. The character is not echoed to stdout.
_getch bypasses the normal buffering done by getchar and getc.
And for your problem, as someone already said, you can use the kbhit() method

How to simulate holding down a keyboard button in C++

I am trying to make a program that would simulate holding down a keyboard button.
This program is supposed to work in games, where holding down buttons such as W,A,S,D is required. I tested the program both in Grand Theft Auto V and Garry's Mod, but it didn't work in either of them.
I tried using SendInput and keybd_event functions for emulating the input with no luck.
#include <windows.h>
#define VK_W 0x57
using namespace std;
int main(){
while(1){
keybd_event(VK_W, 0, 0, 0);
Sleep(3000); //should hold W for 3 seconds
keybd_event(VK_W, 0, KEYEVENTF_KEYUP, 0);
Sleep(1000);
}
return 0;
}
I've created macros using Razer's keyboard software, which work perfectly, so there must be a way to simulate the key hold input.
I also tried creating an AutoHotkey script, which does work in Garry's Mod, but not in Grand Theft Auto V:
w::
SendInput {w down}
Sleep 3000
SendInput {w up}
This script holds W for 3 seconds when W is pressed.
I tried searching the web, but didn't find any working implementation.
EDIT: I searched around some more and found this: https://stackoverflow.com/a/3647975/1587051
It turns out I was using Unicode instead of keyboard scan codes combined with KEYEVENTF_SCANCODE flag. DirectInput games are now receiving the keystrokes correctly.
For reference sake, as it has already been answered in the comments, you have to use SendInput rather than SendMessage, when filling the INPUT structure required for the SendInput function make sure you combine your Flags with KEYEVENTF_SCANCODE to send hardware signals instead of virtual ones. These will be handled by DirectInput.
Source : Simulating Keyboard with SendInput API in DirectInput applications

Non canonical mode

What's a simple way to using backspace in non canonical mode in linux terminal ?
It's part of code, when i set flags:
struct termios old_tio, new_tio;
/* get the terminal settings for stdin */
tcgetattr(STDIN_FILENO, &old_tio);
/* we want to keep the old setting to restore them a the end */
new_tio = old_tio;
/* disable canonical mode (buffered i/o) and local echo */
new_tio.c_lflag &=(~ICANON );/*& ~ECHOE );*/
/* set the new settings immediately */
tcsetattr(STDIN_FILENO,TCSANOW,&new_tio);
for(;1;) {
c = getchar();
switch(c) {...}
}
And when i press backspace i get an
^?
.
But i need to erase last symbol..
Thank you.
I don't think it's possible. According to the tcsetattr() man page (emphasis mine):
In noncanonical mode input is available immediately (without the user
having to type a line-delimiter character), and line editing is disabled.
Besides, if your program immediately receives every character you type, how can it be 'taken away' again?
Do this in your linux terminal and do your coding as usual it will not show ^? when u use backspace.
You can also add this in your .profile as permanent.
stty erase ^?

Sending Keystrokes to a X Window

I am currently experimenting with xdotool to send keys to a process (I understand that it may not work for all processes that does not set _NET_WM_PID). I have trouble sending keystrokes to windows other from the focus. It does work if you are sending keystrokes to the CURRENTWINDOW. Below is the snippet that I used to test xdotool's functionality.
extern "C"{
#include <xdo.h>
}
//extern "C" xdo_window_search
#include <iostream>
#include <string.h>
using namespace std;
int main(){
xdo_t* p_xdo = xdo_new(NULL);
// Allocate memory for search query.
xdo_search_t s;
// Clear the allocated memory.
memset(&s, 0, sizeof(xdo_search_t));
// Set the search query.
s.pid = 1916;
s.max_depth = -1;
s.searchmask = SEARCH_PID;
s.require = xdo_search::SEARCH_ANY;
// Allocate memory for output
Window* windows;
int no_windows;
xdo_window_search(p_xdo,&s,&windows,&no_windows);
cout << no_windows << endl;
// Prints all windows' names with matching criteria
for( int i=0;i<no_windows;i++ ){
unsigned char * name;
int size;
int type;
xdo_get_window_name(p_xdo,windows[i],&name,&size,&type);
cout << i << ":" << name << endl;
}
for( int i=0;i<no_windows;i++ ){
xdo_type(p_xdo,windows[i],"Hello World",0);
}
//xdo_type(p_xdo,CURRENTWINDOW,"Hello World",0); // This does work.
return 0;
}
In additional to testing xdotool's functionality, I've looked into xdotool's source code. Interestingly, I found that they are using Xtest to send keystrokes to the focused window (CURRENTWINDOW) and X11's XSendEvent for other windows. I turned to xdotool because I couldn't get XSendEvent to work and Xtest cannot send keys to any other windows than the focused window.
Am I not using the xdotool correctly? Does xdotool not work with all *nix OS with X11?
[I am running this on Ubuntu 13.04.]
EDIT
So, it looks like that does work but not for all windows that it finds. For example, it works for firefox but not gedit and gnome-terminal although it found gedit and gnome-terminal by its pid. It behaves differently if I used CURRENTWINDOW.
So, it would be great if someone can explain why is this so. Like, is it related the force send flag in an XEvent?
Directly from the xdotool manual:
SENDEVENT NOTES
If you are trying to send key input to a specific window, and it does
not appear to be working, then it's likely your application is ignoring
the events xdotool is generating. This is fairly common.
Sending keystrokes to a specific window uses a different API than
simply typing to the active window. If you specify 'xdotool type
--window 12345 hello' xdotool will generate key events and send them
directly to window 12345. However, X11 servers will set a special flag
on all events generated in this way (see XEvent.xany.send_event in
X11's manual). Many programs observe this flag and reject these events.
It is important to note that for key and mouse events, we only use
XSendEvent when a specific window is targeted. Otherwise, we use XTEST.
Some programs can be configured to accept events even if they are
generated by xdotool. Seek the documentation of your application for
help.
Specific application notes (from the author's testing): * Firefox 3
seems to ignore all input when it does not have focus. * xterm can be
configured while running with ctrl+leftclick, 'Allow SendEvents' *
gnome-terminal appears to accept generated input by default.

KEY_ENTER vs '\n'?

When I'm using PDcurses and I try to have a while loop exit when the enter key is pressed with while(key != KEY_ENTER), the while loop never exits. However, when I try to have the same loop exit with while((char)key != '\n'), it exits successfully whenever I pressed enter. Why does '\n' work and not KEY_ENTER?
btw, key is an int
and I hope this is the relevant few lines of the code:
int key;
while((char)key != '\n') {
key = getch();
...
}
getch() is a function defined by the ANSI C standard for the C runtime library.
On most systems, such as Windows, Linux, etc., this function is implemented to return '\n' when the user pressed Enter. For Comparison, on Windows the key-press itself (of Enter) might be represented as the key-code VK_ENTER.
PDCurses is translating the key codes to ASCII values for you.
You can get the key values you want if you first call the PDCurses functions raw(); nonl();. Also, you should probably use wgetch() for new code.
KEY_ENTER == 0x157, '\n' == 0xA
'\n' is the standard ASCII newline, while KEY_ENTER represents a keyboard code. See the PDCurses code.
For more information, you should post the relevant part of your code.