Qt, multithreading context switching with QRadioButtons - c++

Hi guys so I'm try switch between different threads with the way I have now by having users switch back and forth between multiple radio buttons (here I have only shown 2), when they switch the program freezes. I want to essentially create a thread, stop it then create another thread when I'm doing radio button switching. How do I accomplish this?
mainwindow.cpp
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
s1_thread = new skype_thread(this);
connect(s1_thread, SIGNAL(skype_sig(int)), this, SLOT(skype_change(int)));
x1_thread = new xlite_thread(this);
connect(x1_thread, SIGNAL(xlite_sig(int)), this, SLOT(xlite_change(int)));
}
void MainWindow::on_radioButton_3_toggled(bool checked) //Skype Application is checked
{
x1_thread->stop=true;
s1_thread->start();
}
void MainWindow::on_radioButton_toggled(bool checked) //X-Lite Application is checked
{
s1_thread->stop=true;
x1_thread->start();
}
skype_thread.cpp:
void skype_thread::run()
{
int err;
int skype_signal=0;
//Add programs you would like to use telephony hid here.
wchar_t skype[6] = L"Skype";
unsigned char data_usb[2];
int transfer_size = 4;
//Keyboard input event
INPUT ip;
//Device Handle
libusb_device_handle* dev;
//Initialize libusb with default device
libusb_init(NULL);
//Check whether the Red Button is meant to be a Hangup or Reject Button.
bool check_d = 0;
//Open Device VID = 0x04B4, PID = 0xE002 with the default libusb context
dev = libusb_open_device_with_vid_pid(NULL, VID, PID);
//Claim interface 3 on the device
err = libusb_claim_interface(dev, 3);
//Get first window on desktop
HWND firstwindow = FindWindowEx(NULL, NULL, NULL, NULL);
HWND window = firstwindow;
wchar_t windowtext[MAX_PATH]; //search term
//We need to get the console title in case we
//accidentally match the search word with it
//instead of the intended target window.
wchar_t consoletitle[MAX_PATH];
GetConsoleTitle(consoletitle, MAX_PATH);
//Error message for when window isn't found.
QString error_msg = NULL;
while(true){
//Check window title for a match
GetWindowText(window, windowtext, MAX_PATH);
if (wcsstr(windowtext, skype)!=NULL && wcscmp(windowtext, consoletitle)!=0) break; //search for program
window = FindWindowEx(NULL, window, NULL, NULL); //Get next window
}
while(true){
QMutex mutex;
mutex.lock();
//Differentiate the different button presses.
//Interrupt IN transfer
err = libusb_interrupt_transfer(dev, LIBUSB_ENDPOINT_IN | EP_IN, data_usb, sizeof(data_usb), &transfer_size, 1000);
if(transfer_size > 0){
if(data_usb[0]==0x02 && data_usb[1]==0x04){ //Pickup Button Payload
printf("Window found: %ls\n", windowtext);
//Press the "Alt" key
ip.ki.wVk = 0x12; // virtual-key code for the "Alt" key
ip.ki.dwFlags = 0; // 0 for key press
SendInput(1, &ip, sizeof(INPUT));
//Release the "Alt" key
ip.ki.wVk = 0x12;
ip.ki.dwFlags = KEYEVENTF_KEYUP; // KEYEVENTF_KEYUP for key release
SendInput(1, &ip, sizeof(INPUT));
//Bring specified window into focus
SetForegroundWindow(window);
//Press the "Alt" key
ip.ki.wVk = 0x12; // virtual-key code for the "alt" key
ip.ki.dwFlags = 0; // 0 for key press
SendInput(1, &ip, sizeof(INPUT));
//Press the "Pageup" key
ip.ki.wVk = 0x21; // virtual-key code for the "pageup" key
ip.ki.dwFlags = 0; // 0 for key press
SendInput(1, &ip, sizeof(INPUT));
//Release the "Pageup" key
ip.ki.wVk = 0x21;
ip.ki.dwFlags = KEYEVENTF_KEYUP; // KEYEVENTF_KEYUP for key release
SendInput(1, &ip, sizeof(INPUT));
//Release the "Alt" key
ip.ki.wVk = 0x12;
ip.ki.dwFlags = KEYEVENTF_KEYUP; // KEYEVENTF_KEYUP for key release
SendInput(1, &ip, sizeof(INPUT));
check_d = 1;
}
if(data_usb[0]==0x02 && data_usb[1]==0x01 && check_d==1){ //Disconnect Button Payload
//Press the "Alt" key
ip.ki.wVk = 0x12; // virtual-key code for the "Alt" key
ip.ki.dwFlags = 0; // 0 for key press
SendInput(1, &ip, sizeof(INPUT));
//Release the "Alt" key
ip.ki.wVk = 0x12;
ip.ki.dwFlags = KEYEVENTF_KEYUP; // KEYEVENTF_KEYUP for key release
SendInput(1, &ip, sizeof(INPUT));
//Bring specified window into focus
SetForegroundWindow(window);
//Press the "Alt" key
ip.ki.wVk = 0x12; // virtual-key code for the "alt" key
ip.ki.dwFlags = 0; // 0 for key press
SendInput(1, &ip, sizeof(INPUT));
//Press the "Pagedown" key
ip.ki.wVk = 0x22; // virtual-key code for the "pageup" key
ip.ki.dwFlags = 0; // 0 for key press
SendInput(1, &ip, sizeof(INPUT));
//Release the "Pagedown" key
ip.ki.wVk = 0x22;
ip.ki.dwFlags = KEYEVENTF_KEYUP; // KEYEVENTF_KEYUP for key release
SendInput(1, &ip, sizeof(INPUT));
//Release the "Alt" key
ip.ki.wVk = 0x12;
ip.ki.dwFlags = KEYEVENTF_KEYUP; // KEYEVENTF_KEYUP for key release
SendInput(1, &ip, sizeof(INPUT));
check_d = 0;
}//end if
if(data_usb[0]==0x02 && data_usb[1]==0x01 && check_d==0){ //Reject Button Payload
//Press the "Alt" key
ip.ki.wVk = 0x12; // virtual-key code for the "Alt" key
ip.ki.dwFlags = 0; // 0 for key press
SendInput(1, &ip, sizeof(INPUT));
//Release the "Alt" key
ip.ki.wVk = 0x12;
ip.ki.dwFlags = KEYEVENTF_KEYUP; // KEYEVENTF_KEYUP for key release
SendInput(1, &ip, sizeof(INPUT));
//Bring specified window into focus
SetForegroundWindow(window);
//Press the "Ctrl"Key
ip.ki.wVk = 0x11; // virtual-key code for the "alt" key
ip.ki.dwFlags = 0; // 0 for key press
SendInput(1, &ip, sizeof(INPUT));
//Press the "Alt" key
ip.ki.wVk = 0x12; // virtual-key code for the "alt" key
ip.ki.dwFlags = 0; // 0 for key press
SendInput(1, &ip, sizeof(INPUT));
//Press the "Pagedown" key
ip.ki.wVk = 0x22; // virtual-key code for the "pageup" key
ip.ki.dwFlags = 0; // 0 for key press
SendInput(1, &ip, sizeof(INPUT));
//Release the "Pagedown" key
ip.ki.wVk = 0x22;
ip.ki.dwFlags = KEYEVENTF_KEYUP; // KEYEVENTF_KEYUP for key release
SendInput(1, &ip, sizeof(INPUT));
//Release the "Alt" key
ip.ki.wVk = 0x12;
ip.ki.dwFlags = KEYEVENTF_KEYUP; // KEYEVENTF_KEYUP for key release
SendInput(1, &ip, sizeof(INPUT));
//Release the "Ctrl" key
ip.ki.wVk = 0x11;
ip.ki.dwFlags = KEYEVENTF_KEYUP; // KEYEVENTF_KEYUP for key release
SendInput(1, &ip, sizeof(INPUT));
check_d = 0;
}//end if
}//end if
if(this->stop) break;
mutex.unlock();
emit skype_sig(skype_signal);
skype_signal++;
} //end while
}
xlite_thread.cpp
void xlite_thread::run()
{
int xlite_signal=0;
int err;
//Add programs you would like to use telephony hid here.
wchar_t xlite[7] = L"X-Lite";
unsigned char data_usb[2];
int transfer_size = 4;
//Keyboard input event
INPUT ip;
//Device Handle
libusb_device_handle* dev;
//Initialize libusb with default device
libusb_init(NULL);
//Check whether the Red Button is meant to be a Hangup or Reject Button.
bool check_d = 0;
//Open Device VID = 0x04B4, PID = 0xE002 with the default libusb context
dev = libusb_open_device_with_vid_pid(NULL, VID, PID);
//Claim interface 3 on the device
err = libusb_claim_interface(dev, 3);
//Get first window on desktop
HWND firstwindow = FindWindowEx(NULL, NULL, NULL, NULL);
HWND window = firstwindow;
wchar_t windowtext[MAX_PATH]; //search term
//We need to get the console title in case we
//accidentally match the search word with it
//instead of the intended target window.
wchar_t consoletitle[MAX_PATH];
GetConsoleTitle(consoletitle, MAX_PATH);
//Error message for when window isn't found.
QString error_msg = NULL;
while(true){
//Check window title for a match
GetWindowText(window, windowtext, MAX_PATH);
if (wcsstr(windowtext, xlite)!=NULL && wcscmp(windowtext, consoletitle)!=0) break; //search for program
window = FindWindowEx(NULL, window, NULL, NULL); //Get next window
}
while(true){
QMutex mutex;
mutex.lock();
//Differentiate the different button presses.
//Interrupt IN transfer
err = libusb_interrupt_transfer(dev, LIBUSB_ENDPOINT_IN | EP_IN, data_usb, sizeof(data_usb), &transfer_size, 1000);
if(transfer_size > 0){
if(data_usb[0]==0x02 && data_usb[1]==0x04){ //Pickup Button Payload
printf("Window found: %ls\n", windowtext);
//Press the "Alt" key
ip.ki.wVk = 0x12; // virtual-key code for the "Alt" key
ip.ki.dwFlags = 0; // 0 for key press
SendInput(1, &ip, sizeof(INPUT));
//Release the "Alt" key
ip.ki.wVk = 0x12;
ip.ki.dwFlags = KEYEVENTF_KEYUP; // KEYEVENTF_KEYUP for key release
SendInput(1, &ip, sizeof(INPUT));
//Bring specified window into focus
SetForegroundWindow(window);
//Press the "Ctrl" key
ip.ki.wVk = 0xA2; // virtual-key code for the "alt" key
ip.ki.dwFlags = 0; // 0 for key press
SendInput(1, &ip, sizeof(INPUT));
//Press the "N" key
ip.ki.wVk = 0x4E; // virtual-key code for the "pageup" key
ip.ki.dwFlags = 0; // 0 for key press
SendInput(1, &ip, sizeof(INPUT));
//Release the "N" key
ip.ki.wVk = 0x4E;
ip.ki.dwFlags = KEYEVENTF_KEYUP; // KEYEVENTF_KEYUP for key release
SendInput(1, &ip, sizeof(INPUT));
//Release the "Ctrl" key
ip.ki.wVk = 0xA2;
ip.ki.dwFlags = KEYEVENTF_KEYUP; // KEYEVENTF_KEYUP for key release
SendInput(1, &ip, sizeof(INPUT));
check_d = 1;
}
if(data_usb[0]==0x02 && data_usb[1]==0x01 && check_d==1){ //Disconnect Button Payload
//Press the "Alt" key
ip.ki.wVk = 0x12; // virtual-key code for the "Alt" key
ip.ki.dwFlags = 0; // 0 for key press
SendInput(1, &ip, sizeof(INPUT));
//Release the "Alt" key
ip.ki.wVk = 0x12;
ip.ki.dwFlags = KEYEVENTF_KEYUP; // KEYEVENTF_KEYUP for key release
SendInput(1, &ip, sizeof(INPUT));
//Bring specified window into focus
SetForegroundWindow(window);
//Press the "Ctrl" key
ip.ki.wVk = 0xA2; // virtual-key code for the "alt" key
ip.ki.dwFlags = 0; // 0 for key press
SendInput(1, &ip, sizeof(INPUT));
//Press the "E" key
ip.ki.wVk = 0x45; // virtual-key code for the "pageup" key
ip.ki.dwFlags = 0; // 0 for key press
SendInput(1, &ip, sizeof(INPUT));
//Release the "E" key
ip.ki.wVk = 0x45;
ip.ki.dwFlags = KEYEVENTF_KEYUP; // KEYEVENTF_KEYUP for key release
SendInput(1, &ip, sizeof(INPUT));
//Release the "Ctrl" key
ip.ki.wVk = 0xA2;
ip.ki.dwFlags = KEYEVENTF_KEYUP; // KEYEVENTF_KEYUP for key release
SendInput(1, &ip, sizeof(INPUT));
check_d = 0;
}//end if
if(data_usb[0]==0x02 && data_usb[1]==0x01 && check_d==0){ //Reject Button Payload
//Press the "Alt" key
ip.ki.wVk = 0x12; // virtual-key code for the "Alt" key
ip.ki.dwFlags = 0; // 0 for key press
SendInput(1, &ip, sizeof(INPUT));
//Release the "Alt" key
ip.ki.wVk = 0x12;
ip.ki.dwFlags = KEYEVENTF_KEYUP; // KEYEVENTF_KEYUP for key release
SendInput(1, &ip, sizeof(INPUT));
//Bring specified window into focus
SetForegroundWindow(window);
//Press the "Ctrl" key
ip.ki.wVk = 0xA2; // virtual-key code for the "alt" key
ip.ki.dwFlags = 0; // 0 for key press
SendInput(1, &ip, sizeof(INPUT));
//Press the "D" key
ip.ki.wVk = 0x44; // virtual-key code for the "pageup" key
ip.ki.dwFlags = 0; // 0 for key press
SendInput(1, &ip, sizeof(INPUT));
//Release the "D" key
ip.ki.wVk = 0x44;
ip.ki.dwFlags = KEYEVENTF_KEYUP; // KEYEVENTF_KEYUP for key release
SendInput(1, &ip, sizeof(INPUT));
//Release the "Ctrl" key
ip.ki.wVk = 0xA2;
ip.ki.dwFlags = KEYEVENTF_KEYUP; // KEYEVENTF_KEYUP for key release
SendInput(1, &ip, sizeof(INPUT));
check_d = 0;
}//end if
}//end if
if(this->stop) break;
mutex.unlock();
emit xlite_sig(xlite_signal);
xlite_signal++;
} //end while
}

