Get any key from keyboard in C++ including keys like control - c++

I'm programming in C++ and have run into a wall.
I need to get input from the keyboard. The problem is that I also need to get input from keys like control, scroll lock, windows key, etc. I also need to be able to differentiate between the numpad and regular numbers 0-9.
I tried using _getch(). While it can get keys like arrow keys and the numpad, I can't get keys like control, shift and scroll lock.
Does anyone have any suggestions?

There is no standard way to do this because C++ does not assume the system even has all those things.
A good solution for what you are trying to do is the SDL library. Look here:
https://www.libsdl.org/

I see the word "windows key" so I'm assuming you're programming for Windows
Use WinAPI ReadConsoleInput
HANDLE hInput = GetStdHandle(STD_INPUT_HANDLE);
INPUT_RECORD ir;
DWORD read;
if (!ReadConsoleInput(hInput, &ir, 1, &read) || read == 0) {
// Something went wrong
}
if (ir.EventType == KEY_EVENT) {
// Do stuff here
}
Refer to KEY_EVENT_RECORD for more information. You can get control keys states from
ir.Event.KeyEvent.dwControlKeyState
This is an example provided by Microsoft.

Related

Detecting keyboard hotkeys when DirectInput DIK constants fail

I want to assign tasks and functions to the additional keys of my keyboard (e.g. Mute,VolumeChange, Browser,...). Now, I do know that DirectInput implements a full list of those keys like DIK_MUTE (msdn link). Unluckily, none of the keys are assigned to those values and obviously every key pressed is recognized as No. 128 by DirectInput.
But Windows seems to have no problem distincting between those keys as some of them are functional and for instance open applications. Is there a way to tweak this issues with or without DirectInput so that i can detect those keys also in fullscreen DX/OpenGL applications?
IDirectInputDevice8* device;
BYTE arrKey[256] = {0};
if FAILED(device->GetDeviceState(sizeof(BYTE)*256,arrKey))
return false;
BYTE byKey = ReportPressedKey(arrKey, sizeof(BYTE*)*256);
// byKey = 128 (DIK_MUTE, DIK_VOLUMEUP,DIK_NEXTTRACK,...)

Unechoed string input in C++

I am writing a program in C++ where I am supposed to receive a string from user without displaying it on screen (for example: apassword). I tried using cin and gets to accept the string. But both will echo the characters entered by user in console.
So is there any function or any other way of doing it in C++?
How to avoid that data being read via cin shows up on the console depends very much on the console; it's certainly operating system dependant.
On Windows, you can use the SetConsoleMode function to enable/disable the echo for any file handle, including the standard input handle.
Something like
void enableStdinEcho( bool b ) {
HANDLE hStdin = ::GetStdHandle( STD_INPUT_HANDLE );
DWORD mode = 0;
::GetConsoleMode( hStdin, &mode );
if ( b ) {
mode |= ENABLE_ECHO_INPUT;
} else {
mode &= ~ENABLE_ECHO_INPUT;
}
::SetConsoleMode( hStdin, mode );
}
could probably be used to toggle the echo on stdin.
The C++ standard does not define a mechanism to do this. You have to rely on a platform specific library. For example with gcc/glibc use getpass
http://www.gnu.org/software/libc/manual/html_mono/libc.html#getpass
There might be other libraries that abstract these functions and provide a platform independent wrapper.
This is not a C++, iostream etc. question at all - it's specific to the terminal you're using.
See this question for ideas, and then ask a question specific to your terminal if it isn't covered there and you can't use ncurses.

Handling keyboard input in win32, WM_CHAR or WM_KEYDOWN/WM_KEYUP?

