Do I need to introduce delays when simulating a mouse click with SendInput API? - c++

I need to be able to simulate a mouse click on a control in another process. I came up with the following method:
BOOL SimulateMouseClick(POINT* pPntAt)
{
//Simulate mouse left-click
//'pPntAt' = mouse coordinate on the screen
//RETURN:
// = TRUE if success
BOOL bRes = FALSE;
if(pPntAt)
{
//Get current mouse position
POINT pntMouse = {0};
BOOL bGotPntMouse = ::GetCursorPos(&pntMouse);
//Move mouse to a new position
::SetCursorPos(pPntAt->x, pPntAt->y);
//Send mouse click simulation
INPUT inp = {0};
inp.type = INPUT_MOUSE;
inp.mi.dx = pPntAt->x;
inp.mi.dy = pPntAt->y;
inp.mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
if(SendInput(1, &inp, sizeof(inp)) == 1)
{
//Do I need to wait here?
Sleep(100);
inp.mi.dwFlags = MOUSEEVENTF_LEFTUP;
if(SendInput(1, &inp, sizeof(inp)) == 1)
{
//Do I need to wait here before restoring mouse pos?
Sleep(500);
//Done
bRes = TRUE;
}
}
//Restore mouse
if(bGotPntMouse)
{
::SetCursorPos(pntMouse.x, pntMouse.y);
}
}
return bRes;
}
My question is do I need to introduce those artificial delays like a human mouse click would have?

The documentation for SendInput contains the following:
The SendInput function inserts the events in the INPUT structures serially into the keyboard or mouse input stream. These events are not interspersed with other keyboard or mouse input events inserted either by the user (with the keyboard or mouse) or by calls to keybd_event, mouse_event, or other calls to SendInput.
This is the reason, why SendInput was introduced. Placing artificial delays between individual calls of SendInput completely defies its purpose.
The short answer is: No, you do not need to introduce delays between synthesized input. You also do not need to call SetCursorPos; the INPUT structure already contains the location of the mouse input.
Of course, you wouldn't have to deal with any of this, if you went with UI Automation instead. A design goal of UI Automation is "to manipulate the UI by means other than standard input. UI Automation also allows automated test scripts to interact with the UI."

Related

XSendEvent does not change modifier key state

I'm trying to send key events by creating a XKeyEvent and sending it using XSendEvent (inspired by this post). The XKeyEvents are prepared as follows:
XKeyEvent createKeyEvent(Display *display, Window win, Window winRoot, _Bool press, int keycode, int modifiers) {
XKeyEvent event;
event.display = display;
event.window = win;
event.root = winRoot;
event.subwindow = None;
event.time = CurrentTime;
event.x = 1;
event.y = 1;
event.x_root = 1;
event.y_root = 1;
event.same_screen = True;
event.keycode = keycode;
event.state = modifiers;
if (press) {
event.type = KeyPress;
} else {
event.type = KeyRelease;
}
return event;
}
Then they are sent with XSendEvent(event.display, event.window, 1, KeyPressMask, (XEvent *)&event);
The key events are sent and the target program receives them (letters are entered, arrow keys work etc.). However, problems arise with modifier keys. Let's say the program sends a key-down event for the opt/alt key. In this scenario, the text in the menu bar is underlined until a key-up event is sent (indicating that the X-server has received and processed the key-down event).
However, when retrieving the the current state of the modifier keys, the modifier keys do not appear to be pressed at all. When calling XQueryPointer(self->display, winFocus, &root_return, &child_return, &root_x_return, &root_y_return, &win_x_return, &win_y_return, &keyboard_state_mask);, the keyboard_state_mask is 0. Checking the keyboard with xev gives the same result. Physically pressing the modifier keys does change the state mask, both in xev and in my code.
How do I properly change the current modifier-key state?
Solved the problem by using the method int XTestFakeButtonEvent(display, button, is_press, delay) from the library <X11/extensions/XTest.h>. For some reason, this causes the keyboard modifier state to change when sending a modifier key (as I wanted), while the above-mentioned method does not.
From xsendevent man pages:
"The contents of the event are otherwise unaltered and unchecked by the X server except except to force send_event to True in the forwarded event and to set the serial number in the event correctly."
I assume that you copied createKeyEvent() from the following place: http://www.doctort.org/adam/nerd-notes/x11-fake-keypress-event.html
And if you also copied the way this function is called:
createKeyEvent(display, winFocus, winRoot, false, KEYCODE, 0);
then it makes sense that "modifier" is not set to anything, as the last argument is "0". According to documentation you need to set the modifier state yourself.
I did not verify this information. If it does not work as documented, that it might be a documentation bug or a bug in X server's implementation.

