I've got some older MFC code I wrote that I'm "freshening up" a bit. I have the following code in a window class' OnChar() handler.
I really don't like using constants like 0x18. I'd like to make the code more readable. I know I can declare my own, but are there no Windows macros for these values? I couldn't find anything about this on the web.
// Check for clipboard commands
switch (nChar)
{
case 0x18: // Ctrl+X - Cut
OnEditCut();
break;
case 0x03: // Ctrl+C - Copy
OnEditCopy();
break;
case 0x16: // Ctrl+V - Paste
OnEditPaste();
break;
}
Do you have some code above there which is subtracting an offset from nChar?
Those values are the letters' places in the alphabet, but I don't think character codes normally work like that. (It has been a long time since I used any of this so maybe I'm just mis-remembering.)
Anyway, the code fragment you have is effectively this (at least on architectures that use the ASCII character ordering, i.e. alphabetic):
// Check for clipboard commands
switch (nChar)
{
case ('X' - 'A' + 1): // Ctrl+X - Cut
OnEditCut();
break;
case ('C' - 'A' + 1): // Ctrl+C - Copy
OnEditCopy();
break;
case ('V' - 'A' + 1): // Ctrl+V - Paste
OnEditPaste();
break;
}
As mentioned in my other comment, I'd expect there to be some other code checking for Ctrl being held down.
Related
In a MFC application within PreTranslateMessage(MSG *pMsg) inherited from a CView, I have this:
if (pMsg->message == WM_KEYDOWN) ...
The fields in a WM_KEYDOWN are documented here. The virtual key VK_ value is in pMsg->wParam and pMsg->lParam contains several field, of which bits 16-23 is the keyboard scan code.
So in my code I use:
const int virtualKey = pMsg->wParam;
const int hardwareScanCode = (pMsg->lParam >> 16) & 0x00ff; // bits 16-23
On my non-US keyboard for example, when I press the "#" character, I get the following:
virtualKey == 0xde --> VK_OEM_7 "Used for miscellaneous characters; it can vary by keyboard."
hardwareScanCode == 0x29 (41 decimal)
The character I'd like to "capture" or process differently is ASCII "#", 0x23 (35 decimal).
MY QUESTION
How do I translate the WM_KEYDOWN information to get something I can compare against, regardless of language or keyboard layout? I need to identify the # key whether the user has a standard US keyboard, or something different.
For example, I've been looking at the following functions such as:
MapVirtualKey(virtualkey, MAPVK_VSC_TO_VK);
// previous line is useless, the key VK_OEM_7 doesn't map to anything without the scan code
ToAscii(virtualKey, hardwareScanCode, nullptr, &word, 0);
// previous line returns zero, and zero is written to `word`
Edit:
Long story short: On a U.S. keyboard, SHIFT+3 = #, while on a French keyboard SHIFT+3 = /. So I don't want to look at individual keys, instead I want to know about the character.
When handling WM_KEYDOWN, how do I translate lParam and wParam (the "keys") to find out the character which the keyboard and Windows is about to generate?
I believe this is a better solution. This one was tested with both the standard U.S. keyboard layout and the Canadian-French keyboard layout.
const int wParam = pMsg->wParam;
const int lParam = pMsg->lParam;
const int keyboardScanCode = (lParam >> 16) & 0x00ff;
const int virtualKey = wParam;
BYTE keyboardState[256];
GetKeyboardState(keyboardState);
WORD ascii = 0;
const int len = ToAscii(virtualKey, keyboardScanCode, keyboardState, &ascii, 0);
if (len == 1 && ascii == '#')
{
// ...etc...
}
Even though the help page seems to hint that keyboardState is optional for the call to ToAscii(), I found that it was required with the character I was trying to detect.
Found the magic API call that gets me what I need: GetKeyNameText()
if (pMsg->message == WM_KEYDOWN)
{
char buffer[20];
const int len = GetKeyNameTextA(pMsg->lParam, buffer, sizeof(buffer));
if (len == 1 && buffer[0] == '#')
{
// ...etc...
}
}
Nope, that code only works on keyboard layouts that have an explicit '#' key. Doesn't work on layouts like the standard U.S. layout where '#' is a combination of other keys like SHIFT + 3.
I'm not an MFC expert, but here's roughly what I believe its message loop looks like:
while (::GetMessage(&msg, NULL, 0, 0) > 0) {
if (!app->PreTranslateMessage(&msg)) { // the hook you want to use
TranslateMessage(&msg); // where WM_CHAR messages are generated
DispatchMessage(&msg); // where the original message is dispatched
}
}
Suppose a U.S. user (for whom 3 and # are on the same key) presses that key.
The PreTranslateMessage hook will see the WM_KEYDOWN message.
If it allows the message to pass through, then TranslateMessage will generate a WM_CHAR message (or something from that family of messages) and dispatch it directly. PreTranslateMessage will never see the WM_CHAR.
Whether that WM_CHAR is a '3' or a '#' depends on the keyboard state, specifically whether a Shift key is currently pressed. But the WM_KEYDOWN message doesn't contain all the keyboard state. TranslateMessage keeps track of the state by taking notes on the keyboard messages that pass through it, so it knows whether the Shift (or Ctrl or Alt) is already down.
Then DispatchMessage will dispatch the original WM_KEYDOWN message.
If you want to catch only the '#' and not the '3's, then you have two options:
Make your PreTranslateMessage hook keep track of all the keyboard state (like TranslateMessage would normally do). It would have to watch for all of the keyboard messages to track the keyboard state and use that in conjunction with the keyboard layout to figure whether the current message would normally generate a '#'. You'd then have to manually dispatch the WM_KEYDOWN message and return TRUE (so that the normal translate/dispatch doesn't happen). You'd also have to be careful to also filter the corresponding WM_KEYUP messages so that you don't confuse TranslateMessage's internal state. That's a lot of work and lots to test.
Find a place to intercept the WM_CHAR messages that TranslateMessage generates.
For that second option, you could subclass the destination window, have it intercept WM_CHAR messages when the character is '#' and pass everything else through. That seems a lot simpler and well targeted.
I have a Win32 window message loop. I want to intercept "Copy to clipboard" via CTRL+C.
My current approach is to handle it like this:
...
case WM_KEYDOWN:
TranslateMessage(&message);
// Intercept Ctrl+C for copy to clipboard
if ('C' == message.wParam && (::GetKeyState(VK_CONTROL)>>15))
{ // do the copy... }
...
Is there a better way to do this other than explicitly checking for the key-stroke combination?
Is there some way to register the standard copy-to-clipboard keystroke and then handle a WM_COPY message?
Windows treats Ctrl+C, Ctrl+V, Ctrl+X as one key in the WM_CHAR message.
enum
{
CTRL_BASE = 'A' - 1,
SELECT_ALL = 'A' - CTRL_BASE, // Ctrl+A
COPY = 'C' - CTRL_BASE, // Ctrl+C
CUT = 'X' - CTRL_BASE, // Ctrl+X
PASTE = 'V' - CTRL_BASE, // Ctrl+V
UNDO = 'Z' - CTRL_BASE, // Ctrl+Z
REDO = 'Y' - CTRL_BASE, // Ctrl+Y
};
Note: This is not documented at MSDN - WM_CHAR message. This is an observation I made while creating my text editor. Although Ctrl+A == 0x41 is mentioned in Keyboard Input.
Using WM_CHAR instead of manually handling WM_KEYDOWN, etc makes processing closer to the standard, specifically does auto-repeat when a key is held, and does not emit the message when extra keys are held.
Apparently there's no readily available way to have WM_COPY delivered for you instead of keys.
RAWINPUT provides two flags (RI_KEY_E0 and RI_KEY_E1) to check whether the left or right version of a key is pressed. This works great for CTRL, but not for left and right shift. In fact, the flags are the same for both, and the VKey is also the same (VK_SHIFT). How can I find out which shift was pressed? I'm working on Windows 7. Interestingly, the flags/vkey values are exactly the same no matter which shift key I'm pressing.
Windows 7, and I only get VK_SHIFT, never the L/R variants
Which is part of the explanation why this doesn't work the way you think it should do. There's ancient history behind this. The keyboard controller was redesigned for the IBM AT, again for the Enhanced keyboard. It started sending out 0xe0 and 0xe1 prefixes for keys that were added to the keyboard layout. Like the right Ctrl and Alt keys.
But keyboards always had two shift keys. The original IBM PC didn't consider them special keys, they simply have a different scan code. Which was maintained in later updates. Accordingly, you don't get the RI_KEY_E0 or E1 flags for them. You have to distinguish them by the RAWKEYBOARD.MakeCode value. The left shift key has makecode 0x2a, the right key is 0x36.
Note that the left Ctrl and Alt keys don't have the flags either. They match the corresponding keys on the old PC keyboard layout. The description of the flags in the MSDN Library article is not very accurate.
You can distinguish left-right SHIFT/CONTROL/ALT VK codes like this:
case WM_INPUT:
{
HRAWINPUT dataHandle = reinterpret_cast<HRAWINPUT>(lParam);
RAWINPUT input;
UINT size = sizeof(input);
::GetRawInputData(dataHandle, RID_INPUT, &input, &size, sizeof(RAWINPUTHEADER));
if (input.header.dwType != RIM_TYPEKEYBOARD)
break;
const RAWKEYBOARD& keyboard = input.data.keyboard;
// Ignore key overrun state
if (keyboard.MakeCode == KEYBOARD_OVERRUN_MAKE_CODE)
return;
// Ignore keys not mapped to any VK code
// This effectively filters out scan code pre/postfix for some keys like PrintScreen.
if (keyboard.VKey >= 0xff/*VK__none_*/)
return;
uint16_t scanCode = keyboard.MakeCode;
// Scan codes could contain 0xe0 or 0xe1 one-byte prefix.
// See https://download.microsoft.com/download/1/6/1/161ba512-40e2-4cc9-843a-923143f3456c/translate.pdf
scanCode |= (keyboard.Flags & RI_KEY_E0) ? 0xe000 : 0;
scanCode |= (keyboard.Flags & RI_KEY_E1) ? 0xe100 : 0;
uint16_t vkCode = keyboard.VKey;
switch (vkCode)
{
case VK_SHIFT: // -> VK_LSHIFT or VK_RSHIFT
case VK_CONTROL: // -> VK_LCONTROL or VK_RCONTROL
case VK_MENU: // -> VK_LMENU or VK_RMENU
vkCode = LOWORD(MapVirtualKeyW(scanCode, MAPVK_VSC_TO_VK_EX));
break;
}
//...
return 0;
}
This code should work at least from Vista.
But please note that gamedev programmers are usually manually mapping scancodes to internal game engine specific keycodes - because VK codes are tend to change on different keyboard layouts. For example if you use usual VK_W/VK_A/VK_S/VK_D for movement in QWERTY layout - it could turn into VK_Z/VK_Q/VK_S/VK_D in AZERTY keyboard layout. VK codes are primarily handy in Win32 GUI programming.
You can grab decent scancode<->USB HID Usage conversion table here: https://source.chromium.org/chromium/chromium/src/+/main:ui/events/keycodes/dom/dom_code_data.inc
For me, Visual Studio's Ctrl + K, Ctrl + C keyboard shortcut is used to comment-out the selected lines. When editing C++, this sometimes uses block comments (/* */) and sometimes uses line comments (//). Why does it change? How does it decide which to use when?
A couple other discussions on the topic:
Visual studio feature - commenting code Ctrl K - Ctrl C
visual studio C++ toggle comment ? comment while not whole line is selected?
Based on my own tinkerings, and what was said in those articles...
It's based on the start/end of the selection. It seems to use double slashes // whenever you start your selection at the beginning of the line AND end it at the end of a line.
It will use /* */ notation whenever the selection occurs midway through lines.
IE:
If I have the code
int main () {
return 0;
}
and highlight only int main, it will convert it to /*int main*/.
If I highlight the entire code section, starting after the indent tab, it will convert it to
/*int main () {
return 0;
}*/
But if I highlight the section starting before the indent tab, it converts it to
//int main () {
// return 0;
//}
Summary of links under Zhais' answer. Because following links is hard!
Selecting entire lines (including leading whitespace) will use //
Selecting at least one partial line
If a // comment is included, will use //
Otherwise, will use /* */
I am trying to get a script like this in AHK but I don't know how to write it in AHK:
string arrow
if (leftArrowKeyPressed) {
arrow = "left"
}
if (rightArrowKeyPressed) {
arrow = "right"
}
if (arrow = "left") {
for (int number = 1000; number < 10000; number++) {
simulateKeyPresses(number)
simulateKeyPresses(mousebutton0)
}
}
I did something similar to this. It uses the While command. Your code might look something like the following:
~left::
While GetKeyState("left", "P") {
Send {NUMBER}
Send {MOUSE_BUTTON}
}
Line 1: '~left::' tells the following lines of code to activate when the left button is pressed. The '~' tells the program to still allow the 'left' arrow key to work. If you wanted this code to run and simultaneously block the 'left' arrow from working, remove the '~'.
Line 2: 'While GetKeyState("left", "P")' is self-explanatory. It's a 'while' loop that runs as long as you are holding the 'left' arrow key.
Line 3 and line 4 are for your code to go. Note that 'NUMBER' can be replace by any number 0-9, and 'MOUSE_BUTTON' can be replaced by either the left mouse button (LButton) or the right mouse button (RButton).
I hoped this helped get you started. Also, as formentioned, the AHK Help manual is very informative. You can search 'AutoHotKey Help' on your computer for your off-line version, or visit this link for the online version. These manuals include documentation of just about anything you could ever hope for, as well as a useful example of code at the bottom of each page.