You are better off using a Object and a timer to repeatedly call a slot in the object (that is moved to a worker thread)
for example:
class SkypeObject: public QObject{
Q_OBJECT
slots:
void start();
void loop();
void stop();
signals:
//...
}
Then you trigger the start and stop slots after you move it to the background thread. Inside the loop slot you put the body of the while and trigger it by QTimer (or using startTimer and inherit timerEvent(QTimerEvent))
Also the mutex in the while loop doesn't actually do anything to protect against race conditions except leak when you exit the while when stop is true.

Related

C++ How to simulate special key strokes (alt+numepad)

I'm working on a project where I have to send certain text into specific webpage (in Chrome) but I can't send it directly or copy&paste it. The solution I came up with is keyboard bot - I use virtual keys to do the job, but in that text I have special sign "↔" (Alt+numepad2+numepad9) and I can't make it with virtual keys. I'll be greatful for any working solution. I did try various methods I found but nothing worked, if I simulate only alt press and manually type on numepad it works, but not when program does it.
Here's my code:
#define WINVER 0x0500
#include <windows.h>
int main()
{
INPUT typ;
typ.type = INPUT_KEYBOARD;
typ.ki.wScan = 0;
typ.ki.time = 0;
typ.ki.dwExtraInfo = 0;
//Time to select window
Sleep(5000);
// Press the "X" key
typ.ki.wVk = 'X';
typ.ki.dwFlags = 0; // 0 for key press
SendInput(1, &typ, sizeof(INPUT));
// Release the "X" key
typ.ki.wVk = 'X';
typ.ki.dwFlags = KEYEVENTF_KEYUP;
SendInput(1, &typ, sizeof(INPUT));
// Press the "Alt" key
typ.ki.wVk = VK_MENU;
typ.ki.dwFlags = KEYEVENTF_EXTENDEDKEY|0;
SendInput(1, &typ, sizeof(INPUT));
//Sleep(3000);
// Press the "2" key
typ.ki.wVk = VK_NUMPAD2;
typ.ki.dwFlags = KEYEVENTF_EXTENDEDKEY|0;
SendInput(1, &typ, sizeof(INPUT));
// Release the "2" key
typ.ki.wVk = VK_NUMPAD2;
typ.ki.dwFlags = KEYEVENTF_EXTENDEDKEY|KEYEVENTF_KEYUP;
SendInput(1, &typ, sizeof(INPUT));
// Release the "Alt" key
typ.ki.wVk = VK_MENU;
typ.ki.dwFlags = KEYEVENTF_EXTENDEDKEY|KEYEVENTF_KEYUP;
SendInput(1, &typ, sizeof(INPUT));
return 0;
}
If someone needs the unicode key press
// Press a unicode "key"
typ.ki.dwFlags = KEYEVENTF_UNICODE;
typ.ki.wVk = 0;
typ.ki.wScan = 0x2194; // HEX UNICODE
SendInput(1, &typ, sizeof(INPUT));
// Release key
typ.ki.dwFlags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP;
SendInput(1, &typ, sizeof(INPUT));
This works:
keybd_event(0x12, MapVirtualKey(0x12, 0), 0, 0); //Alt press
keybd_event(0x62, MapVirtualKey(0x62, 0), 0, 0); // Numpad2 press
keybd_event(0x62, MapVirtualKey(0x62, 0), KEYEVENTF_KEYUP, 0); //Numpad2 relese
keybd_event(0x69, MapVirtualKey(0x69, 0), 0, 0); // Numpad9 press
keybd_event(0x69, MapVirtualKey(0x69, 0), KEYEVENTF_KEYUP, 0); //Numpad9 relese
keybd_event(0x12, MapVirtualKey(0x12, 0), KEYEVENTF_KEYUP, 0); // Alt relese

