1
/***************************************************************************
2
 * Copyright (c) 2009 Enrico Ros                                           *
3
 *         2009 Enrico Ros <enrico.ros@email.it>                           *
4
 *         2009 Alberto Scarpa <skaal.sl@gmail.com>                        *
5
 *                                                                         *
6
 * Permission is hereby granted, free of charge, to any person             *
7
 * obtaining a copy of this software and associated documentation          *
8
 * files (the "Software"), to deal in the Software without                 *
9
 * restriction, including without limitation the rights to use,            *
10
 * copy, modify, merge, publish, distribute, sublicense, and/or sell       *
11
 * copies of the Software, and to permit persons to whom the               *
12
 * Software is furnished to do so, subject to the following                *
13
 * conditions:                                                             *
14
 *                                                                         *
15
 * The above copyright notice and this permission notice shall be          *
16
 * included in all copies or substantial portions of the Software.         *
17
 *                                                                         *
18
 ***************************************************************************/
19
20
#include "InputUtils.h"
21
#include <QPoint>
22
#include <QCursor>
23
24
#if defined(Q_WS_X11)
25
#include <QX11Info>
26
#include <X11/extensions/XTest.h>
27
//include <X11/keysymdef.h> defines:
28
#define KS_X11_BACKSPACE    0xff08
29
#define KS_X11_ESCAPE       0xff1b
30
#define KS_X11_RETURN       0xff0d
31
#define KS_X11_SHIFT_L      0xffe1
32
#define KS_X11_SHIFT_R      0xffe2
33
#define KS_X11_CTRL_L       0xffe3
34
#define KS_X11_CTRL_R       0xffe4
35
#define KS_X11_LEFT         0xff51
36
#define KS_X11_UP           0xff52
37
#define KS_X11_RIGHT        0xff53
38
#define KS_X11_DOWN         0xff54
39
#elif defined(Q_WS_WIN)
40
#include <windows.h>
41
#elif defined(Q_WS_MAC)
42
#import <ApplicationServices/ApplicationServices.h>
43
#else
44
#warning InputUtils not implemented for this Windowing System
45
#endif
46
47
void InputUtils::mouseLeftClick()
48
{
49
    mouseLeftPress();
50
    mouseLeftRelease();
51
}
52
53
void InputUtils::mouseLeftPress()
54
{
55
#if defined(Q_WS_X11)
56
    XTestFakeButtonEvent( QX11Info::display(), 1, true, CurrentTime );
57
    XFlush( QX11Info::display() );
58
#elif defined(Q_WS_WIN)
59
    INPUT Input={0};
60
    Input.type = INPUT_MOUSE;
61
    Input.mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
62
    ::SendInput( 1, &Input, sizeof(INPUT) );
63
#elif defined(Q_WS_MAC)
64
    QPoint currPos = QCursor::pos();
65
    // The data structure CGPoint represents a point in a two-dimensional
66
    // coordinate system.  Here, X and Y distance from upper left, in pixels.
67
    //
68
    CGPoint pt;
69
    pt.x = currPos.x();
70
    pt.y = currPos.y();
71
    // CGPostMouseEvent( CGPoint        mouseCursorPosition,
72
    //                   boolean_t      updateMouseCursorPosition,
73
    //                   CGButtonCount  buttonCount,
74
    //                   boolean_t      mouseButtonDown, ... )
75
    // So, we feed coordinates to CGPostMouseEvent, put the mouse there,
76
    // then click and release.
77
    CGPostMouseEvent( pt, 1, 1, 1 );
78
#endif
79
}
80
81
void InputUtils::mouseLeftRelease()
82
{
83
#if defined(Q_WS_X11)
84
    XTestFakeButtonEvent( QX11Info::display(), 1, false, CurrentTime );
85
    XFlush( QX11Info::display() );
86
#elif defined(Q_WS_WIN)
87
    INPUT Input={0};
88
    Input.type = INPUT_MOUSE;
89
    Input.mi.dwFlags = MOUSEEVENTF_LEFTUP;
90
    ::SendInput( 1, &Input, sizeof(INPUT) );
91
#elif defined(Q_WS_MAC)
92
    CGPoint pt;
93
    QPoint currPos = QCursor::pos();
94
    pt.x = currPos.x();
95
    pt.y = currPos.y();
96
    CGPostMouseEvent( pt, 1, 1, 0 );
97
#endif
98
}
99
100
void InputUtils::mouseMove( int x, int y )
101
{
102
    QCursor::setPos( x, y );
103
}
104
105
void InputUtils::keyWrite( const QString & string )
106
{
107
    int len = string.length();
108
    for ( int i = 0; i < len; i++ )
109
        keyClick( string.at( i ) );
110
}
111
112
#if defined(Q_WS_X11)
113
static void xSendScanCode( Display * display, unsigned int keyCode )
114
{
115
    XTestFakeKeyEvent( display, keyCode, true, CurrentTime );
116
    XTestFakeKeyEvent( display, keyCode, false, CurrentTime );
117
    XFlush( display );
118
}
119
#endif
120
121
void InputUtils::keyClick( const QChar & singleChar )
122
{
123
#if defined(Q_WS_X11)
124
    char latin1 = singleChar.toLatin1();
125
    Display * display = QX11Info::display();
126
    unsigned int keyCode = XKeysymToKeycode( display, latin1 );
127
    if ( !keyCode ) {
128
        if ( latin1 == '\n' )
129
            keyCode = XKeysymToKeycode( display, KS_X11_RETURN );
130
        if ( !keyCode ) {
131
            qWarning( "InputUtils::keyClickKeysym(X11): cannot get keycode of char '%d', please provide the conversion.", latin1 );
132
            return;
133
        }
134
    }
135
    xSendScanCode( display, keyCode );
136
#elif defined(Q_WS_WIN)
137
    // keypress
138
    SHORT virtKey = VkKeyScan(singleChar.unicode());
139
    INPUT input[2];
140
    input[0].type = INPUT_KEYBOARD;
141
    input[0].ki.wVk = LOBYTE(virtKey);
142
    input[0].ki.wScan = 0;
143
    input[0].ki.dwFlags = 0;
144
    input[0].ki.time = 0;
145
    input[0].ki.dwExtraInfo = 0;
146
    // keyrelease
147
    input[1] = input[0];
148
    input[1].ki.dwFlags |= KEYEVENTF_KEYUP;
149
    // send both
150
    ::SendInput( 2, input, sizeof(INPUT) );
151
#else
152
    qWarning( "InputUtils::keyClick: notImplemented()");
153
#endif
154
}
155
156
void InputUtils::keyClickSpecial( int qtKeyCode )
157
{
158
#if defined(Q_WS_X11)
159
    Display * display = QX11Info::display();
160
#elif defined(Q_WS_WIN)
161
    // pre-init Virtual Input structure
162
    INPUT vinput[2];
163
    vinput[0].type = INPUT_KEYBOARD;
164
    vinput[0].ki.wVk = 0;
165
    vinput[0].ki.wScan = 0;
166
    vinput[0].ki.dwFlags = 0;
167
    vinput[0].ki.time = 0;
168
    vinput[0].ki.dwExtraInfo = 0;
169
#endif
170
171
    switch ( qtKeyCode ) {
172
        case Qt::Key_Control:
173
#if defined(Q_WS_X11)
174
            xSendScanCode( display, XKeysymToKeycode( display, KS_X11_CTRL_L ) );
175
#elif defined(Q_WS_WIN)
176
            vinput[0].ki.wVk = VK_CONTROL;
177
#else
178
            qWarning("InputUtils::keyClickSpecial: CTRL not implemented for this platform");
179
#endif
180
            break;
181
182
        default:
183
            qWarning( "InputUtils::keyClickSpecial: cannot get keycode of special qtkey '%d', please provide the conversion.", qtKeyCode );
184
            break;
185
    }
186
187
#if defined(Q_WS_WIN)
188
    // send keypress and keyrelease
189
    if ( vinput[0].ki.wVk ) {
190
        vinput[1] = vinput[0];
191
        vinput[1].ki.dwFlags |= KEYEVENTF_KEYUP;
192
        ::SendInput( 2, vinput, sizeof(INPUT) );
193
    }
194
#endif
195
}