So in the text editor program that i've been working on, I've used WM_CHAR to process input from the keyboard. However, I found that some of the character mesages are not recorded. For example, if I use [shift]+ number key to type a symbol such as % or &, some re recorded while others such as [shift]+9 (which results in ')'), are not recorded. So, I'm wondering if I should use WM_KEYDOWN/WMKEYUP pair to handle keyboard input. I once wrote a keylogger in assembly(actually it was just a tutorial that i was trying out) and had used WM_KEYDOWN/WM_KEYUP pairs and that worked out quite good. So, should I move on to this, or is it something unusual that is happening with my program?
Thanks,
Devjeet
This is really a long reply to your comment above, but putting it in an answer because it's too long for a comment :)
The core issue to understand here is that keys and characters are not quite the same thing. Some (but not all) keys generate characters; some keys generate different characters depending on shift or other keyboard state. And to implement an editor, you need to handle both textual input and also non-textual keyboard input like arrow keys. Now the long-winded version, picking off from what seems to be an incorrect assumption:
Apparently, windows works in really strange ways. [...] It seems that when you press [shift]+9, windows sends a VK_LEFT in the wParam of message WM_CHAR
Sounds like you might be mixing two things up here. The thing with WM_CHAR is that it gives you character codes for textual characters: so if someone presses the 9 key, you'll get '9'. If someone presses SHIFT+9, Windows will take the shift state into account - and you get '(' (if using US keyboard). But you won't ever get a WM_CHAR for arrow keys, HOME, END, and so on, since they are not textual characters. WM_KEYDOWN, on the other hand, does not deal in characters, but in VK_ codes; so pressing 9 gives you VK_9 regardless of shift state; and left arrow gives you VK_LEFT - again regardles of shift state.
The things is that WM_CHAR and WM_KEYDOWN both give you two parts to the overall input picture - but you really have to handle both to get the full picture. And have to be aware that the wParam is a very different thing in both cases. It's a character code for WM_CHAR, but a VK_ code for WM_KEYDOWN. Don't mix the two.
And to make things more confusing, VK_ values share the same values as valid characters. Open up WinUser.h (it's in the include dir under the compiler installation dir), and look for VK_LEFT:
#define VK_LEFT 0x25
Turns out that 0x25 is also the code for the '%' character (see any ascii/unicode table for details). So if WM_CHAR gets 0x25, it means shift-5 was pressed (assuming US keyboard) to create a '%'; but if WM_KEYDOWN gets 0x25, it means left arrow (VK_LEFT) was pressed. And to add a bit more confusion, the Virtual Key codes for the A-Z keys and 0-9 keys happen to be the same as the 'A'-'Z' and '0'-'9' characters - which makes it seem like chars and VK_'s are interchangable. But they're not: the code for lower case 'a', 0x61, is VK_NUMPAD1! (So getting 0x61 in WM_CHAR does mean 'a', getting it in WM_KEYDOWN means NUMPAD1. And if a user does hit the 'A' key in unshifted state, what you actually get is first a VK_A (same value as 'A') in WM_KEYDOWN, which gets translated to WM_CHAR of 'a'.)
So tying all this together, the typical way to handle keyboard is to use all of the following:
Use WM_CHAR to handle textual input: actual text keys. wParam is the character that you want to append to your string, or do whatever else with. This does all the shift- processing for you.
Use WM_KEYDOWN to handle 'meta' keys - like arrow keys, home, end, page up, and so on. Pass all the A-Z/0-9 values through, the default handling will turn them into WM_CHARs that you can handle in your WM_CHAR handler. (You can also handle numpad keys here if you want to use them for special functionality; otherwise they 'fall through' to end up as numeric WM_CHARs, depending on numlock state. Windows takes care of this, just as it handles shift state for the alphabetic keys.)
If you want to handle ALT- combos explicitly (rather than using an accelerator table), you'll get those via WM_SYSKEYDOWN.
I think there are some keys that might show up in both - Enter might show up as both a WM_KEYDOWN of VK_RETURN and as either \r or \n WM_CHAR - but my preference would be to handle it in WM_KEYDOWN, to keep editing key handling separate from text keys.
Spy++ will show you the messages being sent to a window, so you can experiment and see what messages are appropriate for your application.
If you have Visual Studio installed, it should be in your Start menu, under Programs -> Microsoft Visual Studio -> Visual Studio Tools -> Spy++.
WM_CHAR
WM_KEYDOWN
The helpful message above inspired me to create this snippet, which gives you a human-readable indication of what key was pressed from any WM_KEYDOWN/WM_KEYUP/WM_SYSKEYDOWN/WM_SYSKEYUP independent of the state of the modifier keys.
// get the keyboard state
BYTE keyState[256];
GetKeyboardState(keyState);
// clear all of the modifier keys so ToUnicode will ignore them
keyState[VK_CONTROL] = keyState[VK_SHIFT] = keyState[VK_MENU] = 0;
keyState[VK_LCONTROL] = keyState[VK_LSHIFT] = keyState[VK_LMENU] = 0;
keyState[VK_RCONTROL] = keyState[VK_RSHIFT] = keyState[VK_RMENU] = 0;
// convert the WM_KEYDOWN/WM_KEYUP/WM_SYSKEYDOWN/WM_SYSKEYUP to characters
UINT scanCode = (inLParam >> 16) & 0xFF;
int i = ToUnicode(inWParam, scanCode, keyState, outBuf, inOutBufLenCharacters, 0);
outBuf[i] = 0;
By modifying the keyState array so that all the modifier keys are clear, ToUnicode will always output the unshifted key you pressed. (So, on the English keyboard you'll never get '%' but always '5') as long as it's a human readable key. You still have to do the VK_XXX checking to sense the arrow and other non-human readable keys however.
(I was trying to rig up a user editable "hot key" system in my app, and the distinction between WM_KEYXXX and WM_CHAR was making me nuts. The code above solved that problem.)

Checking if a registry key exists

I am looking for a clean way to check if a registry key exists. I had assumed that RegOpenKey would fail if I tried to open a key that didn't exist, but it doesn't.
I could use string processing to find and open the parent key of the one I'm looking for, and then enumerate the subkeys of that key to find out if the one I'm interested in exists, but that feels both like a performance hog and a weird way to have to implement such a simple function.
I'd guess that you could use RegQueryInfoKey for this somehow, but MSDN doesn't give too many details on how, even if it's possible.
Update: I need the solution in Win32 api, not in managed code, .NET or using any other library.
The docs in MSDN seem to indicate that you should be able to open a key for read permission and get an error if it doesn't exist, like this:
lResult = RegOpenKeyEx (hKeyRoot, lpSubKey, 0, KEY_READ, &hKey);
if (lResult != ERROR_SUCCESS)
{
if (lResult == ERROR_FILE_NOT_FOUND) {
However, I get ERROR_SUCCESS when I try this.
Update 2: My exact code is this:
HKEY subKey = nullptr;
LONG result = RegOpenKeyEx(key, subPath.c_str(), 0, KEY_READ, &subKey);
if (result != ERROR_SUCCESS) {
... but result is ERROR_SUCCESS, even though I'm trying to open a key that does not exist.
Update 3: It looks like you guys are right. This fails on one specific test example (mysteriously). If I try it on any other key, it returns the correct result. Double-checking it with the registry editor still does not show the key. Don't know what to make of all that.
First of all don't worry about performance for stuff like this. Unless you are querying it 100x per sec, it will be more than fast enough. Premature optimization will cause you all kinds of headaches.
RegOpenKeyEx will return ERROR_SUCCESS if it finds the key. Just check against this constant and you are good to go.
RegOpenKey does return an error if the key does not exist. How are you using it? The expected return value is ERROR_FILE_NOT_FOUND.
From your code:
HKEY subKey = nullptr;
LONG result = RegOpenKeyEx(key, subPath.c_str(), 0, KEY_READ, &subKey);
if (result != ERROR_SUCCESS) {
I would look at the value of key and subPath and make sure they are what you expect, and that the key does not actually exist. What is the value of subKey afterwards? It is obviously opening something - try enumerating it to see what the keys and values under it are.
There is no issue with RegOpenKey not returning an error if the key does not exist - I would not try to assume there is some kind of weird OS bug in something as commonly used as the registry.
Maybe you have a registry key that is not visible to you, the user that is running the registry editor, but not to your code? A permissions problem perhaps? Is your code running as an elevated user in windows Vista or server 2008? Did you try running the registry editor as administrator?
Note that beside the "core" Registry functions that start with "Reg" there are also helper functions starting with "SHReg". These are intended for use by the Shell i.e. Explorer but are documented and can be used in normal applications too. They're typically thin wrappers that make some common tasks easier. They're part of the "Shell LightWeight API" (shlwapi.dll)

Edit Registry Values

I want to change the registry values on the pocketPC. I ran the following code:
if(enabled)
{
dwData = 120;
}
if(RegSetValueEx(HKEY_LOCAL_MACHINE, _T("System\\CurrentControlSet\\Control\\Power\\Timeouts\\BattSuspendTimeout"), 0, REG_DWORD, (LPBYTE)&dwData, sizeof(DWORD)))
{
return FALSE;
}
but it doesn't shange the registry entry. Does anyone know how to set registry key values with c++?
Thanks!
There are a two problems with what you are doing:
1: RegSetValueEx does not take a path, only a valuename. So you need to open the key path first.
e.g.
HKEY key;
if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, "System\\CurrentControlSet\\Control\\Power\\Timeouts", 0, 0, &key))
{
if(RegSetValueEx(key, _T("BattSuspendTimeout"), 0, REG_DWORD, (LPBYTE)&dwData, sizeof(DWORD)))
{
RegCloseKey(key);
return FALSE;
}
RegCloseKey(key);
}
2: That area of the registry requires Privileged code signing to work on all Windows Mobile devices. You can get away with it on most current touch-screen windows mobile devices if the user says "yes" to the unknown publisher question when the application is first run or installed. If you get a "Access Denied" error on the set, then you really need to be Privileged code signed for the set to work.
RegSetValueEx returns a descriptive error code. You can get a human-readable message out of this error code using FormatMessage and possibly via the Error Lookup tool, or the #ERR facility in VS. The code you have looks correct so see what the error message tells you.
How are you verifying the change? Keep in mind that making this change will not be reflected automatically in the device behavior and it probably won't show up in the Control Panel either (depends on if the CPL has already been loaded or not). The shell is unaware that you made the change and it doesn't poll the value - you have to tell it to go out and re-read. How to do it is documented in MSDN (basically you set a named system event).
Check out [VORegistry][1], it makes working with the registry so much easier.
[1]: http://www.voscorp.com/products/developer/winmobile/voregistry/index.htm VORegistry
Assuming that your looking with RegEdit, did you refresh (F5) the registry view?