SDL Mouse Click

So, I'm currently working on an options menu for my game, I have a button that when pressed it changes it's text to the next resolution in an array, so basically the user presses this button to change their resolution to the next string in the array.
My problem is getting the click event.
Right now, when the user presses the button, it returns true while the mouse is down, instead of when the mouse is pressed. I want to only return true in the mouse event when the mouse is pressed.
I've looked around, and everything I've found seems to be similar to what I've done or, as I said, returning true while the mouse is down, instead of the initial click.
My events are handled in a EventManager singleton, and here are the functions that I see as necessary:
My update function, this is where the event is polled, it is worth noting I'm using a private SDL_Event named "e".
void EventManager::update(){
while(SDL_PollEvent(&e)){
SDL_GetMouseState(&mouseX, &mouseY);
switch(e.type){
case SDL_QUIT:
running = false;
}
}
}
My mousePress function, where I want a mouse press returned.
int EventManager::mousePress(){
if(e.type == SDL_MOUSEBUTTONDOWN){
return e.button.button;
}
return 0;
}
Instead of using SDL_GetMouseState(), which gets you the actual state of the mouse (thats probably where its name comes from ;) ), use the event you are polling. SDL should give you a SDL_MouseButtonEvent which contains the informations you need and should only be queued once.
See https://wiki.libsdl.org/SDL_MouseButtonEvent
Edit to clarify what i mean:
You would use something like this:
void EventManager::update(){
SDL_Event e;
while(SDL_PollEvent(&e)){
switch(e.type){
case SDL_QUIT:
running = false;
break;
case SDL_MOUSEBUTTONDOWN:
//do whatever you want to do after a mouse button was pressed,
// e.g.:
mousePress(e.button);
break;
}
}
}
Inside your mousePress-Function you can then test, which of the mouse buttons has been pressed:
void EventManager::mousePress(SDL_MouseButtonEvent& b){
if(b.button == SDL_BUTTON_LEFT){
//handle a left-click
}
}
This works, because SDL_PollEvent will only return exactly once for every Event. If theres no new Event, it will return an empty Event. So 1 click = 1 times SDL_PollEvent() with e being of type SDL_MOUSEBUTTONDOWN afterwards and 1 times SDL_PollEvent() with e being of type SDL_MOUSEBUTTONUP afterwards. If you call SDL_PollEvent() in between or afterwards, it will return 0 and leave e as an Empty Event, not calling the switch at all. If you respond to MOUSEBUTTONDOWN or MOUSEBUTTONUP or both is up to you...
I've also declared the SDL_Event a local variable to update(). Why? The Idea behind an Event is, that theres an Event-Object whenever some event has occured. Then you react to the event and forget about it. So theres no need to have a global variable. If you want to prevent constant construction/destruction, you can also declare it to be static. But thats just some hint, not related to your original question.

Text Selection with CRichEditCtrl in MFC

I have CRichEditCtrl object which is read only(Text is for read and not allowed to modified). I want to provide functionality of Text Selection with Mouse for text displayed with CRichEditCtrl object.
Following Code is working to capture event for Left Mouse Button - DOWN & UP
BOOL CReportFormView::PreTranslateMessage(MSG* pMsg)
{
if (m_EditNs->GetFocus()!=NULL)
{
switch (pMsg->message)
{
case WM_LBUTTONDOWN:
return TRUE;
case WM_LBUTTONUP:
return TRUE;
}
}
}
Now looking for some code to write in case block which will highlight selected text. I want to know if there is any API available for CRichEditCtrl object which help to track at which location user pressed Left Mouse Button and released
You could use member function CString strText = m_myRichEditCtrl.GetSelText(); or some other member function. Like GetSel() just a suggestion.
I think you will need to use the EM_CHARFROMPOS message. ex. some form of this:
POINTL pt { x,y }; // ... screen coordinates to test relative to edit
DWORD info = m_EditNS->SendMessage(EM_CHARFROMPOS, 0, pt);
int charIndex = LOWORD(info);
int line = HIWORD(info);
After that, set the selection with normal selection methods.
https://msdn.microsoft.com/en-us/library/windows/desktop/bb761566(v=vs.85).aspx

