I am trying to send an X event based on this example and the comments that followed it:
#include <X11/Xlib.h>
#include <X11/keysym.h>
#include <cstdio>
#include <iostream>
#include <string>
#include <unistd.h>
// #include <X11/extensions/XTest.h> // Uncomment to use XTestFakeKeyEvent()
// The key code to be sent.
// A full list of available codes can be found in /usr/include/X11/keysymdef.h
#define KEYCODE XK_Down
// Function to create an X11 keyboard event
// http://www.doctort.org/adam/nerd-notes/x11-fake-keypress-event.html
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 = XKeysymToKeycode(display, keycode);
event.state = modifiers;
if (press)
event.type = KeyPress;
else
event.type = KeyRelease;
return event;
}
int main() {
// Obtain the X11 display.
Display *display = XOpenDisplay(0);
if (display == NULL) return -1;
// Get the root window for the current display.
Window winRoot = XDefaultRootWindow(display);
// Find the window which has the current keyboard focus.
Window winFocus;
int revert;
XGetInputFocus(display, &winFocus, &revert);
// Send a fake key press event to the window.
XKeyEvent event =
createKeyEvent(display, winFocus, winRoot, true, KEYCODE, 0);
int res = XSendEvent(event.display, event.window, True, KeyPressMask,
(XEvent *)&event);
// int res =
// XTestFakeKeyEvent(event.display, event.keycode, True, CurrentTime);
std::cout << ((res != 0) ? std::string("Sent successfully")
: std::string("Sending failed")) << std::endl;
sleep(1);
if (XPending(display))
std::cout << "Got it!" << std::endl;
else
std::cout << "It's lost..." << std::endl;
// Done.
XCloseDisplay(display);
return 0;
}
Based on the output, the event gets sent OK and then gets lost, whether I use XSendEvent or XTestFakeKeyEvent (the commented out code). I am compiling the code with gcc 4.8.2 under Ubuntu 14.04. What is missing?
In order to receive events, an X11 application generally need to register an interest in them. This is done with the XSelectInput function:
XSelectInput(display, winFocus, KeyPressMask|KeyReleaseMask);
tells X11 that this client wants to receive key-press and key-release events associated with winFocus.
Related
I am making a simple xcb application and I noticed that when XCB_EVENT_MASK_KEY_PRESS is in the event mask and XCB_EVENT_MASK_KEY_RELEASE is not in the event mask I still get XCB_KEY_RELEASE events in my event loop if I hold down a key so that it repeats the key press event. Surely if XCB_EVENT_MASK_KEY_RELEASE is not in the event mask I should never get an XCB_KEY_RELEASE event?
Minimum reproducible example:
Run and hold down a key for a few seconds so that the keypress event repeats. This causes the key release event despite XCB_EVENT__MASK_KEY_RELEASE not being in the event mask.
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <xcb/xcb.h>
/* notice that the event mask does not conatin XCB_EVENT_MASK_KEY_RLEASE */
const uint32_t EVENT_MASK
= XCB_EVENT_MASK_EXPOSURE
| XCB_EVENT_MASK_KEY_PRESS;
int main()
{
int screenNum;
xcb_connection_t* xcon = xcb_connect(NULL, &screenNum);
const xcb_setup_t* xsetup = xcb_get_setup(xcon);
xcb_screen_t* screen;
{
xcb_screen_iterator_t iter = xcb_setup_roots_iterator(xsetup);
for (int i = 0; i < screenNum; i++)
xcb_screen_next(&iter);
screen = iter.data;
}
xcb_window_t window = xcb_generate_id(xcon);
uint32_t winvals[] = { screen->white_pixel, EVENT_MASK };
xcb_create_window(
xcon,
XCB_COPY_FROM_PARENT,
window,
screen->root,
10, 10,
150, 150,
10,
XCB_WINDOW_CLASS_INPUT_OUTPUT,
screen->root_visual,
XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK, winvals);
xcb_map_window(xcon, window);
xcb_flush(xcon);
xcb_generic_event_t* event;
while ((event = xcb_wait_for_event(xcon))) {
switch (event->response_type & ~0x80) {
case XCB_EXPOSE: {
// TODO: draw something
xcb_flush(xcon);
break;
}
case XCB_KEY_PRESS: {
xcb_key_press_event_t* kp = (xcb_key_press_event_t*)event;
printf("key pressed: %u\n", kp->detail);
break;
}
case XCB_KEY_RELEASE: {
puts("KEY RELEASE EVENT?!");
break;
}
default: {
printf("unknown event. type = %u\n", event->response_type);
break;
}
}
free(event);
}
xcb_disconnect(xcon);
return 0;
}
There are many examples on how to handle the closing of a window using XLib, which can be found on the internet:
http://cboard.cprogramming.com/linux-programming/60466-xwindows-close-window-event.html
https://en.wikibooks.org/wiki/X_Window_Programming/XLib
https://john.nachtimwald.com/2009/11/01/x11-intercept-window-close-event/
There are several more. That said I have tried to implement them in code, as seen below. However when I click on X in the corner of my window I get no event sent to my message loop. Is this because XChcekWindowEvent ignores or does not process Client Messages? If this is not the case what are some other things I should be looking for to get messages from XLib set using SetWMProtocols?
m_impl->m_delete_window = XInternAtom(display, "WM_DELETE_WINDOW", False);
if (!XSetWMProtocols(display, window, &m_impl->m_delete_window, 1)) {
std::cout << "Set Window Protocols Failed" << std::endl;
}
...
while (!terminate) {
while (::XCheckWindowEvent(display, window, events::mask, &x_event)) {
if (x_event.type == ClientMessage) {
std::cout << "Client Message" << std::endl;
if ((Atom)x_event.xclient.data.l[0] == m_impl->m_delete_window) {
terminate = true;
}
}
}
}
The XCheckWindowEvent() will not return ClientMessage. It returns none of the non maskable ones. Work around:
while (XPending(display))
{
XNextEvent(display, &event);
But could create extra work to filter event by window.
BR Pekka
If you want to prevent using XNextEvent (which is not applied in real-time event loops), you may use the following code based on XCheckTypedWindowEvent:
// Globals
Atom wm_protocols;
Atom wm_delete_window;
// Functions
void PreventClose(Display* disp, Window& win)
{
wm_protocols = XInternAtom(disp, "WM_PROTOCOLS", false);
wm_delete_window = XInternAtom(disp, "WM_DELETE_WINDOW", false);
XSetWMProtocols(disp, win, &wm_delete_window, 1);
}
bool IsClosed(Display* disp, Window& win)
{
XEvent e;
if (XCheckTypedWindowEvent(disp, win, ClientMessage, &e))
if (e.xclient.message_type == wm_protocols &&
e.xclient.data.l[0] == wm_delete_window_)
return true;
return false;
}
// Usage
int main()
{
...
PreventClose(disp, win);
do {
if (IsClosed(disp, win))
// break, some actions, etc...
...
} while(true);
return 0;
}
For more info see man 3 XCheckTypedWindowEvent
So I'm learning SDL and I'm trying to make a basic menu. The menu consists of "Start", below it "Load" and below it "Quit". None of them have a function, they're just for show.
What I'm doing is adding a box that surrounds the selected option. I tried to make it so whenever up or down is pressed on the keyboard, the counter will be incremented or lowered by one and the box will move up or down. However, every time I press one of the buttons the counter goes to huge numbers. I know that because I wrote alongside code that displays the counter on the screen.
I would really appreciate any help with what I'm doing wrong.
screenshot: http://i.imgur.com/6Io8cLj.png
PS: I'm using a header file with a function apply_surface() so I'll add it first.
Start of head.h:
#ifndef CYOP_H_HEADER
#define CYOP_H_HEADER
#include "SDL/SDL.h"
#include "SDL/SDL_image.h"
#include "SDL/SDL_ttf.h"
using namespace std;
void apply_surface(int x, int y, SDL_Surface* source, SDL_Surface* destination)
{
SDL_Rect offset;
offset.x = x;
offset.y = y;
Uint32 colorkey = SDL_MapRGB( source->format, 0, 0xFF, 0xFF );
SDL_SetColorKey(source, SDL_SRCCOLORKEY, colorkey);
SDL_BlitSurface(source, NULL, destination, &offset);
}
#endif
Start of main.cpp:
#include "SDL/SDL.h"
#include "SDL/SDL_image.h"
#include "SDL/SDL_ttf.h"
#include "head.h"
#include <string>
#include <sstream>
using namespace std;
// Text rendering parts
TTF_Font *font = NULL;
SDL_Color color = {255, 0, 0};
int cur=0; // Current Menu Item (0 is start, 1 is Load, 2 is Quit)
string str = "Counter: ";
string num;
string strc = str+num;
bool quitp = false; //Quit Program bool
ostringstream convert;
SDL_Surface* background = NULL;
SDL_Surface* start = NULL;
SDL_Surface* load = NULL;
SDL_Surface* quit = NULL;
SDL_Surface* screen = NULL;
SDL_Surface* select = NULL;
SDL_Surface* message = NULL;
SDL_Event event;
void selected(int n)
/*Function that is supposed to reload all images again,
only the "select" picture at a different place**/
{
convert << cur;
num=convert.str();
strc=str+num;
message = TTF_RenderText_Solid(font, strc.c_str(), color); // Renders "Counter: *number
of cur **/
int arr[3]={50, 100, 150};
apply_surface(0,0,background,screen);
apply_surface(60,50,start,screen);
apply_surface(60,100,load,screen);
apply_surface(60,150,quit,screen);
apply_surface(0, 0, message, screen);
apply_surface(60, arr[n], select, screen);
SDL_Flip(screen);
}
int main(int argc, char* args[])
{
SDL_Init(SDL_INIT_EVERYTHING);
TTF_Init();
screen = SDL_SetVideoMode(300, 300, 32, SDL_SWSURFACE);
font = TTF_OpenFont("grasping.ttf", 28);
message = TTF_RenderText_Solid(font, strc.c_str(), color);
background = IMG_Load ("background.bmp");
start = IMG_Load ("start1.bmp");
load = IMG_Load ("load1.bmp");
quit = IMG_Load ("quit1.bmp");
select = IMG_Load ("select.bmp");
apply_surface(0,0,background,screen);
apply_surface(60,50,start,screen);
apply_surface(60,100,load,screen);
apply_surface(60,150,quit,screen);
apply_surface(60, 50, select, screen);
apply_surface(0, 0, message, screen);
SDL_Flip(screen);
while(quitp==false)
{
if(SDL_PollEvent(&event));
{
if (event.type == SDL_QUIT)
{
quitp = true;
}
if (event.type == SDL_KEYDOWN)
{
SDLKey keyPressed = event.key.keysym.sym;
switch (keyPressed)
{
case SDLK_DOWN:
cur++;
break;
case SDLK_UP:
cur--;
break;
default: break;
}selected(cur);
}// Closing if(event.type == SDL_KEYDOWN)
}// Closing if(SDL_PollEvent)
} // Closing main while loop
SDL_Quit();
return 0;
}
There are two problems:
The first is a classic rookie mistake:
if(SDL_PollEvent(&event));
What you meant to do here is this:
if(SDL_PollEvent(&event))
Amazing what a difference one character makes!
The second issue is this:
However, every time I press one of the buttons the counter goes to
huge numbers. I know that because I wrote alongside code that displays
the counter on the screen.
You need to look a little more closely at that screenshot. The number it's printing out is 123456789101112. See the pattern there?
cur = 1, strc = "Counter: 1"
cur = 2, strc = "Counter: 12"
cur = 3, strc = "Counter: 123"
cur = 4, strc = "Counter: 1234"
..etc
The way you're using the string stream just appends the number each time. The easy solutions here are to either not use the same string stream each time, or to reset it to the empty string.
How can I simulate a mouse event causing the pointer to move 500 pixels to the left, then click using C++. How would I do something like this?
Here's some modified Win32 code I had lying around:
#define WIN32_LEAN_AND_MEAN
#define _WIN32_WINNT 0x0500
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <conio.h>
#include <string.h>
#include <windows.h>
#define X 123
#define Y 123
#define SCREEN_WIDTH 1024
#define SCREEN_HEIGHT 800
void MouseSetup(INPUT *buffer)
{
buffer->type = INPUT_MOUSE;
buffer->mi.dx = (0 * (0xFFFF / SCREEN_WIDTH));
buffer->mi.dy = (0 * (0xFFFF / SCREEN_HEIGHT));
buffer->mi.mouseData = 0;
buffer->mi.dwFlags = MOUSEEVENTF_ABSOLUTE;
buffer->mi.time = 0;
buffer->mi.dwExtraInfo = 0;
}
void MouseMoveAbsolute(INPUT *buffer, int x, int y)
{
buffer->mi.dx = (x * (0xFFFF / SCREEN_WIDTH));
buffer->mi.dy = (y * (0xFFFF / SCREEN_HEIGHT));
buffer->mi.dwFlags = (MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE);
SendInput(1, buffer, sizeof(INPUT));
}
void MouseClick(INPUT *buffer)
{
buffer->mi.dwFlags = (MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_LEFTDOWN);
SendInput(1, buffer, sizeof(INPUT));
Sleep(10);
buffer->mi.dwFlags = (MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_LEFTUP);
SendInput(1, buffer, sizeof(INPUT));
}
int main(int argc, char *argv[])
{
INPUT buffer[1];
MouseSetup(&buffer);
MouseMoveAbsolute(&buffer, X, Y);
MouseClick(&buffer);
return 0;
}
You'll need to call MouseSetup() to each INPUT buffer before you use it.
Resources
MSDN - SendInput()
MSDN - INPUT
MSDN - MOUSEINPUT
Here is a solution using Xlib for those who use Linux :
#include <X11/Xlib.h>
#include<stdio.h>
#include<unistd.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
void mouseClick(int button)
{
Display *display = XOpenDisplay(NULL);
XEvent event;
if(display == NULL)
{
fprintf(stderr, "Errore nell'apertura del Display !!!\n");
exit(EXIT_FAILURE);
}
memset(&event, 0x00, sizeof(event));
event.type = ButtonPress;
event.xbutton.button = button;
event.xbutton.same_screen = True;
XQueryPointer(display, RootWindow(display, DefaultScreen(display)), &event.xbutton.root, &event.xbutton.window, &event.xbutton.x_root, &event.xbutton.y_root, &event.xbutton.x, &event.xbutton.y, &event.xbutton.state);
event.xbutton.subwindow = event.xbutton.window;
while(event.xbutton.subwindow)
{
event.xbutton.window = event.xbutton.subwindow;
XQueryPointer(display, event.xbutton.window, &event.xbutton.root, &event.xbutton.subwindow, &event.xbutton.x_root, &event.xbutton.y_root, &event.xbutton.x, &event.xbutton.y, &event.xbutton.state);
}
if(XSendEvent(display, PointerWindow, True, 0xfff, &event) == 0) fprintf(stderr, "Error\n");
XFlush(display);
usleep(100000);
event.type = ButtonRelease;
event.xbutton.state = 0x100;
if(XSendEvent(display, PointerWindow, True, 0xfff, &event) == 0) fprintf(stderr, "Error\n");
XFlush(display);
XCloseDisplay(display);
}
int main(int argc, char * argv[]) {
int x , y;
x = atoi(argv[1]);
y = atoi(argv[2]);
Display *display = XOpenDisplay(0);
Window root = DefaultRootWindow(display);
XWarpPointer(display, None, root, 0, 0, 0, 0, x, y);
mouseClick(Button1);
XFlush(display);
XCloseDisplay(display);
return 0;
}
Just Build it and then to simulate a click at x ,y do:
$ ./a.out x y
i.e.
$g++ -lX11 sgmousesim2.cpp
$./a.out 123 13
Use SendInput to generate the input you want to simulate. From MSDN documentation:
Synthesizes keystrokes, mouse motions, and button clicks.
I have never did this using C++. Nevertheless, there is a Java class called Robot which is able to produce mouse events. I used this back on Java version 1.4 but it does still work. I tried the example from this Simulate a physical mouse move in Mac OS X. It runs smoothly with Oracle Java 1.6.0_26 on MacOSX Lion. The good about Java is that it is platform independent.
import java.awt.AWTException;
import java.awt.Robot;
public final class MovingMouseDemo
{
public static void main(String[] args) throws AWTException
{
Robot robot = new Robot();
robot.setAutoDelay(5);
robot.setAutoWaitForIdle(true);
//put mouse in the top left of the screen
robot.mouseMove(0, 0);
//wait so that you can see the result
robot.delay(1000);
//put the mouse 200 pixels away from the top
//10 pixels away from the left
robot.mouseMove(200, 10);
robot.delay(1000);
robot.mouseMove(40, 130);
}
}
You can still use JNI to bind it with C++.
I hope it helps
C++ alone can't do this. It has no concept of a "mouse", let alone a "click".
You need some sort of library which talks to your windowing system. For example, QT. Then it's a matter of searching through the API and making the right C++ calls.
Use the mouse_event function.
I wrote a code in mfc for login form
my code is here
// login1Dlg.cpp : implementation file
//
#include "stdafx.h"
#include "login1.h"
#include "login1Dlg.h"
#include "afxdialogex.h"
//#include "LOGINDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// Clogin1Dlg dialog
Clogin1Dlg::Clogin1Dlg(CWnd* pParent /*=NULL*/)
: CDialogEx(Clogin1Dlg::IDD, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
m_username = _T("");
m_password = _T("");
}
void Clogin1Dlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Text(pDX, IDC_USERNAME_EDIT, m_username);
DDX_Text(pDX, IDC_PASSWORD_EDIT, m_password);
}
BEGIN_MESSAGE_MAP(Clogin1Dlg, CDialogEx)
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_OK_BUTTON, &Clogin1Dlg::OnBnClickedOkButton)
END_MESSAGE_MAP()
// Clogin1Dlg message handlers
BOOL Clogin1Dlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
// TODO: Add extra initialization here
return TRUE; // return TRUE unless you set the focus to a control
}
// If you add a minimize button to your dialog, you will need the code below
// to draw the icon. For MFC applications using the document/view model,
// this is automatically done for you by the framework.
void Clogin1Dlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialogEx::OnPaint();
}
}
// The system calls this function to obtain the cursor to display while the user drags
// the minimized window.
HCURSOR Clogin1Dlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}
void Clogin1Dlg::OnBnClickedOkButton()
{
// TODO: Add your control notification handler code here
UpdateData();
char UsernameFromFile[20], PasswordFromFile[20];
FILE *fleCredentials;
bool ValidLogin = false;
if(m_username == "" )
{
AfxMessageBox(_T("You must provide a username and a password or click Cancel"));
return;
}
if( m_password == "" )
{
AfxMessageBox(_T("Invalid Login"));
return;
}
try {
// Open the file for reading
fleCredentials = fopen("credentials.txt", "r");
// Scan the file from beginning to end
while( !feof(fleCredentials) )
{
//Read a username
fscanf(fleCredentials, "%s", UsernameFromFile);
//Compare the typed username with the username from the file
if(strcmp((LPCTSTR)m_username, UsernameFromFile) == 0 )
{
// With the current username, retrieve the corresponding password
fscanf(fleCredentials, "%s", PasswordFromFile);
//Compare the typed password with the one on file
if( strcmp((LPCTSTR)m_password, PasswordFromFile) == 0 )
{
ValidLogin = true;
}
else
ValidLogin = false;
}
}
if( ValidLogin == true )
OnOK();
else
{
AfxMessageBox(_T("Invalid Credentials. Please try again"));
//this->m_EditUsername.SetFocus();
}
fclose(fleCredentials);
}
catch(...)
{
AfxMessageBox(_T("Could not validate the credentials"));
}
UpdateData(FALSE);
}
But I got this error
Error 3 error C2664: 'strcmp' : cannot convert parameter 1 from 'LPCTSTR' to 'const char *' e:\win32\test\login1\login1dlg.cpp 130 1 login1
i want little help from u
try Change the 2 if statement code to this
if(strcmp((LPSTR)(LPCTSTR)m_username, UsernameFromFile) == 0 )
if( strcmp((LPSTR)(LPCTSTR)m_password, PasswordFromFile) == 0 )
from the error i can see cannot convert parameter 1 from 'LPCTSTR' to 'const char *'
strcmp is used with char ANSI but try using the Unicode version of it instead
as you know LPCTSTR is dependent on unicode or ansi if you use unicode library use the following function wcscmp for more information help at msdn
also for types windows data types on msdn
so you replace strcmp at line 129 and 135 with wcscmp if this solve the problem just let us know