No console key up event while shift key is pressed - c

I have a piece of code that will read a key event from the console using the ReadConsoleInput function. It works mostly, except that it fails to read when a button is released while the shift key is pressed.
I wrote the most minimal example code I could. What it does right now is reads whether the 'a' key is pressed or not and displays it to the screen. If you run it and press 'a' you get
41[down]
41[up]
if you run it and hold down the shift key before pressing 'a', all you get is
41[down]
and you will not get a key up event until you release the shift key and press 'a' again.
Here is my code:
#include <stdlib.h>
#include <stdio.h>
#include <Windows.h>
#include <Tchar.h>
int main()
{
HANDLE rhnd = GetStdHandle(STD_INPUT_HANDLE);
while(1)
{
INPUT_RECORD buf[128];
DWORD Events = 0;
DWORD EventsRead = 0;
GetNumberOfConsoleInputEvents(rhnd, &Events);
if(Events == 0)continue;
int i;
for(i=0;i<sizeof(buf);++i)//clear buf in case ReadConsoleInput doesn't do it for me, probably unnecessary
((char *)buf)[i]=0;
ReadConsoleInput(rhnd, buf, 128, &(EventsRead));
for(i=0;i<128;++i)//I would just loop while i<EventsRead but this ensures there are not extra elements (a little paranoid, I know)
{
if(buf[i].EventType == KEY_EVENT && (buf[i].Event.KeyEvent.wVirtualKeyCode & 0xff) == 0x41 /*keycode for 'a' button -- you can remove this condition to see the results for all key presses*/)
{
printf("%x",buf[i].Event.KeyEvent.wVirtualKeyCode);
if(buf[i].Event.KeyEvent.bKeyDown)
{
printf("[down]\n");
}
else //if this else gets executed it's what I'm calling a key up event
//this conditional should only be reached if either 'a' is pressed or 'a' was just released
//and the else should only be executed if it was just released
{
printf("[up]\n");
}
}
}
}
}
Any ideas on why this is happening and how to fix it
Compiled on windows 10 using gcc (MinGW-64) and also using Visual Studio 15

Related

C xtest emitting key presses for every Unicode character