How to highlight an entire word in C++?

I have made the following C++ program to highlight the last word before the cursor in a typing interface by sending Control+Shift+Left and then copy it to clipboard by sending Control+C.
#define WINVER 0x0500
#include <windows.h>
#include <Winuser.h>
using namespace std;int main() {
// Create a generic keyboard event structure
INPUT ip;
ip.type = INPUT_KEYBOARD;
ip.ki.wScan = 0;
ip.ki.time = 0;
ip.ki.dwExtraInfo = 0;
while(true) {
if( GetKeyState(VK_LMENU) & 0x8000 ) {
Sleep(200);
// Press the "Ctrl" key
ip.ki.wVk = VK_CONTROL;
ip.ki.dwFlags = 0; // 0 for key press
SendInput(1, &ip, sizeof(INPUT));
// Press the "Shift" key
ip.ki.wVk = VK_SHIFT;
ip.ki.dwFlags = 0; // 0 for key press
SendInput(1, &ip, sizeof(INPUT));
// Press the "Left" key
ip.ki.wVk = VK_LEFT;
ip.ki.dwFlags = 0; // 0 for key press
SendInput(1, &ip, sizeof(INPUT));
// Release the "Left" key
ip.ki.wVk = VK_LEFT;
ip.ki.dwFlags = KEYEVENTF_KEYUP;
SendInput(1, &ip, sizeof(INPUT));
// Release the "Shift" key
ip.ki.wVk = VK_SHIFT;
ip.ki.dwFlags = KEYEVENTF_KEYUP;
SendInput(1, &ip, sizeof(INPUT));
// Press the "C" key
ip.ki.wVk = 'C';
ip.ki.dwFlags = 0; // 0 for key press
SendInput(1, &ip, sizeof(INPUT));
// Release the "C" key
ip.ki.wVk = 'C';
ip.ki.dwFlags = KEYEVENTF_KEYUP;
SendInput(1, &ip, sizeof(INPUT));
// Release the "Ctrl" key
ip.ki.wVk = VK_CONTROL;
ip.ki.dwFlags = KEYEVENTF_KEYUP;
SendInput(1, &ip, sizeof(INPUT));
}}}
This is meant to work when I press the Left-Alt key. It works fine for words like abc or hello but not with words like #abc or hello%hello. I need to make it work for the entire word. By "entire word" what I mean is any collection of characters that does not include spaces or line breaks.
If you can't solve my problem completely, please know that I am open to workarounds that may work differently or include certain limitations. But I really this so please help.
And please feel free to suggest edits to help me improve this question.
As IInspectable mentioned, obviously what you consider to be a word and what the text field considers to be a word are two different things and you can't really do anything about it. So instead of trying to simulate the input which is not getting you what you want anyway, you should try and retrieve a handle (HWND) for the text field using some combination of FindWindowEx calls.
Now I can't exactly tell you how to find the window you need because I don't know where it is on your system and which application it belongs to. But you might be able to get the required information to do this (window hierarchy and class names) using some tool such as Inspect.
After that you should be able to get the text from the text field and parse it to get the first word:
#include <Windows.h>
int main()
{
/* You should adjust the following code to whatever criteria
you are using to choose the text field */
HWND appWindow = FindWindowEx(GetDesktopWindow(), NULL, NULL, "App window title");
HWND editControl = FindWindowEx(appWindow, NULL, "EDIT", NULL);
int size = GetWindowTextLength(editControl) + 1;
char *text = new char[size];
GetWindowText(editControl, text, size);
int cursorPos = 0;
SendMessage(editControl, EM_GETSEL, (WPARAM) &cursorPos, NULL);
for (int i = cursorPos; i < size; ++i) {
if (text[i] == ' ') {
text[i] = '\0';
break;
}
}
char *word = &text[cursorPos];
//do whatever you need with the word here
delete[] text;
return 0;
}
I didn't really have the opportunity to test this code and regarding copying the text to the clipboard: it seems to be a lot more complicated task to achieve using Win32 API which is in great detail described here.

