Does GetKeyState generate input message? - c++

const int KEY_0 = 0x30;
void main() {
byte keyState[256];
ZeroMemory(keyState, sizeof(byte) * 255);
byte pressed = (keyState[KEY_0] & 0x80);
while (pressed == false)
{
ZeroMemory(keyState, sizeof(byte) * 255);
//GetKeyState(0); // with this line, works well. It makes GetKeyboardState(KEY_0) works.
//GetAsyncKeyState(KEY_0);
GetKeyboardState(keyState);
pressed = (keyState[KEY_0] & 0x80);
};
}
I have learn that this code does not work because GetKeyboardState() get values generated after a keyboard message is processed. As no keyboard message is generated, the loop will not stop. That is what I understand.
And MSDN says:
An application calls GetKeyState in response to a keyboard-input message. This function retrieves the state of the key when the input message was generated.
I'm confused, as the upper code with GetKeyState(0); works well, which means GetKeyState() makes a message about the keyboard?
How can I understand GetKeyState() and GetKeyboardState()?

Related

The contradiction on the return values of PostMessageA and WM_MOUSEMOVE

I want to post WM_MOUSEMOVE message using Windows api PostMessageA. In the microsoft document on WM_MOUSEMOVE, it says:
If an application processes this message, it should return zero.
And in the one on PostMessageA, it says:
If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To get extended error information, call GetLastError. GetLastError returns ERROR_NOT_ENOUGH_QUOTA when the limit is hit.
Aren't they contradictory? In my program, I wrote these codes:
// ...
// mainGameWnd is the handle on the main window
// wParamRawMouse = 0, which indicates no mouse button was pressed
// _mouse_position.x and _mouse_position.y are LONG type
if ((PostMessageA(mainGameWnd, WM_MOUSEMOVE, wParamRawMouse, MAKELPARAM(_mouse_position.x, _mouse_position.y))) == 0);
{
// error logging
LogError("post message in Mouse move failed. Error: %ld", GetLastError());
}
In the log file, I found this line:
[Error]: post message in Mouse move failed. Error: 0
What exactly the meaning of the returned "0" ? Did it mean PostMessageA failed and I should check the parameters sent into it or just the message was processed successfully and I needed do nothing?
Appendix
About the LogError
// global: FILE* logFile = stdout;
// lastLog is enum
void Log(LogCategory level, LPCSTR format, bool append, va_list args)
{
lastLog = level;
if (!(LogFlag & (1 << level)))
return;
if (logEventFunc)
{
if (!logEventFunc(level, format, append, args))
return;
}
if (!append)
{
time_t rawtime;
char pblgtime[128] = { 0 };
time(&rawtime);
switch (level)
{
case Log_Error: strftime(pblgtime, 128, "%Y-%m-%d %X [Error]: ", localtime(&rawtime)); break;
}
fprintf(logFile, pblgtime);
}
vfprintf(logFile, format, args);
fflush(logFile);
}
void LogError(LPCSTR format, ...)
{
va_list args;
va_start(args, format);
Log(Log_Error, format, false, args);
va_end(args);
}
In the log file, I found this line:
[Error]: post message in Mouse move failed. Error: 0
What exactly the meaning of the returned "0" ?
Nothing. You have an erroneous ; on the end of your if statement, so it doesn't matter what value PostMessageA() returns, because LogError() will be called unconditionally and be passed an indeterminate GetLastError() value, which just happened to be 0.
You need to get rid of that ;:
if (PostMessageA(mainGameWnd, WM_MOUSEMOVE, wParamRawMouse, MAKELPARAM(_mouse_position.x, _mouse_position.y)) == 0)
{
// error logging
LogError("post message in Mouse move failed. Error: %ld", GetLastError());
}
Now, with that said:
Did it mean PostMessageA failed and I should check the parameters sent into it or just the message was processed successfully and I needed do nothing?
With proper error checking in place, a return value of 0 means that PostMessageA() itself failed. The message's return value is NOT returned to you. Only the SendMessage....() functions can do that.
PostMessage is asynchronous. It can only enqueue a message to the thread of the HWND. A successful return value form PostMessage indicates that the message was queued, not serviced or handled. So there's no return value from the handler to give back to the caller.
PostMessage can really only fail when:
The hwnd is invalid
There is no message queue associated with the given thread where the message is intended for (which is nearly impossible if you have an HWND)
The queue is full
SendMessage is synchronous and will return the result of the message handler for the given hwnd/msg pair. It invokes the wndproc message handler directly (or waits between threads for it to return) and delivers the return value back to the caller.
I'm not sure what you are really trying to do, but consider this:
Do you really need the return value from either PostMessage, SendMessage, or the associated handler?
Posting a WM_MOUSEMOVE is a weird thing to do. It doesn't actually move the mouse cursor. It just notifies the app that the mouse cursor moved (if it's interested in listening for that event). At the actual system level, many mouse messages are neither posted nor sent. They are generated on the fly as a result of the thread invoking GetMessage and observing the mouse position state has changed since the last call.

