Handling Ctrl+C with Win32 - winapi

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.

Related

AutoHotKey If Key pressed while win11 TaskView is open syntax

I've recently been using Gnome 41.5 and fell in love with the way the Activities menu works
So I am trying to use AHK to create a script that when I press the windows key it opens Task View - then if Task View is open and I start to type, (to search for an application) I want AHK to open the start menu so that I can utilize its search function
My rough outline for how I imagine it would work below - I've been trying to learn but got stuck here
Lwin::
Send, #{Tab}
if (""taskview is open"" + ""any char pressed"") {
Send, Rctrl + Esc
}
In the future I'd love to have the start button just appear on the Task View screen so that it's almost just like Gnome
i wanted to do the same thing and got this so far, i like how this works tbh, but you might wanna add RWin as well (i don't have it, so i didn't)
before task view appears the start menu flashes shortly, but the activation timing keeps shortcuts working without opening task view, so it's a good tradeoff imo.
;couldn't check these names bc the names are different based on system language
;double click on the script in the task tray and hit CTRL+K to figure out the correct name
taskView := "Task View" ;these 2 names are guesses
search := "Search"
;----------------------------------------------------------------------
;Hotkey function hotkeys have to be created first
Hotkey, ~*LButton, mousedown, off
Hotkey, ~*RButton, mousedown, off
Hotkey, ~*MButton, mousedown, off
Hotkey, ~LWin, showTask
;checks every half second if you're in task view to activate the key logging
SetTimer, taskInput, 500
return
showTask:
;prevent repeats
keywait, LWin
;cancel if a different key got pressed while win was held down
if (A_PriorKey != "LWin") {
return
}
if WinActive(taskView){
sleep 1
send {Esc}
return
}
else send #{tab}
taskInput:
if (!WinActive(taskView)){
return
}
Mouse_Flag = 0
Hotkey, ~*LButton, on
Hotkey, ~*RButton, on
Hotkey, ~*MButton, on
;wait for any key
Input, key, L1 V, {VK0E}{LWin}{RWin}{Home}{End}{PgUp}{PgDn}{Del}{Ins}{BS}{Pause} ;excluded: {LControl}{RControl}{LAlt}{RAlt}{LShift}{RShift}{CapsLock}{NumLock}{PrintScreen}{Left}{Right}{Up}{Down}{AppsKey}{F1}{F2}{F3}{F4}{F5}{F6}{F7}{F8}{F9}{F10}{F11}{F12}
if WinActive(taskView){
if (key = LWin) {
keywait, LWin
sleep 1
send {Esc}
}
else if (Mouse_Flag || key = Chr(27)) { ;chr 27 = blank space character, matches some characters specified in the any key input check, notably Esc
;nothing/return
}
else {
;open search
send #s
WinWaitActive %search%
if("LWin" != A_PriorKey && key != A_PriorKey){ ;slight fix if you type very fast and the letters get jumbled bc winwaitactive takes too long
send {BS}
send {%key%}
send {%A_PriorKey%}
}
else send {%key%}
}
}
Hotkey, ~*LButton, off
Hotkey, ~*RButton, off
Hotkey, ~*MButton, off
Return
mousedown:
Mouse_Flag = 1
sendevent, {Blind}{VK0E} ;unused virtual key
return

How to extract the character from WM_KEYDOWN in PreTranslateMessage(MSG*pMsg)

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.

Distinguish between left and right shift keys using RAWINPUT

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

Windows Constants for Ctrl+X, Ctrl+C, and Ctrl+V

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.

How to know which window has focus and how to change it?

I would like to know how can I ask X11 which windows has the focus. And if for any reason my own application (that may be visible or not) got the focus I want be able to let the former windows get the focus again.
For instance, my application is running with many others (e.g. firefox, gvim, nautilus, ...)
Suppose that at first firefox has focus and that the user clicked on my app which now has the focus. I want that my application put the focus on firefox again.
Does anyone knows how to achieve this? Books recommendations would be very nice.
Take a look at the _NET_ACTIVE_WINDOW value of the root window which is set by most modern window managers:
xprop -root _NET_ACTIVE_WINDOW
This value can, of course, be obtained using Xlib library calls.
You probably want the XGetInputFocus call.
Window focused;
int revert_to;
XGetInputFocus(dpy, &focused, &revert_to);
In this snippet, focused will be the window with current input focus, getting keyboard events and mouse button presses.
This will work even if the window manager does not set the _NET_ACTIVE_WINDOW property on the root window, as specified by EWMH. A few window managers, such as dwm and my 9wm, don't set this.
I recommend an application called XDoTool. It supports quite a lot of queries, controls, and even hooks.
> xdotool getwindowfocus # 29360135
> xdotool getwindowfocus getwindowpid # 12988
> xdotool getwindowfocus getwindowname # tilda
> xdotool getwindowfocus behave '%#' blur getmouselocation
# or focus, mouse-enter, etc.
x:514 y:317 screen:0 window:56623121
x:271 y:26 screen:0 window:56623121
...
Commands like behave accept a callback, which can be built-in like getmouselocation or external like exec notify-send 'focused window', exec zsh myscript.zsh, etc., however you want to use it.
Edit - you can focus using xdotool windowfocus [options] [window], as in xdotool search --class firefox windowfocus. In my case this causes errors because Firefox shows up as a couple dozen 'windows', but all have the same PID; it works given the right ID. Hopefully that's a start.
Edit 2 - the 'window ID' is the decimal representation of the window pointer, e.g. from xprop:
> xprop -root _NET_ACTIVE_WINDOW
_NET_ACTIVE_WINDOW(WINDOW): window id # 0x1c00007, 0x0
> xdotool getwindowfocus
29360135
> printf '%d\n' '0x1c00007'
29360135
Use this XQueryTree to find the currently active, or top-most window.
Here is a function, when given a display, it will find the current window in focus:
static Window
GetCurrWindow(d)
Display *d;
{
Window foo;
Window win;
int bar;
do{
(void) XQueryPointer(d, DefaultRootWindow(d), &foo, &win,
&bar, &bar, &bar, &bar, &bar);
} while(win <= 0);
#ifdef VROOT
{
int n;
Window *wins;
XWindowAttributes xwa;
(void) fputs("=xwa=", stdout);
/* do{ */
XQueryTree(d, win, &foo, &foo, &wins, &n);
/* } while(wins <= 0); */
bar=0;
while(--n >= 0) {
XGetWindowAttributes(d, wins[n], &xwa);
if( (xwa.width * xwa.height) > bar) {
win = wins[n];
bar = xwa.width * xwa.height;
}
n--;
}
XFree(wins);
}
#endif
return(win);
}
http://tronche.com/gui/x/xlib/window-information/XQueryTree.html
I found the source:
http://examples.oreilly.com/networksa/tools/xsnoop.c
Good Luck

Resources