Virtual key codes

I have a c++ console program. Ho can I simulate the "é" character ?
Code:
// Set up a generic keyboard event.
ip.type = INPUT_KEYBOARD;
ip.ki.wScan = 0; // hardware scan code for key
ip.ki.time = 0;
ip.ki.dwExtraInfo = 0;
ip.ki.wVk = 0x45; //e
ip.ki.dwFlags = 0;
SendInput(1, &ip, sizeof(INPUT));
ip.ki.dwFlags = KEYEVENTF_KEYUP;
SendInput(1, &ip, sizeof(INPUT));
How do I convert it to the "é" instead of "e"?
Thanks.
Per the KEYBDINPUT documentation, you can use the KEYEVENTF_UNICODE flag:
INPUT ip[2];
// Set up a generic keyboard event.
ip[0].type = INPUT_KEYBOARD;
ip[0].ki.dwFlags = KEYEVENTF_UNICODE; // We want to send a Unicode key code.
ip[0].ki.wScan = 0x00E9; // Unicode value of é
ip[0].ki.time = 0;
ip[0].ki.dwExtraInfo = 0;
ip[0].ki.wVk = 0; // Ignored
ip[1] = ip[0]; // Duplicate entry
ip[1].ki.dwFlags |= KEYEVENTF_KEYUP; // but make it key up
SendInput( 2, ip, sizeof(ip[0]));
(If you are ambitious, you can make that final "2" be your favourite ARRAY_COUNT macro or template function.)