Global alt+space hotkey grabbing - weird keyboard focus behaviour

I'm grabbing Alt+Space global hotkey using xcb_grab_key, as follows:
xcb_key_symbols_t *keysyms = xcb_key_symbols_alloc(c);
xcb_keycode_t *keycodes = xcb_key_symbols_get_keycode(keysyms, XK_space), keycode;
// add bindings for all screens
xcb_screen_iterator_t iter;
iter = xcb_setup_roots_iterator (xcb_get_setup (c));
for (; iter.rem; xcb_screen_next (&iter)) {
int i = 0;
while(keycodes[i] != XCB_NO_SYMBOL) {
keycode = keycodes[i];
xcb_grab_key(c, true, iter.data->root, XCB_MOD_MASK_ANY, keycode, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_SYNC);
i += 1;
}
}
Then in Qt's QAbstractNativeEventFilter subclass I process it and emit a Qt signal if key matches Alt+Space:
xcb_keycode_t *keycodes = xcb_key_symbols_get_keycode(keysyms, XK_space);
int i = 0;
bool found = false;
while(keycodes[i] != XCB_NO_SYMBOL) {
if(event->detail == keycodes[i]) {
if(event->state & GetModifier(c, keysyms, XK_Alt_L) || event->state & GetModifier(c, keysyms, XK_Alt_R)) {
xcb_allow_events(c, XCB_ALLOW_ASYNC_KEYBOARD, event->time);
emit gotHotKey();
found = true;
} else {
xcb_allow_events(c, XCB_ALLOW_REPLAY_KEYBOARD, event->time);
}
break;
}
i += 1;
}
if(found) return true;
(GetModifier is copied from VLC but I think this part doesn't matter since Alt-key is matched correctly)
The problem I'm having is that after show()ing main window when the hotkey is pressed, keyboard is most of the times1 not focused properly. I can type, but the cursor is not visible, input's border is not highlighted, and the shortcut Ctrl+Q for quitting desn't work. It can be worked around by moving the window, or pressing space - then focus is restored - cursor+border reappears and Ctrl+Q works. What might be causing this behaviour?
I'm using Qt 5.0.0 and xcb 1.8.1. Complete application can be downloaded for compiling from github.
1 it means sometimes the issue is not reproducible - focus is set correctly even for repeated window hide/shows, but then other times it happens multiple times in a row of hide/shows. It occurs more often than not overall.
(Edit: I've implemented a (very ugly...) workaround, so to reproduce the issue for the github project, the following code needs to be removed)
#ifndef WIN32
// Very ugly workaround for the problem described at http://stackoverflow.com/questions/14553810/
// (just show and hide a modal dialog box, which for some reason restores proper keyboard focus)
hackDialog.setGeometry(0, 0, 0, 0);
hackDialog.setModal(true);
hackDialog.show();
QTimer::singleShot(100, &hackDialog, SLOT(reject()));
#endif

Mac event tap just delays discarded events

I'm trying to write some code that discards all keyboard and mouse events when enabled on Mac OSX 10.6. My code runs as the root user. The approach I'm taking is to create an event tap that discards all events passed to it (while enabled). The event tap callback function looks like this:
CGEventRef MyTapCallback(CGEventTapProxy proxy,
CGEventType type,
CGEventRef event,
void *refcon)
{
return CKeyLocker::isEnabled() ? NULL : event;
}
And the code I'm using to enable and disable the event tap looks like this:
void CKeyLocker::enable(bool bEnable)
{
if (bEnable == m_bEnabled)
return;
if (bEnable)
{
// which events are we interested in?
CGEventMask evMask = kCGEventMaskForAllEvents;
CFMachPortRef mp = CGEventTapCreate(kCGHIDEventTap,
kCGHeadInsertEventTap,
kCGEventTapOptionDefault,
evMask,
MyTapCallback,
NULL);
if (mp)
{
qDebug() << "Tap created and active. mp =" << mp;
m_enabledTap = mp;
m_bEnabled = true;
}
}
else
{
CGEventTapEnable(m_enabledTap, false);
CFRelease(m_enabledTap);
m_enabledTap =0;
m_bEnabled = false;
qDebug() << "Tap destroyed and inactive";
}
}
This approach works very well while the event tap is active - I can hammer on the keyboard and mouse as much as I want and no events make it through the system. However, when the tap is disabled all the keys I pushed while the tap was active appear in the current window. It's like the event tap is just delaying the events, rather than destroying them, which is odd, since the Mac documentation clearly states:
If the event tap is an active filter, your callback function should return one of the following:
The (possibly modified) event that is passed in. This event is passed back to the event system.
A newly-constructed event. After the new event has been passed back to the event system, the new event will be released along with the original event.
NULL if the event passed in is to be deleted.
I'm returning NULL, but the event doesn't seem to be deleted. Any ideas?
The linked comment does not have an answer from what I see, so I'll dump some info from what I've seen when poking around with this stuff.
First, I have much better luck with CGEventTapCreateForPSN. It's as if the system gives you some leeway for restricting your tap. However, from this example it looks like this is not sufficient.
Next up - and this /may/ be all you need... In your call back, you probably want (and may need) to check for the following events:
switch (type)
{
case kCGEventTapDisabledByTimeout:
case kCGEventTapDisabledByUserInput:
{
CFMachPortRef *pTap = (CFMachPortRef*)refcon;
CGEventTapEnable( *pTap, true );
return NULL;
}
default:
break;
}
Regardless of what the various documentation does or doesn't say, it's been my observation that the OS feels like it's 'probing' for bad callbacks; basically disabling event tap callbacks that are universally eating events. If you re-register in these cases the OS seems to be ok with it, as if saying: OK, you seem to know what you're doing, but I'll probably poke you again in a bit to make sure.
It's really strange, we use event taps for the same purpose (input blocking in a given scenario) and works perfectly 10.4 - 10.8.2. excpet one thing, it should not block or receive events from a password dialog (which is not a big surprise)
What I can see now is different compared to you sample is:
we use kCGTailAppendEventTap instead of kCGHeadInsertEventTap (this should not matter)
we do some event logging in the installed callback
we have some user event data in some self injected events, that filtered out, but apart from this we simply return NULL to drop an unwanted event (like you do), I can confirm, not all events are ignorable!
we turn on/off the event tap this way:
bool SetInputFilter(bool bOn)
{
bool result = false;
CFRunLoopRef runLoopRef = CFRunLoopGetMain();
if (bOn) {
// Create an event tap.
CGEventMask eventMask = kCGEventMaskForAllEvents;
if ((m_eventTapInput = CGEventTapCreate(kCGHIDEventTap,
kCGTailAppendEventTap,
kCGEventTapOptionDefault,
eventMask, CGInputEventCallback, this)) == NULL) {
Log(L"Failed to create event tap");
return result;
}
// Create a run loop source.
m_runLoopEventTapSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, m_eventTapInput, 0);
CFRelease(m_eventTapInput); // CFMachPortCreateRunLoopSource retains m_eventTapInput
if (m_runLoopEventTapSource == NULL) {
Log(L"Failed to create run loop source for event tap");
return result;
}
// Add to the current run loop.
CFRunLoopAddSource(runLoopRef, m_runLoopEventTapSource, kCFRunLoopCommonModes);//kCFRunLoopDefaultMode);
CFRelease(m_runLoopEventTapSource); // CFRunLoopAddSource retains m_runLoopEventTapSource
result = true;
}
else {
// Disable the event tap.
if (m_eventTapInput)
CGEventTapEnable(m_eventTapInput, false);
// Remove our run loop source from the current run loop.
if (runLoopRef && m_runLoopEventTapSource) {
CFRunLoopRemoveSource(runLoopRef, m_runLoopEventTapSource, kCFRunLoopCommonModes);//kCFRunLoopDefaultMode);
m_runLoopEventTapSource = NULL; // removing m_runLoopEventTapSource releases last reference of m_runLoopEventTapSource too
m_eventTapInput = NULL; // removing m_runLoopEventTapSource releases last reference of m_eventTapInput too
}
}
return result;
}
I can verify that returning NULL does effectively delete some events, but i have also seen times when it does not, exactly how it decides what deletions to permit is unclear but it looks like mass deletions seem to be prevented e.g.: when you delete more than 100 events or so in a row.