I wanted to make a program to simulate key presses. I think i am mostly done but i have done something wrong i guess because it is not doing what i expect it to do. I have made a small example program to illustrate the issue. The main problem is that if i want to generate capital letters it does not work with strings like 'zZ'. It is generating only small letters 'zz'. Although symbols like '! $ & _ >' etc. work fine (that require shift on my German keyboard layout) and even multi byte ones like 'πŸ’£' . What i am doing is this:
preamble:
So basically the main problem by emulating key presses is first the layout that changes from user to user and most importantly modifier keys. So if you go the naive route and get a keysym with XStringToKeysym() get a keycode from that keysym with XKeysymToKeycode() and fire that event its not working like most 'newcomers' would expect (like me). The problem here is, that multiple keysyms are mapped to the same keycode. Like the keysysm for 'a' and 'A' are mapped to the same keycode because they're on the same physikal button on your keyboard that is linked to that keycode. So if you go the route from above you end up with the same keycode although the keysyms are different but mapped to the same button/keycode. And there is usually no way around this because it is not clear how the 'A' came to existence in the first place. shift+a or caps+a or you have a fancy keyboard with an 'a' and 'A' button on it. The other problem is how do i emit key presses for buttons that are not even on the keyboard of that person running that application. Like what key is pressed on an english layout if i want to type a 'Γ„' (german umlaut). This does not work because XKeysymToKeycode() will not return a proper keycode for this because there is no keysym mapping for it with that layout.
my approach:
What i am tying to do to circumvent this is finding a keycode that is not being used. You have 255-8 keycodes at your disposal but a regular keyboard has only ~110 keys on it so there is usually some space left. I am trying to find one of those keycodes that are unmapped on the current layout and use it to assign my own keysyms on it. Then i get a keysym from my char i got by iterating over my string and pass it to XStringToKeysym() which gives me the appropriate keysym. In case of β€™πŸ’£β€™ that is in most cases not mapped to any keyboard layout i know of. So i map it to the unused keycode and press it with XTestFakeKeyEvent() and repeat that for every char in the string. This works great with all fancy glyph one can think of but it does not work with simple letters and i really don't know why :( in my debugging sessions keysyms and keycodes seem to be correct its just that XTestFakeKeyEvent() does not do the right things in that case. Its possible that i fucked something up at the keymapping part but i am not really sure whats the problem here and i hope someone has a good idea and can help me find a way to a working solution.
I am just using this unicode notation in the strings array because i don't want to deal with this in the example here. Just assume there is code producing this from an arbitrary input string.
be aware that the code below can ruin your keymapping in such a way that you're not able to type and use your keyboard anymore and need to restart your X-Server/PC ... i hope it does not in its current state (working fine here) just be aware if you fiddle with the code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/extensions/XTest.h>
#include <unistd.h>
//gcc -g enigo2.c -lXtst -lX11
int main(int argc, char *argv[])
{
Display *dpy;
dpy = XOpenDisplay(NULL);
//my test string already transformed into unicode
//ready to be consumed by XStringToKeysym
const char *strings[] = {
"U1f4a3",// πŸ’£
"U007A", //z
"U005A", //Z
"U002f", //'/'
"U005D", //]
"U003a", //:
"U002a", //*
"U0020", //' '
"U0079", //y
"U0059", //Y
"U0020", //' '
"U0031", //1
"U0021", //!
"U0020", //' '
"U0036", //6
"U0026", //&
"U0020", //' '
"U0034", //4
"U0024", //$
"U0020", //' '
"U002D", //-
"U005F", //_
"U0020", //' '
"U003C", //<
"U003E", //>
"U0063", //c
"U0043", //C
"U006f", //o
"U004f", //O
"U00e4", //Γ€
"U00c4", //Γ„
"U00fc", //ΓΌ
"U00dc", //Ü
};
KeySym *keysyms = NULL;
int keysyms_per_keycode = 0;
int scratch_keycode = 0; // Scratch space for temporary keycode bindings
int keycode_low, keycode_high;
//get the range of keycodes usually from 8 - 255
XDisplayKeycodes(dpy, &keycode_low, &keycode_high);
//get all the mapped keysyms available
keysyms = XGetKeyboardMapping(
dpy,
keycode_low,
keycode_high - keycode_low,
&keysyms_per_keycode);
//find unused keycode for unmapped keysyms so we can
//hook up our own keycode and map every keysym on it
//so we just need to 'click' our once unmapped keycode
int i;
for (i = keycode_low; i <= keycode_high; i++)
{
int j = 0;
int key_is_empty = 1;
for (j = 0; j < keysyms_per_keycode; j++)
{
int symindex = (i - keycode_low) * keysyms_per_keycode + j;
// test for debugging to looking at those value
// KeySym sym_at_index = keysyms[symindex];
// char *symname;
// symname = XKeysymToString(keysyms[symindex]);
if(keysyms[symindex] != 0) {
key_is_empty = 0;
} else {
break;
}
}
if(key_is_empty) {
scratch_keycode = i;
break;
}
}
XFree(keysyms);
XFlush(dpy);
usleep(200 * 1000);
int arraysize = 33;
for (int i = 0; i < arraysize; i++)
{
//find the keysym for the given unicode char
//map that keysym to our previous unmapped keycode
//click that keycode/'button' with our keysym on it
KeySym sym = XStringToKeysym(strings[i]);
KeySym keysym_list[] = { sym };
XChangeKeyboardMapping(dpy, scratch_keycode, 1, keysym_list, 1);
KeyCode code = scratch_keycode;
usleep(90 * 1000);
XTestFakeKeyEvent(dpy, code, True, 0);
XFlush(dpy);
usleep(90 * 1000);
XTestFakeKeyEvent(dpy, code, False, 0);
XFlush(dpy);
}
//revert scratch keycode
{
KeySym keysym_list[] = { 0 };
XChangeKeyboardMapping(dpy, scratch_keycode, 1, keysym_list, 1);
}
usleep(100 * 1000);
XCloseDisplay(dpy);
return 0;
}
When you send a single keysym for a given keycode to XChangeKeyboardMapping and it is a letter, it automatically fills correct upper and lower case equivalents for shift and capslock modifiers. That is, after
XChangeKeyboardMapping(dpy, scratch_keycode, 1, &keysym, 1);
the keycode map for scratch_keycode effectively changes (on my machine) to
tolower(keysym), toupper(keysym), tolower(keysym), toupper(keysym), tolower(keysym), toupper(keysym), 0, 0, 0, 0, ...
In order to inhibit this behaviour, send 2 identical keysyms per keycode:
KeySym keysym_list[2] = { sym, sym };
XChangeKeyboardMapping(dpy, scratch_keycode, 2, keysym_list, 1);
This will fill both shifted and unshifted positions with the same keysym.

Why does an empty printf allow me to continue reading data from the stdin?