How to copy text from outside application using hotkey?

I have MFC application which gets invoked on hotkey (should be running, just brings it to front), send clipboard data to one of the text box using,
SendMessage(hWnd,WM_PASTE,0,0);
Everything is working fine till now.
We get new requirement wherein we should be able to copy selected text to clipboard using hot key (without using Ctrl + C), and then launch our application.
I tried to use SendMessage(WM_COPY), but does not work.
Please suggest how to get selected text of any other application on clipboard.
Finally I myself got the answer.
I had to use SendInput, following is sample code,
INPUT ip;
// Set up a generic keyboard event.
ip.type = INPUT_KEYBOARD;
ip.ki.wScan = 0; // hardware scan code for key
ip.ki.time = 0;
ip.ki.dwExtraInfo = 0;
// Press the "Ctrl" key
ip.ki.wVk = VK_CONTROL;
ip.ki.dwFlags = 0; // 0 for key press
SendInput(1, &ip, sizeof(INPUT));
// Press the "C" key
ip.ki.wVk = 'C';
ip.ki.dwFlags = 0; // 0 for key press
SendInput(1, &ip, sizeof(INPUT));
// Release the "C" key
ip.ki.wVk = 'C';
ip.ki.dwFlags = KEYEVENTF_KEYUP;
SendInput(1, &ip, sizeof(INPUT));
// Release the "Ctrl" key
ip.ki.wVk = VK_CONTROL;
ip.ki.dwFlags = KEYEVENTF_KEYUP;
SendInput(1, &ip, sizeof(INPUT));