Sampling keyboard input at a certain rate in C++

What I want to do is sampling the keyboard input at a certain rate (e.g. 10-20 Hz). I use a while loop that read from stdin (I use read because I want to read asynchronously, e.i. I don't want to press enter every time) and then I have a pause before a new cycle starts to keep the sampling frequency stable.
The user press left/right arrow to give a command (to a robot). If nothing is pressed, the output is 0.
The problem is that, during the pause, the stdin buffer is written (I suppose), and so the read will return an old input. The final result is that the output is delayed. So if I press left the output immediately change to 1, but when I release it takes some seconds to return to 0. I want to remove this delay.
My aim is to sample just the more recent key pressed, in order to synchronize user input and output command without delays. Is there a way? Thank you in advance.
This is the method I'm using:
void key_reader::keyLoop()
{
char c;
bool dirty = false;
int read_flag;
// get the console in raw mode
tcgetattr(kfd, &cooked);
memcpy(&raw, &cooked, sizeof(struct termios));
raw.c_lflag &= ~(ICANON | ECHO);
// Setting a new line, then end of file
raw.c_cc[VEOL] = 1;
raw.c_cc[VEOF] = 2;
tcsetattr(kfd, TCSANOW, &raw);
//FD_ZERO(&set); /* clear the set */
//FD_SET(kfd, &set); /* add our file descriptor to the set */
//timeout.tv_sec = 0;
//timeout.tv_usec = 10000;
if (fcntl(kfd, F_SETFL, O_NONBLOCK) == -1)
{
perror("fcntl:"); // an error accured
exit(-1);
}
puts("Reading from keyboard");
puts("---------------------------");
puts("Use arrow keys to move the turtle.");
ros::Rate r(10);
while (ros::ok())
{
read_flag = read(kfd, &c, 1);
switch (read_flag)
{
case -1:
// case -1: is empty and errono
// set EAGAIN
if (errno == EAGAIN)
{
//no input yet
direction = 0;
break;
}
else
{
perror("read:");
exit(2);
}
// case 0 means all bytes are read and EOF(end of conv.)
case 0:
//no input yet
direction = 0;
break;
default:
ROS_DEBUG("value: 0x%02X\n", c);
switch (c)
{
case KEYCODE_L:
ROS_DEBUG("LEFT");
direction = 1;
dirty = true;
break;
case KEYCODE_R:
ROS_DEBUG("RIGHT");
direction = -1;
dirty = true;
break;
}
}
continuos_input::input_command cmd;
cmd.type = "Keyboard";
cmd.command = direction;
cmd.stamp = ros::Time::now();
key_pub.publish(cmd);
r.sleep();
}
}
I feel that the issue is with your subscriber rather than publisher. I can see that you have used rate to limit the publishing rate to 10Hz. Do confirm the publishing rate using Topic Monitor in rqt. Also setting a lower queue size for the publisher might help. Can't give a more definitive answer without referring to your subscriber node.

How to handle pasted text correctly via GetConsoleInput()?

In Windows console, we can use GetConsoleInput() to get raw keyboard (and more) input. I want to use it to implement a custom function that read keystrokes with possible CTRL, SHIFT, ALT status. A simplified version of the function is
// for demo only, no error checking ...
struct ret {
wchar_t ch; // 2-byte UTF-16 in Windows
DWORD control_keys;
};
ret getch() {
HANDLE in = GetStdHandle(STD_INPUT_HANDLE);
INPUT_RECORD buf;
DWORD cnt;
for (;;) {
ReadConsoleInput(in, &buf, 1, &cnt);
if (buf.EventType != KEY_EVENT)
continue;
const KEY_EVENT_RECORD& rec = buf.Event.KeyEvent;
if (!rec.bKeyDown)
continue;
if (!rec.uChar.UnicodeChar)
continue;
return { rec.uChar.UnicodeChar,rec.dwControlKeyState };
}
}
It works fine, except that when I try to paste character not representable in 2 bytes in UTF-16, the UnicodeChar field is 0 when bKeyDown==true, and the UnicodeChar field is the pasted content when bKeyDown==false. Can anyone tell why it is the case and suggest possible workarounds?
Here is some demo code and result.

Serial.read() skips over serial input

Trying to send serial messages using Arduino Uno and standard IDE. Ran into issue parsing the serial message sent to the device.
See that if I include this line Serial.println("Serial.available() = " + String(Serial.available())); I will be able to read the rest of the message. If this is commented out I will only see the first letter of the message and skip over the rest. Attached image of output that I'm seeing with and without the added line of code.
// the setup routine runs once when you press reset:
void setup() {
// initialize serial communication at 9600 bits per second:
Serial.begin(9600);
while (!Serial) {} // wait for serial to be initialized
Serial.println("Setup called. Serial port ready.");
Serial.println("Waiting for time sync message...");
while (!Serial.available()) {}
processSyncMessage();
}
void processSyncMessage() {
// parse first letter of message
char messageHeader = (char) Serial.read();
switch (messageHeader) {
case TIME_HEADER:
// do processing
break;
default:
Serial.println("Unknown message sent with header: " + String(messageHeader));
// must include this line in order to see the entire message sent
// just calling a println or a Serial.available() doesn't work ????
Serial.println("Serial.available() = " + String(Serial.available()));
Serial.println("---start of message");
for (int r = 0; r != -1; r = Serial.read()) {
Serial.print((char) r);
}
Serial.println();
Serial.println("---end of message");
break;
}
}
Missing Buffer
With printout
Is this somehow related to a buffer? Can I flush it somehow with fflush(SOME_SECRET_BUFFER)?
have you tried Serial.readString() to parse the entire missing characters?
Serial data is transmitted and received one character at a time. At 9600 baud, the transmission rate is approximately one character per millisecond.
The code assumes that once the first character has arrived, all of them have. This is not the case. The addition of the println consumes CPU time, and therefore has the effect of adding a delay. This delay allows the rest of the original message to be received.
A receive function with an appropriate timeout for your application is needed here.

How do I write multiple GetAsyncKeyState with C++

My problem is where can I add this line of code:
if( GetKeyState(VK_F2) & 0x8000 )
I tried in different ways, but when I compile and run it and press the F1 or F2 key it executes all the functions. I want to call the F1 key functions when the key is pressed and F2 key when it is pressed. I am using Visual Studio 2010 Express.
Here is my code:
switch(uMsg)
{
case WM_INITDIALOG:
{
// do something here
break;
}
case WM_TIMER:
{
if( GetKeyState(VK_F1) & 0x8000 )
if( GetKeyState(VK_F2) & 0x8000 )
{
// do something here
}
break;
}
case WM_CLOSE:
{
// do something here
}
}
return 0;
SOLVED:) well my problem is solved after trying for sometime finally i got it the problem
was that little "break;" statement please look at the code its working flawless.
Thank you so very much for your time and help appreciated
case WM_TIMER:
{
if(GetKeyState(VK_F1) & 0x8000 )
{
MessageBoxA (NULL, TEXT ("This is a call from F1 key!"), TEXT("Test F1 key"), MB_OK );
}
//break; << this was the one that was giving me the problem
if(GetKeyState(VK_F2) & 0x8000 )
{
MessageBoxA (NULL, TEXT ("This is a call from F2 key!"), TEXT("Test F2 key"), MB_OK );
}
//if(GetKeyState(VK_F3) & 0x8000 ) << i can add multi VK_ keys here
break; // << should be here
}
case WM_CLOSE:
A couple points:
Are you sure you want to poll like this? Maybe you want to be responding to notifications when the user presses these keys (WM_KEYDOWN for example) instead of polling periodically? Your code has the problem that it can easily miss if you press & release F1 between WM_TIMERs.
You should probably be using GetKeyState, as Joachim Pileborg says. GetAsyncKeyState works on the state of the keyboard at the time of the call; GetKeyState works on the state of the keyboard when the current message was sent. This tends to keep things more tightly synchronized. That said, if you're polling in WM_TIMER, it probably doesn't matter so much.
You are only checking if the return value is non-zero, which is not how this function works. The return value is a bitmask. From the documentation:
If the high-order bit is 1, the key is down; otherwise, it is up.
If the low-order bit is 1, the key is toggled. A key, such as the CAPS LOCK key, is toggled if it is turned on. The key is off and untoggled if the low-order bit is 0. A toggle key's indicator light (if any) on the keyboard will be on when the key is toggled, and off when the key is untoggled.
Thus, to check for F1:
if( GetKeyState(VK_F1) & 0x8000 )
{
...
}