CODE
while (1)
{
keycode = key_hook();
if (keycode == SPACE || keycode == BKSPACE)
{
render_again = 1;
}
if (keycode == ESC)
break;
if (render_again)
{
render_again = 0;
render(all);
}
dprintf(1, ""); //I have no idea why this prevents the program from freezing
}
int key_hook()
{
char buffer[4];
read(0, buffer, 4);
return (*(unsigned int *)buffer);
}
Alright, so this piece of code handles redrawing of text on screen. Some rows of text are underlined or highlighted using termcaps (tputs(tgetstr("us, NULL")......). Everything prints fine but after the first redraw of the text the while apparently freezes unless a dprintf/printf is present. The key_hook function just reads 4 bytes from the stdin and converts them to an int.
When I last did work here, my version of key_hook had a loop of single byte reads. This was broken by an alarm of 1 second and logic to whether the data so far was a key prefix.
The alarm interrupted the read, and stopped freeze

Compiler not Recognizing Control Keys like Return key in C

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main()
{
char b;
// the loop is executed until the "Return key" or "Enter" is pressed by the user
while(b!='\n')
{
b=getch();
putch('*');
}
return 0;
}
The program is something like typing password.As you press alphabets the output displays successive "*"s.
Until you press Return key and the program gets finished.
My problem is that my compiler(Codeblocks 13.12-->GNU GCC) doesn't understand the control keys like Return.Even when I replace '\n' with the ASCII code 10(the concerning ASCII code for Return key) the program makes a mistake again.The mistake is to continue displaying "*"s even when Return key is pressed!
What's going on with the compiler and how it 'll be fixed?
Try using
/* 13 refers to '\r' (carriage return) */
while(b != 13) {
//Code
}

Issues with repeated key checking with getch()

I am having issues with repeating key checking using a function that utilizes getch().
Here is a code example:
static char g_keybuffer[256];
_Bool IsKeyDown(char c)
{
char ch;
if(kbhit())
ch = getch();
if(ch == -32 || ch == 224)
{
ch = getch();
}
g_keybuffer[ch] = 1;
if(g_keybuffer[c] == 1)
{
g_keybuffer[c] = 0;
return 1;
}
return 0;
}
/*
*
*/
int main(int argc, char** argv) {
while(1)
{
if(IsKeyDown('a'))
{
printf("Test\n");
}
if(IsKeyDown('a'))
{
printf("Hello\n");
}
else if(IsKeyDown('b'))
{
printf("World\n");
}
Sleep(100);
}
return (EXIT_SUCCESS);
}
I know why the problem occurs. When a key is pressed, kbhit is true once per loop, and sets ch to the character retrieved from the buffer. When IsKeyDown is used, if it is equal to the parameter, the key in the buffer g_keybuffer is set equal to zero to avoid having a key be "down" infinitely. The problem with this is if you want to check if the same key is down more than once, only the first instance of IsKeyDown will be ran, with the rest being invalid due to the g_keybuffer of the key now being 0.
Does anyone know how I can change IsKeyDown to give it the ability to check the same key multiple times per looping? I'm stuck.
Your problem is because you are setting g_keybuffer[c] to 0 after you get a hit for the key state. I'm guessing you have done this to avoid getting the same result twice - but that is just a workaround. The only way to do what you want to do properly is to choose a library that is actually made to capture the keyboard state.
Most graphics libraries have functions for capturing keyboard states. I don't know of any solutions thought that don't involve a little overhead if you are just writing a small program.

How to pause a loop in C/C++

I am trying to make a screen for a car game and make the screen wait for a key to go into the next screen, thing is that with this code it changes colors too fast. I've already tried delay() and sleep() which haven't worked properly. Also, after hitting a key, it closes and doesn't wait for me to enter a key. I just want the title to blink between white and red until a key is hit, and get to know why it exits after hitting a key.
Here is my code:
#include <dos.h>
#include <graphics.h>
#include <stdlib.h>
#include <stdio.h>
#include <conio.h>
int main(void)
{
int gdriver = DETECT, gmode, errorcode;
initgraph(&gdriver, &gmode, "C|\\BORLANDC\\BGI");
outtextxy(250,280,"POINTER DRIVER 1.0");
outtextxy(250,290,"LCCM 10070249");
do
{
setcolor(WHITE);
outtextxy(250,380,"PRESS ANY KEY TO CONTINUE");
// delay(10); nothing works here :(
setcolor(RED);
outtextxy(250,380,"PRESS ANY KEY TO CONTINUE");
} while(!kbhit());
cleardevice();
outtextxy(250,290,"HELLO"); //here it draws mega fast and then exits
getch();
closegraph();
return 0;
}
Instead of using delay(10), maybe try using some sort of timer variable to do this. Try something like the following (a modification of your do-while loop):
unsigned flashTimer = 0;
unsigned flashInterval = 30; // Change this to vary flash speed
do
{
if ( flashTimer > flashInterval )
setcolor(RED);
else
setcolor(WHITE);
outtextxy(250,380,"PRESS ANY KEY TO CONTINUE");
++flashTimer;
if ( flashTimer > flashInterval * 2 )
flashTimer = 0;
// Remember to employ any required screen-sync routine here
} while(!kbhit());
kbhit() returns true if there's a character in the buffer, but doesn't remove the character before it returns. Once you reach the getch() line, it takes the first key that you pressed to break out of the while loop.
Possible solution: While it's a bit hacky, adding a getch() right after your while loop would probably fix it.
May I also suggest using ncurses instead of those Borland libraries?

Resources