C++ - Simulating keystrokes using SendInput method, failure to distinguish rightctrl key

I have very little experience in C++, and I'm completely unfamiliar with the SendInput method. I've setup my laptop (with UK keyboard) via a registry modification, to create a crash dump whenever the right control key is held down and scroll lock is twice pressed. I am trying to achieve this programmatically via a c++ executable, compiled in Visual C++ 2010 Express.
Using this post: how to use sendinput function C++ as my inspiration, I have created the code snippet hereunder. Aside from multiple Cannot find or open the PDB debug outputs, which from reading this post: Error Message : Cannot find or open the PDB file can apparently be ignored, the code compiles and runs. However no BSOD transpires. I have manually "forced" the BSOD, so I know it works.
Bearing in mind I'm a novice, please explain what changes must be made for this to work?
#define WINVER 0x500
#include <windows.h>
int main()
{
INPUT ip;
ip.type = INPUT_KEYBOARD;
ip.ki.wScan = 0;
ip.ki.time = 0;
ip.ki.dwExtraInfo = 0;
ip.ki.wVk = VK_RCONTROL;
ip.ki.dwFlags = 0;
SendInput(1, &ip, sizeof(INPUT));
ip.ki.wVk = VK_SCROLL;
ip.ki.dwFlags = 0;
SendInput(1, &ip, sizeof(INPUT));
ip.ki.wVk = VK_SCROLL;
ip.ki.dwFlags = KEYEVENTF_KEYUP;
SendInput(1, &ip, sizeof(INPUT));
ip.ki.wVk = VK_SCROLL;
ip.ki.dwFlags = 0;
SendInput(1, &ip, sizeof(INPUT));
ip.ki.wVk = VK_SCROLL;
ip.ki.dwFlags = KEYEVENTF_KEYUP;
SendInput(1, &ip, sizeof(INPUT));
ip.ki.wVk = VK_RCONTROL;
ip.ki.dwFlags = KEYEVENTF_KEYUP;
SendInput(1, &ip, sizeof(INPUT));
return 0;
}
Following is the relevant code for a simple application I wrote to display the virtual key, scan code, flags, etc. of keys that are typed into the application. (The code demonstrates creating a listbox and handling the WM_KEYDOWN, WM_KEYUP, WM_SYSKEYDOWN, and WM_SYSKEYUP messages, then displaying the parameters:
void CChildView::ReportKey (UINT nChar, UINT nRepCnt, UINT nFlags)
{
CString str;
str.Format ( "%s Virtual key=%d; Scan code=%d Extended=%d AltDown=%d",
(nFlags & 0x8000) ? "Up" : "DOWN",
nChar, (nFlags & 0xFF), !!(nFlags & 0x0100), !!(nFlags & 0x2000) );
AddString (str);
}
void CChildView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
ReportKey (nChar, nRepCnt, nFlags);
CListBox::OnKeyDown(nChar, nRepCnt, nFlags);
}
void CChildView::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)
{
ReportKey (nChar, nRepCnt, nFlags);
CListBox::OnKeyUp(nChar, nRepCnt, nFlags);
}
void CChildView::OnSysKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
ReportKey (nChar, nRepCnt, nFlags);
CListBox::OnSysKeyDown(nChar, nRepCnt, nFlags);
}
void CChildView::OnSysKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)
{
ReportKey (nChar, nRepCnt, nFlags);
CListBox::OnSysKeyUp(nChar, nRepCnt, nFlags);
}
When the Right Control key is pressed, then released, while this app has the keyboard focus, it displays:
DOWN Virtual key=17; Scan code=29 Extended=1 AltDown=0
Up Virtual key=17; Scan code=29 Extended=1 AltDown=0
Curiously, virtual key "17" is 0x11, which according to this chart is VK_CONTROL, not VK_RCONTROL! And the Extended flag is true.
When the Left Control key is pressed and released, the output is:
DOWN Virtual key=17; Scan code=29 Extended=0 AltDown=0
Up Virtual key=17; Scan code=29 Extended=0 AltDown=0
So it seems Windows never sees a VK_RCONTROL, instead it sees a VK_CONTROL with Extended = true.
So try to call SendInput() with that:
INPUT ip[6];
...
ip[0].ki.wVk = VK_CONTROL;
ip[0].ki.wScan = MapVirtualKey(VK_CONTROL, 0);
ip[0].ki.dwFlags = KEYEVENTF_EXTENDEDKEY;
....
ip[5].ki.wVk = VK_CONTROL;
ip[5].ki.wScan = MapVirtualKey(VK_CONTROL, 0);
ip[5].ki.dwFlags = KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY;
SendInput(_countof(ip), &ip[0], sizeof(INPUT));
EDIT: Specify ip.ki.wScan due to the comment
not using KEYEVENTF_SCANCODE doesn't mean the wScan value will be ignored. It won't and some applications (e.g. RDP-Client) may behave different/wrong if you set wScan to 0.
EDIT 2: I don't think it matters here, but it is better to call SendInput just once, and pass it an array of INPUT structures to execute as a transaction, so all the keystrokes are replayed as a unit (and user can't intersperse his own keys during the middle of yours, for example).
EDIT 3: You can download the application that shows the keys typed into it.
This Code successfully stuffs RControl+ScrollLock+ScrollLock into the ScanCode app, however, sorry, the computer does not reboot like when it does when these keys are manually typed.
#define WINVER 0x0500
#include <windows.h>
int main()
{
// Must specify INPUT_KEYBOARD for all INPUT structs
INPUT ip[6] = {
{ INPUT_KEYBOARD },
{ INPUT_KEYBOARD },
{ INPUT_KEYBOARD },
{ INPUT_KEYBOARD },
{ INPUT_KEYBOARD },
{ INPUT_KEYBOARD },
};
Sleep(3000);
// Specify keys by scancode. For the VK_SCROLL, it was necessary
// to instead specify the wVK, otherwise VK==3 was received by ScanCode, instead
// of VK_SCROLL == 145!
//ip[0].ki.wVk = VK_CONTROL;
ip[0].ki.wScan = MapVirtualKey(VK_RCONTROL, MAPVK_VK_TO_VSC);
ip[0].ki.dwFlags = KEYEVENTF_SCANCODE | KEYEVENTF_EXTENDEDKEY;
ip[1].ki.wVk = VK_SCROLL;
ip[1].ki.wScan = MapVirtualKey(VK_SCROLL, MAPVK_VK_TO_VSC);
ip[1].ki.dwFlags = /*KEYEVENTF_SCANCODE*/ 0;
ip[2].ki.wVk = VK_SCROLL;
ip[2].ki.wScan = MapVirtualKey(VK_SCROLL, MAPVK_VK_TO_VSC);
ip[2].ki.dwFlags = /*KEYEVENTF_SCANCODE |*/ KEYEVENTF_KEYUP;
ip[3].ki.wVk = VK_SCROLL;
ip[3].ki.wScan = MapVirtualKey(VK_SCROLL, MAPVK_VK_TO_VSC);
ip[3].ki.dwFlags = /*KEYEVENTF_SCANCODE*/ 0;
ip[4].ki.wVk = VK_SCROLL;
ip[4].ki.wScan = MapVirtualKey(VK_SCROLL, MAPVK_VK_TO_VSC);
ip[4].ki.dwFlags = /*KEYEVENTF_SCANCODE |*/ KEYEVENTF_KEYUP;
//ip[5].ki.wVk = VK_CONTROL;
ip[5].ki.wScan = MapVirtualKey(VK_RCONTROL, MAPVK_VK_TO_VSC);
ip[5].ki.dwFlags = KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY;
int i = _countof(ip);
int numSuccessful = SendInput(i, ip, sizeof(INPUT));
if (numSuccessful == i)
printf("Stuffed successful.\n");
else
{
printf("Succeeded with %d of %d; error %d\n", numSuccessful, i, GetLastError());
}
return 0;
}
I believe the reason is that SendInput() injects the keys into the layer above the keyboard driver, and it is the keyboard driver that is monitored for these keystrokes to initiate the BSOD.
#David Ching... this is frustrating me no end... I've read all the relevant documentation (and tried to make sense of it, remember I'm a novice at this), I've tried umpteen permutations of the code taking into account your advice and what I've read. The code below, according to your last suggestion, is the last I've tried with no success. I'm trying to determine what other factors can have a bearing on the issue - would hardware (Laptop is Toshiba Satellite L670D-10N), or OS (Windows 7 Ultimate - Spanish version with English Language Pack) make a difference? - I can't imagine so. I really, really appreciate your help, please don't give up helping! - btw, thanks for the app link.
#define WINVER 0x0500
#include <windows.h>
int main()
{
INPUT ip[6];
ip[0].ki.wVk = VK_CONTROL;
ip[0].ki.wScan = MapVirtualKey(VK_CONTROL, 0);
ip[0].ki.dwFlags = KEYEVENTF_EXTENDEDKEY;
ip[1].ki.wVk = VK_SCROLL;
ip[1].ki.dwFlags = 0;
ip[2].ki.wVk = VK_SCROLL;
ip[2].ki.dwFlags = KEYEVENTF_KEYUP;
ip[3].ki.wVk = VK_SCROLL;
ip[3].ki.dwFlags = 0;
ip[4].ki.wVk = VK_SCROLL;
ip[4].ki.dwFlags = KEYEVENTF_KEYUP;
ip[5].ki.wVk = VK_CONTROL;
ip[5].ki.wScan = MapVirtualKey(VK_CONTROL, 0);
ip[5].ki.dwFlags = KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY;
SendInput(_countof(ip), &ip[0], sizeof(INPUT));
return 0;
}
UPDATE - THE SUCCESSFUL SENDINPUT TEST CODE
#define WINVER 0x0500
#include <windows.h>
int main()
{
INPUT ip;
Sleep(3000);
ip.type = INPUT_KEYBOARD;
ip.ki.wScan = 0;
ip.ki.time = 0;
ip.ki.dwExtraInfo = 0;
ip.ki.wVk = 0x43;
ip.ki.dwFlags = 0;
SendInput(1, &ip, sizeof(INPUT));
ip.ki.wVk = 0x43;
ip.ki.dwFlags = KEYEVENTF_KEYUP;
SendInput(1, &ip, sizeof(INPUT));
ip.ki.wVk = 0x48;
ip.ki.dwFlags = 0;
SendInput(1, &ip, sizeof(INPUT));
ip.ki.wVk = 0x48;
ip.ki.dwFlags = KEYEVENTF_KEYUP;
SendInput(1, &ip, sizeof(INPUT));
ip.ki.wVk = 0x52;
ip.ki.dwFlags = 0;
SendInput(1, &ip, sizeof(INPUT));
ip.ki.wVk = 0x52;
ip.ki.dwFlags = KEYEVENTF_KEYUP;
SendInput(1, &ip, sizeof(INPUT));
ip.ki.wVk = 0x49;
ip.ki.dwFlags = 0;
SendInput(1, &ip, sizeof(INPUT));
ip.ki.wVk = 0x49;
ip.ki.dwFlags = KEYEVENTF_KEYUP;
SendInput(1, &ip, sizeof(INPUT));
ip.ki.wVk = 0x53;
ip.ki.dwFlags = 0;
SendInput(1, &ip, sizeof(INPUT));
ip.ki.wVk = 0x53;
ip.ki.dwFlags = KEYEVENTF_KEYUP;
SendInput(1, &ip, sizeof(INPUT));
ip.ki.wVk = 0x10;
ip.ki.dwFlags = 0;
SendInput(1, &ip, sizeof(INPUT));
ip.ki.wVk = 0x43;
ip.ki.dwFlags = 0;
SendInput(1, &ip, sizeof(INPUT));
ip.ki.wVk = 0x43;
ip.ki.dwFlags = KEYEVENTF_KEYUP;
SendInput(1, &ip, sizeof(INPUT));
ip.ki.wVk = 0x48;
ip.ki.dwFlags = 0;
SendInput(1, &ip, sizeof(INPUT));
ip.ki.wVk = 0x48;
ip.ki.dwFlags = KEYEVENTF_KEYUP;
SendInput(1, &ip, sizeof(INPUT));
ip.ki.wVk = 0x52;
ip.ki.dwFlags = 0;
SendInput(1, &ip, sizeof(INPUT));
ip.ki.wVk = 0x52;
ip.ki.dwFlags = KEYEVENTF_KEYUP;
SendInput(1, &ip, sizeof(INPUT));
ip.ki.wVk = 0x49;
ip.ki.dwFlags = 0;
SendInput(1, &ip, sizeof(INPUT));
ip.ki.wVk = 0x49;
ip.ki.dwFlags = KEYEVENTF_KEYUP;
SendInput(1, &ip, sizeof(INPUT));
ip.ki.wVk = 0x53;
ip.ki.dwFlags = 0;
SendInput(1, &ip, sizeof(INPUT));
ip.ki.wVk = 0x53;
ip.ki.dwFlags = KEYEVENTF_KEYUP;
SendInput(1, &ip, sizeof(INPUT));
ip.ki.wVk = 0x10;
ip.ki.dwFlags = KEYEVENTF_KEYUP;
SendInput(1, &ip, sizeof(INPUT));
return 0;
}
UPDATE - THE UNSUCCESSFUL REVISED CTRL((SCROLL LOCK)X2) CODE
#define WINVER 0x0500
#include <windows.h>
int main()
{
INPUT ip[6] = {0};
Sleep(3000);
ip[0].ki.wVk = VK_CONTROL;
ip[0].ki.wScan = MapVirtualKey(VK_CONTROL, 0);
ip[0].ki.dwFlags = KEYEVENTF_EXTENDEDKEY;
ip[1].ki.wVk = VK_SCROLL;
ip[1].ki.wScan = MapVirtualKey(VK_SCROLL, 0);
ip[1].ki.dwFlags = 0;
ip[2].ki.wVk = VK_SCROLL;
ip[2].ki.wScan = MapVirtualKey(VK_SCROLL, 0);
ip[2].ki.dwFlags = KEYEVENTF_KEYUP;
ip[3].ki.wVk = VK_SCROLL;
ip[3].ki.wScan = MapVirtualKey(VK_SCROLL, 0);
ip[3].ki.dwFlags = 0;
ip[4].ki.wVk = VK_SCROLL;
ip[4].ki.wScan = MapVirtualKey(VK_SCROLL, 0);
ip[4].ki.dwFlags = KEYEVENTF_KEYUP;
ip[5].ki.wVk = VK_CONTROL;
ip[5].ki.wScan = MapVirtualKey(VK_CONTROL, 0);
ip[5].ki.dwFlags = KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY;
SendInput(_countof(ip), &ip[0], sizeof(INPUT));
return 0;
}