mirror of
https://github.com/reactos/reactos.git
synced 2025-05-25 12:14:32 +00:00
add window selection and picking utils from cxtest for Art's regression tests
svn path=/trunk/; revision=19149
This commit is contained in:
parent
b02a62a257
commit
0303a440e3
2 changed files with 905 additions and 0 deletions
686
rosapps/tests/wclickat/wclickat.c
Normal file
686
rosapps/tests/wclickat/wclickat.c
Normal file
|
@ -0,0 +1,686 @@
|
|||
/*----------------------------------------------------------------------------
|
||||
** wclickat.c
|
||||
** Utilty to send clicks to Wine Windows
|
||||
**
|
||||
** See usage() for usage instructions.
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2004 Jozef Stefanka for CodeWeavers, Inc.
|
||||
** Copyright 2005 Dmitry Timoshkov for CodeWeavers, Inc.
|
||||
** Copyright 2005 Francois Gouget for CodeWeavers, Inc.
|
||||
**
|
||||
** This program is free software; you can redistribute it and/or modify
|
||||
** it under the terms of the GNU General Public License as published by
|
||||
** the Free Software Foundation; either version 2 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
**
|
||||
**--------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
#include <windows.h>
|
||||
#include <windowsx.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
|
||||
#define APP_NAME "wclickat"
|
||||
#define DEFAULT_DELAY 500
|
||||
#define DEFAULT_REPEAT 1000
|
||||
|
||||
#define ARRAY_LENGTH(array) (sizeof(array)/sizeof((array)[0]))
|
||||
|
||||
static const WCHAR STATIC_CLASS[]={'s','t','a','t','i','c','\0'};
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
** Global variables
|
||||
**--------------------------------------------------------------------------*/
|
||||
|
||||
#define RC_RUNNING -1
|
||||
#define RC_SUCCESS 0
|
||||
#define RC_INVALID_ARGUMENTS 1
|
||||
#define RC_NODISPLAY 2
|
||||
#define RC_TIMEOUT 3
|
||||
static int status;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
ACTION_INVALID,
|
||||
ACTION_FIND,
|
||||
ACTION_LCLICK,
|
||||
ACTION_MCLICK,
|
||||
ACTION_RCLICK
|
||||
} action_type;
|
||||
static action_type g_action = ACTION_INVALID;
|
||||
|
||||
static WCHAR* g_window_class = NULL;
|
||||
static WCHAR* g_window_title = NULL;
|
||||
static long g_control_id = 0;
|
||||
static WCHAR* g_control_class = NULL;
|
||||
static WCHAR* g_control_caption = NULL;
|
||||
static long g_x = -1;
|
||||
static long g_y = -1;
|
||||
static long g_dragto_x = -1;
|
||||
static long g_dragto_y = -1;
|
||||
static long g_disabled = 0;
|
||||
|
||||
static long g_delay = DEFAULT_DELAY;
|
||||
static long g_timeout = 0;
|
||||
static long g_repeat = 0;
|
||||
static long g_untildeath = 0;
|
||||
static UINT timer_id;
|
||||
|
||||
|
||||
/*
|
||||
* Provide some basic debugging support.
|
||||
*/
|
||||
#ifdef __GNUC__
|
||||
#define __PRINTF_ATTR(fmt,args) __attribute__((format (printf,fmt,args)))
|
||||
#else
|
||||
#define __PRINTF_ATTR(fmt,args)
|
||||
#endif
|
||||
static int debug_on=0;
|
||||
static int init_debug()
|
||||
{
|
||||
char* str=getenv("CXTEST_DEBUG");
|
||||
if (str && strstr(str, "+wclickat"))
|
||||
debug_on=1;
|
||||
return debug_on;
|
||||
}
|
||||
|
||||
static void cxlog(const char* format, ...) __PRINTF_ATTR(1,2);
|
||||
static void cxlog(const char* format, ...)
|
||||
{
|
||||
va_list valist;
|
||||
|
||||
if (debug_on)
|
||||
{
|
||||
va_start(valist, format);
|
||||
vfprintf(stderr, format, valist);
|
||||
va_end(valist);
|
||||
}
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
** usage
|
||||
**--------------------------------------------------------------------------*/
|
||||
static void usage(void)
|
||||
{
|
||||
fprintf(stderr, "%s - Utility to send clicks to Wine Windows.\n", APP_NAME);
|
||||
fprintf(stderr, "----------------------------------------------\n");
|
||||
fprintf(stderr, "Usage:\n");
|
||||
fprintf(stderr, " %s action --winclass class --wintitle title [--timeout ms]\n",APP_NAME);
|
||||
fprintf(stderr, " %*.*s [--ctrlclas class] [--ctrlcaption caption] [--ctrlid id]\n", strlen(APP_NAME) + 3, strlen(APP_NAME) + 3, "");
|
||||
fprintf(stderr, " %*.*s [--position XxY] [--delay ms] [--untildeath] [--repeat ms]\n", strlen(APP_NAME) + 3, strlen(APP_NAME) + 3, "");
|
||||
fprintf(stderr, "Where action can be one of:\n");
|
||||
fprintf(stderr, " find Find the specified window or control\n");
|
||||
fprintf(stderr, " button<n> Send a click with the given X button number\n");
|
||||
fprintf(stderr, " click|lclick Synonym for button1 (left click)\n");
|
||||
fprintf(stderr, " mclick Synonym for button2 (middle click)\n");
|
||||
fprintf(stderr, " rclick Synonym for button3 (right click)\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "The options are as follows:\n");
|
||||
fprintf(stderr, " --timeout ms How long to wait before failing with a code of %d\n", RC_TIMEOUT);
|
||||
fprintf(stderr, " --winclass class Class name of the top-level window of interest\n");
|
||||
fprintf(stderr, " --wintitle title Title of the top-level window of interest\n");
|
||||
fprintf(stderr, " --ctrlclass name Class name of the control of interest, if any\n");
|
||||
fprintf(stderr, " --ctrlcaption cap A substring of the control's caption\n");
|
||||
fprintf(stderr, " --ctrlid id Id of the control\n");
|
||||
fprintf(stderr, " --position XxY Coordinates for the click, relative to the window / control\n");
|
||||
fprintf(stderr, " --dragto If given, then position specifies start click, and\n");
|
||||
fprintf(stderr, " dragto specifies release coords.\n");
|
||||
fprintf(stderr, " --allow-disabled Match the window or control even hidden or disabled\n");
|
||||
fprintf(stderr, " --delay ms Wait ms milliseconds before clicking. The default is %d\n", DEFAULT_DELAY);
|
||||
fprintf(stderr, " --untildeath Wait until the window disappears\n");
|
||||
fprintf(stderr, " --repeat ms Click every ms milliseconds. The default is %d\n", DEFAULT_REPEAT);
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "%s returns %d on success\n", APP_NAME, RC_SUCCESS);
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "Environment variable overrides:\n");
|
||||
fprintf(stderr, " CXTEST_TIME_MULTIPLE Specifies a floating multiplier applied to any\n");
|
||||
fprintf(stderr, " delay and timeout parameters.\n");
|
||||
}
|
||||
|
||||
static const WCHAR* my_strstriW(const WCHAR* haystack, const WCHAR* needle)
|
||||
{
|
||||
const WCHAR *h,*n;
|
||||
WCHAR first;
|
||||
|
||||
if (!*needle)
|
||||
return haystack;
|
||||
|
||||
/* Special case the first character because
|
||||
* we will be doing a lot of comparisons with it.
|
||||
*/
|
||||
first=towlower(*needle);
|
||||
needle++;
|
||||
while (*haystack)
|
||||
{
|
||||
while (towlower(*haystack)!=first && *haystack)
|
||||
haystack++;
|
||||
|
||||
h=haystack+1;
|
||||
n=needle;
|
||||
while (towlower(*h)==towlower(*n) && *h)
|
||||
{
|
||||
h++;
|
||||
n++;
|
||||
}
|
||||
if (!*n)
|
||||
return haystack;
|
||||
haystack++;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static BOOL CALLBACK find_control(HWND hwnd, LPARAM lParam)
|
||||
{
|
||||
WCHAR str[1024];
|
||||
HWND* pcontrol;
|
||||
|
||||
if (!GetClassNameW(hwnd, str, ARRAY_LENGTH(str)) ||
|
||||
lstrcmpiW(str, g_control_class))
|
||||
return TRUE;
|
||||
|
||||
if (g_control_caption)
|
||||
{
|
||||
if (!GetWindowTextW(hwnd, str, ARRAY_LENGTH(str)) ||
|
||||
!my_strstriW(str, g_control_caption))
|
||||
return TRUE;
|
||||
}
|
||||
if (g_control_id && g_control_id != GetWindowLong(hwnd, GWL_ID))
|
||||
return TRUE;
|
||||
|
||||
/* Check that the control is visible and active */
|
||||
if (!g_disabled)
|
||||
{
|
||||
DWORD style = GetWindowStyle(hwnd);
|
||||
if (!(style & WS_VISIBLE) || (style & WS_DISABLED))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
pcontrol = (HWND*)lParam;
|
||||
*pcontrol = hwnd;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static BOOL CALLBACK find_top_window(HWND hwnd, LPARAM lParam)
|
||||
{
|
||||
WCHAR str[1024];
|
||||
HWND* pwindow;
|
||||
|
||||
if (!GetClassNameW(hwnd, str, ARRAY_LENGTH(str)) ||
|
||||
lstrcmpiW(str, g_window_class))
|
||||
return TRUE;
|
||||
|
||||
if (!GetWindowTextW(hwnd, str, ARRAY_LENGTH(str)) ||
|
||||
lstrcmpiW(str, g_window_title))
|
||||
return TRUE;
|
||||
|
||||
/* Check that the window is visible and active */
|
||||
if (!g_disabled)
|
||||
{
|
||||
DWORD style = GetWindowStyle(hwnd);
|
||||
if (!(style & WS_VISIBLE) || (style & WS_DISABLED))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* See if we find the control we want */
|
||||
if (g_control_class)
|
||||
{
|
||||
HWND control = NULL;
|
||||
EnumChildWindows(hwnd, find_control, (LPARAM)&control);
|
||||
if (!control)
|
||||
return TRUE;
|
||||
hwnd=control;
|
||||
}
|
||||
|
||||
pwindow = (HWND*)lParam;
|
||||
*pwindow = hwnd;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static HWND find_window()
|
||||
{
|
||||
HWND hwnd;
|
||||
|
||||
hwnd=NULL;
|
||||
EnumWindows(find_top_window, (LPARAM)&hwnd);
|
||||
return hwnd;
|
||||
}
|
||||
|
||||
static void do_click(HWND window, DWORD down, DWORD up)
|
||||
{
|
||||
WINDOWINFO window_info;
|
||||
long x, y;
|
||||
|
||||
SetForegroundWindow(GetParent(window));
|
||||
window_info.cbSize=sizeof(window_info);
|
||||
GetWindowInfo(window, &window_info);
|
||||
|
||||
/* The calculations below convert the coordinates so they are absolute
|
||||
* screen coordinates in 'Mickeys' as required by mouse_event.
|
||||
* In mickeys the screen size is always 65535x65535.
|
||||
*/
|
||||
x=window_info.rcWindow.left+g_x;
|
||||
if (x<window_info.rcWindow.left || x>=window_info.rcWindow.right)
|
||||
x=(window_info.rcWindow.right+window_info.rcWindow.left)/2;
|
||||
x=(x << 16)/GetSystemMetrics(SM_CXSCREEN);
|
||||
|
||||
y=window_info.rcWindow.top+g_y;
|
||||
if (y<window_info.rcWindow.top || y>=window_info.rcWindow.bottom)
|
||||
y=(window_info.rcWindow.bottom+window_info.rcWindow.top)/2;
|
||||
y=(y << 16)/GetSystemMetrics(SM_CYSCREEN);
|
||||
|
||||
mouse_event(MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE, x, y, 0, 0);
|
||||
if (down) {
|
||||
mouse_event(MOUSEEVENTF_ABSOLUTE | down, x, y, 0, 0);
|
||||
if ((g_dragto_x > 0) && (g_dragto_y > 0)) {
|
||||
int i;
|
||||
long dx, dy;
|
||||
long step_per_x, step_per_y;
|
||||
long dragto_x, dragto_y;
|
||||
|
||||
dragto_x=window_info.rcWindow.left+g_dragto_x;
|
||||
if (dragto_x<window_info.rcWindow.left || dragto_x>=window_info.rcWindow.right)
|
||||
dragto_x=(window_info.rcWindow.right+window_info.rcWindow.left)/2;
|
||||
dragto_x=(dragto_x << 16)/GetSystemMetrics(SM_CXSCREEN);
|
||||
|
||||
dragto_y=window_info.rcWindow.top+g_dragto_y;
|
||||
if (dragto_y<window_info.rcWindow.top || dragto_y>=window_info.rcWindow.bottom)
|
||||
dragto_y=(window_info.rcWindow.bottom+window_info.rcWindow.top)/2;
|
||||
dragto_y=(dragto_y << 16)/GetSystemMetrics(SM_CYSCREEN);
|
||||
|
||||
dx = g_dragto_x - g_x;
|
||||
dy = g_dragto_y - g_y;
|
||||
step_per_x = dx / 4;
|
||||
step_per_y = dy / 4;
|
||||
for (i = 0; i < 4; i++) {
|
||||
mouse_event(MOUSEEVENTF_MOVE, step_per_x, step_per_y, 0, 0);
|
||||
}
|
||||
x=dragto_x;
|
||||
y=dragto_y;
|
||||
}
|
||||
}
|
||||
if (up)
|
||||
mouse_event(MOUSEEVENTF_ABSOLUTE | up, x, y, 0, 0);
|
||||
}
|
||||
|
||||
static void CALLBACK ClickProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
|
||||
{
|
||||
HWND window = find_window();
|
||||
|
||||
if (!window)
|
||||
{
|
||||
if (g_untildeath)
|
||||
{
|
||||
/* FIXME: The window / control might just be disabled and if
|
||||
* that's the case we should not exit yet. But I don't expect
|
||||
* --untildeath to be used at all anyway so fixing this can
|
||||
* wait until it becomes necessary.
|
||||
*/
|
||||
status=RC_SUCCESS;
|
||||
}
|
||||
else
|
||||
cxlog("The window has disappeared!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (g_action)
|
||||
{
|
||||
case ACTION_FIND:
|
||||
/* Nothing to do */
|
||||
break;
|
||||
case ACTION_LCLICK:
|
||||
cxlog("Sending left click\n");
|
||||
do_click(window, MOUSEEVENTF_LEFTDOWN, MOUSEEVENTF_LEFTUP);
|
||||
break;
|
||||
case ACTION_MCLICK:
|
||||
cxlog("Sending middle click\n");
|
||||
do_click(window, MOUSEEVENTF_MIDDLEDOWN, MOUSEEVENTF_MIDDLEUP);
|
||||
break;
|
||||
case ACTION_RCLICK:
|
||||
cxlog("Sending right click\n");
|
||||
do_click(window, MOUSEEVENTF_RIGHTDOWN, MOUSEEVENTF_RIGHTUP);
|
||||
default:
|
||||
fprintf(stderr, "error: unknown action %d\n", g_action);
|
||||
break;
|
||||
}
|
||||
if (!g_repeat)
|
||||
status=RC_SUCCESS;
|
||||
}
|
||||
|
||||
static void CALLBACK DelayProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
|
||||
{
|
||||
KillTimer(NULL, timer_id);
|
||||
timer_id=0;
|
||||
if (g_repeat)
|
||||
{
|
||||
cxlog("Setting up a timer for --repeat\n");
|
||||
timer_id=SetTimer(NULL, 0, g_repeat, ClickProc);
|
||||
}
|
||||
|
||||
ClickProc(NULL, 0, 0, 0);
|
||||
}
|
||||
|
||||
static void CALLBACK FindWindowProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
|
||||
{
|
||||
HWND window = find_window();
|
||||
if (!window)
|
||||
return;
|
||||
|
||||
cxlog("Found the window\n");
|
||||
if (g_delay)
|
||||
{
|
||||
cxlog("Waiting for a bit\n");
|
||||
KillTimer(NULL, timer_id);
|
||||
timer_id=SetTimer(NULL, 0, g_delay, DelayProc);
|
||||
do_click(window, 0,0);
|
||||
}
|
||||
else
|
||||
{
|
||||
DelayProc(NULL, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void CALLBACK TimeoutProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
|
||||
{
|
||||
status = RC_TIMEOUT;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
** parse_arguments
|
||||
**--------------------------------------------------------------------------*/
|
||||
static int arg_get_long(const char** *argv, const char* name, long* value)
|
||||
{
|
||||
if (!**argv)
|
||||
{
|
||||
fprintf(stderr, "error: missing argument for '%s'\n", name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
*value=atol(**argv);
|
||||
if (*value < 0)
|
||||
{
|
||||
fprintf(stderr, "error: invalid argument '%s' for '%s'\n",
|
||||
**argv, name);
|
||||
(*argv)++;
|
||||
return 1;
|
||||
}
|
||||
(*argv)++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int arg_get_utf8(const char** *argv, const char* name, WCHAR* *value)
|
||||
{
|
||||
int len;
|
||||
|
||||
if (!**argv)
|
||||
{
|
||||
fprintf(stderr, "error: missing argument for '%s'\n", name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
len = MultiByteToWideChar(CP_UTF8, 0, **argv, -1, NULL, 0);
|
||||
*value = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
|
||||
if (!*value)
|
||||
{
|
||||
fprintf(stderr, "error: memory allocation error\n");
|
||||
(*argv)++;
|
||||
return 1;
|
||||
}
|
||||
MultiByteToWideChar(CP_UTF8, 0, **argv, -1, *value, len);
|
||||
(*argv)++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_arguments(int argc, const char** argv)
|
||||
{
|
||||
int rc;
|
||||
const char* arg;
|
||||
char* p;
|
||||
|
||||
rc=0;
|
||||
argv++;
|
||||
while (*argv)
|
||||
{
|
||||
arg=*argv++;
|
||||
if (*arg!='-')
|
||||
{
|
||||
if (g_action != ACTION_INVALID)
|
||||
{
|
||||
fprintf(stderr, "error: '%s' an action has already been specified\n", arg);
|
||||
rc=1;
|
||||
}
|
||||
else if (strcmp(arg, "click") == 0 || strcmp(arg, "lclick") == 0)
|
||||
{
|
||||
g_action = ACTION_LCLICK;
|
||||
}
|
||||
else if (strcmp(arg, "mclick") == 0)
|
||||
{
|
||||
g_action = ACTION_MCLICK;
|
||||
}
|
||||
else if (strcmp(arg, "rclick") == 0)
|
||||
{
|
||||
g_action = ACTION_RCLICK;
|
||||
}
|
||||
else if (strncmp(arg, "button", 6) == 0)
|
||||
{
|
||||
int button;
|
||||
char extra='\0';
|
||||
int r=sscanf(arg, "button%d%c", &button, &extra);
|
||||
/* We should always get r==1 but due to a bug in Wine's
|
||||
* msvcrt.dll implementation (at least up to 20050127)
|
||||
* we may also get r==2 and extra=='\0'.
|
||||
*/
|
||||
if (r!=1 && (r!=2 || extra!='\0'))
|
||||
{
|
||||
fprintf(stderr, "error: invalid argument '%s' for '%s'\n",
|
||||
*argv, arg);
|
||||
rc=1;
|
||||
}
|
||||
else if (button<1 || button>3)
|
||||
{
|
||||
fprintf(stderr, "error: unknown button '%s'\n", arg);
|
||||
rc=1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Just to remain compatible with the enum */
|
||||
g_action=button+ACTION_LCLICK-1;
|
||||
}
|
||||
}
|
||||
else if (strcmp(arg, "find") == 0)
|
||||
{
|
||||
g_action = ACTION_FIND;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "error: unknown action '%s'\n", arg);
|
||||
rc=1;
|
||||
}
|
||||
}
|
||||
else if (strcmp(arg, "--winclass") == 0)
|
||||
{
|
||||
rc|=arg_get_utf8(&argv, arg, &g_window_class);
|
||||
}
|
||||
else if (strcmp(arg, "--wintitle") == 0)
|
||||
{
|
||||
rc|=arg_get_utf8(&argv,arg, &g_window_title);
|
||||
}
|
||||
else if (strcmp(arg, "--ctrlclass") == 0)
|
||||
{
|
||||
rc|=arg_get_utf8(&argv, arg, &g_control_class);
|
||||
}
|
||||
else if (strcmp(arg, "--ctrlid") == 0)
|
||||
{
|
||||
rc|=arg_get_long(&argv, arg, &g_control_id);
|
||||
}
|
||||
else if (strcmp(arg, "--ctrlcaption") == 0)
|
||||
{
|
||||
rc|=arg_get_utf8(&argv, arg, &g_control_caption);
|
||||
}
|
||||
else if (strcmp(arg, "--position") == 0)
|
||||
{
|
||||
if (!*argv)
|
||||
{
|
||||
fprintf(stderr, "error: missing argument for '%s'\n", arg);
|
||||
rc=1;
|
||||
}
|
||||
else
|
||||
{
|
||||
char extra='\0';
|
||||
int r=sscanf(*argv, "%ldx%ld%c", &g_x, &g_y, &extra);
|
||||
/* We should always get r==2 but due to a bug in Wine's
|
||||
* msvcrt.dll implementation (at least up to 20050127)
|
||||
* we may also get r==3 and extra=='\0'.
|
||||
*/
|
||||
if (r!=2 && (r!=3 || extra!='\0'))
|
||||
{
|
||||
fprintf(stderr, "error: invalid argument '%s' for '%s'\n",
|
||||
*argv, arg);
|
||||
rc=1;
|
||||
}
|
||||
argv++;
|
||||
}
|
||||
}
|
||||
else if (strcmp(arg, "--dragto") == 0)
|
||||
{
|
||||
if (!*argv)
|
||||
{
|
||||
fprintf(stderr, "error: missing argument for '%s'\n", arg);
|
||||
rc=1;
|
||||
}
|
||||
else
|
||||
{
|
||||
char extra='\0';
|
||||
int r=sscanf(*argv, "%ldx%ld%c", &g_dragto_x, &g_dragto_y, &extra);
|
||||
/* We should always get r==2 but due to a bug in Wine's
|
||||
* * msvcrt.dll implementation (at least up to 20050127)
|
||||
* * we may also get r==3 and extra=='\0'.
|
||||
* */
|
||||
if (r!=2 && (r!=3 || extra!='\0'))
|
||||
{
|
||||
fprintf(stderr, "error: invalid argument '%s' for '%s'\n",
|
||||
*argv, arg);
|
||||
rc=1;
|
||||
}
|
||||
argv++;
|
||||
}
|
||||
}
|
||||
else if (strcmp(arg, "--allow-disabled") == 0)
|
||||
{
|
||||
g_disabled = 1;
|
||||
}
|
||||
else if (strcmp(arg, "--delay") == 0)
|
||||
{
|
||||
rc|=arg_get_long(&argv, arg, &g_delay);
|
||||
}
|
||||
else if (strcmp(arg, "--timeout") == 0)
|
||||
{
|
||||
rc|=arg_get_long(&argv, arg, &g_timeout);
|
||||
}
|
||||
else if (strcmp(arg, "--repeat") == 0)
|
||||
{
|
||||
rc|=arg_get_long(&argv, arg, &g_repeat);
|
||||
}
|
||||
else if (strcmp(arg, "--untildeath") == 0)
|
||||
{
|
||||
g_untildeath=1;
|
||||
}
|
||||
else if (strcmp(arg, "--help") == 0)
|
||||
{
|
||||
rc=2;
|
||||
}
|
||||
}
|
||||
|
||||
if (g_action == ACTION_INVALID)
|
||||
{
|
||||
fprintf(stderr, "error: you must specify an action type\n");
|
||||
rc=1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Adjust the default delay and repeat parameters depending on
|
||||
* the operating mode so less needs to be specified on the command
|
||||
* line, and so we can assume them to be set right.
|
||||
*/
|
||||
if (g_action == ACTION_FIND)
|
||||
g_delay=0;
|
||||
if (!g_untildeath)
|
||||
g_repeat=0;
|
||||
else if (!g_repeat)
|
||||
g_repeat=DEFAULT_REPEAT;
|
||||
}
|
||||
|
||||
if (!g_window_class)
|
||||
{
|
||||
fprintf(stderr, "error: you must specify a --winclass parameter\n");
|
||||
rc=1;
|
||||
}
|
||||
if (!g_window_title)
|
||||
{
|
||||
fprintf(stderr, "error: you must specify a --wintitle parameter\n");
|
||||
rc=1;
|
||||
}
|
||||
if (g_control_class)
|
||||
{
|
||||
if (!g_control_id && !g_control_caption)
|
||||
{
|
||||
fprintf(stderr, "error: you must specify either the control id or its caption\n");
|
||||
rc=1;
|
||||
}
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------
|
||||
** Process environment variables
|
||||
**----------------------------------------------------------------------*/
|
||||
p = getenv("CXTEST_TIME_MULTIPLE");
|
||||
if (p)
|
||||
{
|
||||
float g_multiple = atof(p);
|
||||
g_delay = (long) (((float) g_delay) * g_multiple);
|
||||
g_timeout = (long) (((float) g_timeout) * g_multiple);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int main(int argc, const char** argv)
|
||||
{
|
||||
MSG msg;
|
||||
|
||||
init_debug();
|
||||
|
||||
status = parse_arguments(argc, argv);
|
||||
if (status)
|
||||
{
|
||||
if (status == 2)
|
||||
usage();
|
||||
else
|
||||
fprintf(stderr, "Issue %s --help for usage.\n", *argv);
|
||||
return RC_INVALID_ARGUMENTS;
|
||||
}
|
||||
cxlog("Entering message loop. action=%d\n", g_action);
|
||||
|
||||
if (g_timeout>0)
|
||||
SetTimer(NULL, 0, g_timeout, TimeoutProc);
|
||||
timer_id=SetTimer(NULL, 0, 100, FindWindowProc);
|
||||
|
||||
status=RC_RUNNING;
|
||||
while (status==RC_RUNNING && GetMessage(&msg, NULL, 0, 0)!=0)
|
||||
{
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
219
rosapps/tests/wpickclick/wpickclick.c
Normal file
219
rosapps/tests/wpickclick/wpickclick.c
Normal file
|
@ -0,0 +1,219 @@
|
|||
/*----------------------------------------------------------------------------
|
||||
** wpickclick.c
|
||||
** Utilty to pick clicks posted to Wine Windows
|
||||
**
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2004 Jozef Stefanka for CodeWeavers, Inc.
|
||||
** Copyright 2005 Francois Gouget for CodeWeavers, Inc.
|
||||
** Copyright 2005 Dmitry Timoshkov for CodeWeavers, Inc.
|
||||
**
|
||||
** This program is free software; you can redistribute it and/or modify
|
||||
** it under the terms of the GNU General Public License as published by
|
||||
** the Free Software Foundation; either version 2 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
**
|
||||
**--------------------------------------------------------------------------*/
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <io.h>
|
||||
#include <windows.h>
|
||||
|
||||
#include "hook.h"
|
||||
|
||||
|
||||
#define APP_NAME "wpickclick.exe"
|
||||
|
||||
|
||||
static BOOL (WINAPI *pInstallHooks)(HMODULE hdll);
|
||||
static void (WINAPI *pRemoveHooks)();
|
||||
static action_t* (WINAPI *pGetAction)();
|
||||
static void (WINAPI *pFreeAction)(action_t* action);
|
||||
|
||||
|
||||
/*
|
||||
* Provide some basic debugging support.
|
||||
*/
|
||||
#ifdef __GNUC__
|
||||
#define __PRINTF_ATTR(fmt,args) __attribute__((format (printf,fmt,args)))
|
||||
#else
|
||||
#define __PRINTF_ATTR(fmt,args)
|
||||
#endif
|
||||
static int debug_on=0;
|
||||
static int init_debug()
|
||||
{
|
||||
char* str=getenv("CXTEST_DEBUG");
|
||||
if (str && strstr(str, "+hook"))
|
||||
debug_on=1;
|
||||
return debug_on;
|
||||
}
|
||||
|
||||
static void cxlog(const char* format, ...) __PRINTF_ATTR(1,2);
|
||||
static void cxlog(const char* format, ...)
|
||||
{
|
||||
va_list valist;
|
||||
|
||||
if (debug_on)
|
||||
{
|
||||
va_start(valist, format);
|
||||
vfprintf(stderr, format, valist);
|
||||
va_end(valist);
|
||||
}
|
||||
}
|
||||
|
||||
static HINSTANCE load_hook_dll()
|
||||
{
|
||||
HINSTANCE hinstDll;
|
||||
char dllpath[MAX_PATH];
|
||||
char* p;
|
||||
|
||||
hinstDll=LoadLibrary("hook.dll");
|
||||
if (hinstDll != NULL)
|
||||
return hinstDll;
|
||||
|
||||
if (!GetModuleFileName(NULL,dllpath,sizeof(dllpath)))
|
||||
return NULL;
|
||||
|
||||
p=strrchr(dllpath,'\\');
|
||||
if (!p)
|
||||
return NULL;
|
||||
*p='\0';
|
||||
p=strrchr(dllpath,'\\');
|
||||
if (!p)
|
||||
return NULL;
|
||||
*p='\0';
|
||||
strcat(dllpath,"\\hookdll\\hook.dll");
|
||||
hinstDll=LoadLibrary(dllpath);
|
||||
return hinstDll;
|
||||
}
|
||||
|
||||
char* cleanup(char* str)
|
||||
{
|
||||
char* s;
|
||||
|
||||
while (*str==' ' || *str=='\t' || *str=='\r' || *str=='\n')
|
||||
str++;
|
||||
s=strchr(str,'\n');
|
||||
if (!s)
|
||||
s=str+strlen(str)-1;
|
||||
while (s>str && (*s==' ' || *s=='\t' || *s=='\r' || *s=='\n'))
|
||||
s--;
|
||||
*(s+1)='\0';
|
||||
return str;
|
||||
}
|
||||
|
||||
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
|
||||
LPSTR lpCmdLine, int nCmdShow)
|
||||
{
|
||||
HINSTANCE hDll;
|
||||
action_t* action;
|
||||
|
||||
init_debug();
|
||||
|
||||
/* Our scripts expect Unix-style line ends */
|
||||
_setmode(1,_O_BINARY);
|
||||
_setmode(2,_O_BINARY);
|
||||
|
||||
if (strstr(lpCmdLine,"--help"))
|
||||
{
|
||||
fprintf(stderr,"%s - Utility to print coordinates, component, window title, component class and window class name of a click\n", APP_NAME);
|
||||
fprintf(stderr,"----------------------------------------------\n");
|
||||
fprintf(stderr,"Usage: %s\n",APP_NAME);
|
||||
fprintf(stderr,"The options are as follows:\n");
|
||||
fprintf(stderr,"After starting you can\n");
|
||||
fprintf(stderr,"select where to click. If we properly track the click, it will be reported\n");
|
||||
fprintf(stderr,"in the following format:\n");
|
||||
fprintf(stderr," button-name x y component_name window_name component_class_name window_class_name\n");
|
||||
fprintf(stderr,"Note that x and y can be negative; this typically happens if you click within the\n");
|
||||
fprintf(stderr,"window manager decorations of a given window.\n");
|
||||
fprintf(stderr,"On success, %s returns 0, non zero on some failure\n",APP_NAME);
|
||||
exit(0);
|
||||
};
|
||||
|
||||
/* Load the hook library */
|
||||
hDll = load_hook_dll();
|
||||
if (!hDll)
|
||||
{
|
||||
fprintf(stderr, "Error: Unable to load 'hook.dll'\n");
|
||||
printf("failed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
pInstallHooks=(void*)GetProcAddress(hDll, "InstallHooks");
|
||||
pRemoveHooks=(void*)GetProcAddress(hDll, "RemoveHooks");
|
||||
pGetAction=(void*)GetProcAddress(hDll, "GetAction");
|
||||
pFreeAction=(void*)GetProcAddress(hDll, "FreeAction");
|
||||
if (!pInstallHooks || !pRemoveHooks || !pGetAction)
|
||||
{
|
||||
fprintf(stderr, "Error: Unable to get the hook.dll functions (%ld)\n",
|
||||
GetLastError());
|
||||
printf("failed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!pInstallHooks(hDll))
|
||||
{
|
||||
fprintf(stderr, "Error: Unable to install the hooks (%ld)\n",
|
||||
GetLastError());
|
||||
printf("failed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
fprintf(stderr, "Ready for capture...\n");
|
||||
action=pGetAction();
|
||||
if (!action)
|
||||
{
|
||||
fprintf(stderr, "Error: GetAction() failed\n");
|
||||
printf("failed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
switch (action->action)
|
||||
{
|
||||
case ACTION_FAILED:
|
||||
printf("failed\n");
|
||||
break;
|
||||
case ACTION_NONE:
|
||||
printf("none\n");
|
||||
break;
|
||||
case ACTION_FIND:
|
||||
printf("find\n");
|
||||
break;
|
||||
case ACTION_BUTTON1:
|
||||
case ACTION_BUTTON2:
|
||||
case ACTION_BUTTON3:
|
||||
printf("button%d %ld %ld\n", action->action-ACTION_BUTTON1+1,
|
||||
action->x, action->y);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Error: Unknown action %d\n",action->action);
|
||||
printf("%d\n", action->action);
|
||||
break;
|
||||
}
|
||||
printf("%s\n", action->window_class);
|
||||
printf("%s\n", action->window_title);
|
||||
printf("%ld\n", action->control_id);
|
||||
printf("%s\n", action->control_class);
|
||||
printf("%s\n", cleanup(action->control_caption));
|
||||
|
||||
cxlog("\n%s: action=%d x=%ld y=%ld\n", __FILE__, action->action,
|
||||
action->x, action->y);
|
||||
cxlog("window_class='%s'\n", action->window_class);
|
||||
cxlog("window_title='%s'\n", action->window_title);
|
||||
cxlog("control_id=%ld\n", action->control_id);
|
||||
cxlog("control_class='%s'\n", action->control_class);
|
||||
cxlog("control_caption='%s'\n", action->control_caption);
|
||||
|
||||
pFreeAction(action);
|
||||
pRemoveHooks();
|
||||
return 0;
|
||||
}
|
Loading…
Reference in a new issue