1 /*
2 * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 #include "awt.h"
27 #include "awt_Toolkit.h"
28 #include "awt_Component.h"
29 #include "awt_Robot.h"
30 #include "sun_awt_windows_WRobotPeer.h"
31 #include "java_awt_event_InputEvent.h"
32 #include <winuser.h>
33
AwtRobot(jobject peer)34 AwtRobot::AwtRobot( jobject peer )
35 {
36 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
37 m_peerObject = env->NewWeakGlobalRef(peer);
38 JNU_CHECK_EXCEPTION(env);
39 JNI_SET_PDATA(peer, this);
40 }
41
~AwtRobot()42 AwtRobot::~AwtRobot()
43 {
44 }
45
46 #ifndef SPI_GETMOUSESPEED
47 #define SPI_GETMOUSESPEED 112
48 #endif
49
50 #ifndef SPI_SETMOUSESPEED
51 #define SPI_SETMOUSESPEED 113
52 #endif
53
MouseMove(jint x,jint y)54 void AwtRobot::MouseMove( jint x, jint y)
55 {
56 // Fix for Bug 4288230. See Q193003 from MSDN.
57 int oldAccel[3], newAccel[3];
58 INT_PTR oldSpeed, newSpeed;
59 BOOL bResult;
60
61 // The following values set mouse ballistics to 1 mickey/pixel.
62 newAccel[0] = 0;
63 newAccel[1] = 0;
64 newAccel[2] = 0;
65 newSpeed = 10;
66
67 // Save the Current Mouse Acceleration Constants
68 bResult = SystemParametersInfo(SPI_GETMOUSE,0,oldAccel,0);
69 bResult = SystemParametersInfo(SPI_GETMOUSESPEED, 0, &oldSpeed,0);
70 // Set the new Mouse Acceleration Constants (Disabled).
71 bResult = SystemParametersInfo(SPI_SETMOUSE,0,newAccel,SPIF_SENDCHANGE);
72 bResult = SystemParametersInfo(SPI_SETMOUSESPEED, 0,
73 // 4504963: Though the third argument to SystemParameterInfo is
74 // declared as a PVOID, as of Windows 2000 it is apparently
75 // interpreted as an int. (The MSDN docs for SPI_SETMOUSESPEED
76 // say that it's an integer between 1 and 20, the default being
77 // 10). Instead of passing the @ of the desired value, the
78 // value itself is now passed, cast as a PVOID so as to
79 // compile. -bchristi 10/02/2001
80 (PVOID)newSpeed,
81 SPIF_SENDCHANGE);
82
83 POINT curPos;
84 ::GetCursorPos(&curPos);
85 x -= curPos.x;
86 y -= curPos.y;
87
88 mouse_event(MOUSEEVENTF_MOVE,x,y,0,0);
89 // Move the cursor to the desired coordinates.
90
91 // Restore the old Mouse Acceleration Constants.
92 bResult = SystemParametersInfo(SPI_SETMOUSE,0, oldAccel, SPIF_SENDCHANGE);
93 bResult = SystemParametersInfo(SPI_SETMOUSESPEED, 0, (PVOID)oldSpeed,
94 SPIF_SENDCHANGE);
95 }
96
MousePress(jint buttonMask)97 void AwtRobot::MousePress( jint buttonMask )
98 {
99 DWORD dwFlags = 0L;
100 // According to MSDN: Software Driving Software
101 // application should consider SM_SWAPBUTTON to correctly emulate user with
102 // left handed mouse setup
103 BOOL bSwap = ::GetSystemMetrics(SM_SWAPBUTTON);
104
105 if ( buttonMask & java_awt_event_InputEvent_BUTTON1_MASK ||
106 buttonMask & java_awt_event_InputEvent_BUTTON1_DOWN_MASK)
107 {
108 dwFlags |= !bSwap ? MOUSEEVENTF_LEFTDOWN : MOUSEEVENTF_RIGHTDOWN;
109 }
110
111 if ( buttonMask & java_awt_event_InputEvent_BUTTON3_MASK ||
112 buttonMask & java_awt_event_InputEvent_BUTTON3_DOWN_MASK)
113 {
114 dwFlags |= !bSwap ? MOUSEEVENTF_RIGHTDOWN : MOUSEEVENTF_LEFTDOWN;
115 }
116
117 if ( buttonMask & java_awt_event_InputEvent_BUTTON2_MASK ||
118 buttonMask & java_awt_event_InputEvent_BUTTON2_DOWN_MASK)
119 {
120 dwFlags |= MOUSEEVENTF_MIDDLEDOWN;
121 }
122
123 INPUT mouseInput = {0};
124 mouseInput.type = INPUT_MOUSE;
125 mouseInput.mi.time = 0;
126 mouseInput.mi.dwFlags = dwFlags;
127 if ( buttonMask & AwtComponent::masks[3] ) {
128 mouseInput.mi.dwFlags = mouseInput.mi.dwFlags | MOUSEEVENTF_XDOWN;
129 mouseInput.mi.mouseData = XBUTTON1;
130 }
131
132 if ( buttonMask & AwtComponent::masks[4] ) {
133 mouseInput.mi.dwFlags = mouseInput.mi.dwFlags | MOUSEEVENTF_XDOWN;
134 mouseInput.mi.mouseData = XBUTTON2;
135 }
136 ::SendInput(1, &mouseInput, sizeof(mouseInput));
137 }
138
MouseRelease(jint buttonMask)139 void AwtRobot::MouseRelease( jint buttonMask )
140 {
141 DWORD dwFlags = 0L;
142 // According to MSDN: Software Driving Software
143 // application should consider SM_SWAPBUTTON to correctly emulate user with
144 // left handed mouse setup
145 BOOL bSwap = ::GetSystemMetrics(SM_SWAPBUTTON);
146
147 if ( buttonMask & java_awt_event_InputEvent_BUTTON1_MASK ||
148 buttonMask & java_awt_event_InputEvent_BUTTON1_DOWN_MASK)
149 {
150 dwFlags |= !bSwap ? MOUSEEVENTF_LEFTUP : MOUSEEVENTF_RIGHTUP;
151 }
152
153 if ( buttonMask & java_awt_event_InputEvent_BUTTON3_MASK ||
154 buttonMask & java_awt_event_InputEvent_BUTTON3_DOWN_MASK)
155 {
156 dwFlags |= !bSwap ? MOUSEEVENTF_RIGHTUP : MOUSEEVENTF_LEFTUP;
157 }
158
159 if ( buttonMask & java_awt_event_InputEvent_BUTTON2_MASK ||
160 buttonMask & java_awt_event_InputEvent_BUTTON2_DOWN_MASK)
161 {
162 dwFlags |= MOUSEEVENTF_MIDDLEUP;
163 }
164
165 INPUT mouseInput = {0};
166 mouseInput.type = INPUT_MOUSE;
167 mouseInput.mi.time = 0;
168 mouseInput.mi.dwFlags = dwFlags;
169
170 if ( buttonMask & AwtComponent::masks[3] ) {
171 mouseInput.mi.dwFlags = mouseInput.mi.dwFlags | MOUSEEVENTF_XUP;
172 mouseInput.mi.mouseData = XBUTTON1;
173 }
174
175 if ( buttonMask & AwtComponent::masks[4] ) {
176 mouseInput.mi.dwFlags = mouseInput.mi.dwFlags | MOUSEEVENTF_XUP;
177 mouseInput.mi.mouseData = XBUTTON2;
178 }
179 ::SendInput(1, &mouseInput, sizeof(mouseInput));
180 }
181
MouseWheel(jint wheelAmt)182 void AwtRobot::MouseWheel (jint wheelAmt) {
183 mouse_event(MOUSEEVENTF_WHEEL, 0, 0, wheelAmt * -1 * WHEEL_DELTA, 0);
184 }
185
WinToJavaPixel(USHORT r,USHORT g,USHORT b)186 inline jint AwtRobot::WinToJavaPixel(USHORT r, USHORT g, USHORT b)
187 {
188 jint value =
189 0xFF << 24 | // alpha channel is always turned all the way up
190 r << 16 |
191 g << 8 |
192 b << 0;
193 return value;
194 }
195
GetRGBPixels(jint x,jint y,jint width,jint height,jintArray pixelArray)196 void AwtRobot::GetRGBPixels(jint x, jint y, jint width, jint height, jintArray pixelArray)
197 {
198 DASSERT(width > 0 && height > 0);
199
200 HDC hdcScreen = ::CreateDC(TEXT("DISPLAY"), NULL, NULL, NULL);
201 HDC hdcMem = ::CreateCompatibleDC(hdcScreen);
202 HBITMAP hbitmap;
203 HBITMAP hOldBitmap;
204 HPALETTE hOldPalette = NULL;
205 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
206
207 // create an offscreen bitmap
208 hbitmap = ::CreateCompatibleBitmap(hdcScreen, width, height);
209 if (hbitmap == NULL) {
210 throw std::bad_alloc();
211 }
212 hOldBitmap = (HBITMAP)::SelectObject(hdcMem, hbitmap);
213
214 // REMIND: not multimon-friendly...
215 int primaryIndex = AwtWin32GraphicsDevice::GetDefaultDeviceIndex();
216 hOldPalette =
217 AwtWin32GraphicsDevice::SelectPalette(hdcMem, primaryIndex);
218 AwtWin32GraphicsDevice::RealizePalette(hdcMem, primaryIndex);
219
220 // copy screen image to offscreen bitmap
221 // CAPTUREBLT flag is required to capture WS_EX_LAYERED windows' contents
222 // correctly on Win2K/XP
223 VERIFY(::BitBlt(hdcMem, 0, 0, width, height, hdcScreen, x, y,
224 SRCCOPY|CAPTUREBLT) != 0);
225
226 static const int BITS_PER_PIXEL = 32;
227 static const int BYTES_PER_PIXEL = BITS_PER_PIXEL/8;
228
229 if (!IS_SAFE_SIZE_MUL(width, height)) throw std::bad_alloc();
230 int numPixels = width*height;
231 if (!IS_SAFE_SIZE_MUL(BYTES_PER_PIXEL, numPixels)) throw std::bad_alloc();
232 int pixelDataSize = BYTES_PER_PIXEL*numPixels;
233 DASSERT(pixelDataSize > 0 && pixelDataSize % 4 == 0);
234 // allocate memory for BITMAPINFO + pixel data
235 // 4620932: When using BI_BITFIELDS, GetDIBits expects an array of 3
236 // RGBQUADS to follow the BITMAPINFOHEADER, but we were only allocating the
237 // 1 that is included in BITMAPINFO. Thus, GetDIBits was writing off the
238 // end of our block of memory. Now we allocate sufficient memory.
239 // See MSDN docs for BITMAPINFOHEADER -bchristi
240
241 if (!IS_SAFE_SIZE_ADD(sizeof(BITMAPINFOHEADER) + 3 * sizeof(RGBQUAD), pixelDataSize)) {
242 throw std::bad_alloc();
243 }
244 BITMAPINFO * pinfo = (BITMAPINFO *)(new BYTE[sizeof(BITMAPINFOHEADER) + 3 * sizeof(RGBQUAD) + pixelDataSize]);
245
246 // pixel data starts after 3 RGBQUADS for color masks
247 RGBQUAD *pixelData = &pinfo->bmiColors[3];
248
249 // prepare BITMAPINFO for a 32-bit RGB bitmap
250 ::memset(pinfo, 0, sizeof(*pinfo));
251 pinfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
252 pinfo->bmiHeader.biWidth = width;
253 pinfo->bmiHeader.biHeight = -height; // negative height means a top-down DIB
254 pinfo->bmiHeader.biPlanes = 1;
255 pinfo->bmiHeader.biBitCount = BITS_PER_PIXEL;
256 pinfo->bmiHeader.biCompression = BI_BITFIELDS;
257
258 // Setup up color masks
259 static const RGBQUAD redMask = {0, 0, 0xFF, 0};
260 static const RGBQUAD greenMask = {0, 0xFF, 0, 0};
261 static const RGBQUAD blueMask = {0xFF, 0, 0, 0};
262
263 pinfo->bmiColors[0] = redMask;
264 pinfo->bmiColors[1] = greenMask;
265 pinfo->bmiColors[2] = blueMask;
266
267 // Get the bitmap data in device-independent, 32-bit packed pixel format
268 ::GetDIBits(hdcMem, hbitmap, 0, height, pixelData, pinfo, DIB_RGB_COLORS);
269
270 // convert Win32 pixel format (BGRX) to Java format (ARGB)
271 DASSERT(sizeof(jint) == sizeof(RGBQUAD));
272 for(int nPixel = 0; nPixel < numPixels; nPixel++) {
273 RGBQUAD * prgbq = &pixelData[nPixel];
274 jint jpixel = WinToJavaPixel(prgbq->rgbRed, prgbq->rgbGreen, prgbq->rgbBlue);
275 // stuff the 32-bit pixel back into the 32-bit RGBQUAD
276 *prgbq = *( (RGBQUAD *)(&jpixel) );
277 }
278
279 // copy pixels into Java array
280 env->SetIntArrayRegion(pixelArray, 0, numPixels, (jint *)pixelData);
281 delete[] pinfo;
282
283 // free all the GDI objects we made
284 ::SelectObject(hdcMem, hOldBitmap);
285 if (hOldPalette != NULL) {
286 ::SelectPalette(hdcMem, hOldPalette, FALSE);
287 }
288 ::DeleteObject(hbitmap);
289 ::DeleteDC(hdcMem);
290 ::DeleteDC(hdcScreen);
291 }
292
KeyPress(jint jkey)293 void AwtRobot::KeyPress( jint jkey )
294 {
295 DoKeyEvent(jkey, 0); // no flags means key down
296 }
297
KeyRelease(jint jkey)298 void AwtRobot::KeyRelease( jint jkey )
299 {
300 DoKeyEvent(jkey, KEYEVENTF_KEYUP);
301 }
302
DoKeyEvent(jint jkey,DWORD dwFlags)303 void AwtRobot::DoKeyEvent( jint jkey, DWORD dwFlags )
304 {
305 UINT vkey;
306 UINT modifiers;
307 UINT scancode;
308 JNIEnv * env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
309
310 // convert Java key into Windows key (and modifiers too)
311 AwtComponent::JavaKeyToWindowsKey(jkey, &vkey, &modifiers);
312 if (vkey == 0) {
313 // no equivalent Windows key found for given Java keycode
314 JNU_ThrowIllegalArgumentException(env, "Invalid key code");
315 } else {
316 // get the scancode from the virtual key
317 scancode = ::MapVirtualKey(vkey, 0);
318 keybd_event(vkey, scancode, dwFlags, 0);
319 }
320 }
321
322 //
323 // utility function to get the C++ object from the Java one
324 //
325 // (static)
GetRobot(jobject self)326 AwtRobot * AwtRobot::GetRobot( jobject self )
327 {
328 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
329 AwtRobot * robot = (AwtRobot *)JNI_GET_PDATA(self);
330 DASSERT( !::IsBadWritePtr( robot, sizeof(AwtRobot)));
331 return robot;
332 }
333
334 //////////////////////////////////////////////////////////////////////////////////////////////
335 // Native method declarations
336 //
337
Java_sun_awt_windows_WRobotPeer_create(JNIEnv * env,jobject self)338 JNIEXPORT void JNICALL Java_sun_awt_windows_WRobotPeer_create(
339 JNIEnv * env, jobject self)
340 {
341 TRY;
342
343 new AwtRobot(self);
344
345 CATCH_BAD_ALLOC;
346 }
347
Java_sun_awt_windows_WRobotPeer__1dispose(JNIEnv * env,jobject self)348 JNIEXPORT void JNICALL Java_sun_awt_windows_WRobotPeer__1dispose(
349 JNIEnv *env, jobject self)
350 {
351 TRY_NO_VERIFY;
352
353 AwtObject::_Dispose(self);
354
355 CATCH_BAD_ALLOC;
356 }
357
Java_sun_awt_windows_WRobotPeer_mouseMoveImpl(JNIEnv * env,jobject self,jint x,jint y)358 JNIEXPORT void JNICALL Java_sun_awt_windows_WRobotPeer_mouseMoveImpl(
359 JNIEnv * env, jobject self, jint x, jint y)
360 {
361 TRY;
362
363 AwtRobot::GetRobot(self)->MouseMove(x, y);
364
365 CATCH_BAD_ALLOC;
366 }
367
Java_sun_awt_windows_WRobotPeer_mousePress(JNIEnv * env,jobject self,jint buttons)368 JNIEXPORT void JNICALL Java_sun_awt_windows_WRobotPeer_mousePress(
369 JNIEnv * env, jobject self, jint buttons)
370 {
371 TRY;
372
373 AwtRobot::GetRobot(self)->MousePress(buttons);
374
375 CATCH_BAD_ALLOC;
376 }
377
Java_sun_awt_windows_WRobotPeer_mouseRelease(JNIEnv * env,jobject self,jint buttons)378 JNIEXPORT void JNICALL Java_sun_awt_windows_WRobotPeer_mouseRelease(
379 JNIEnv * env, jobject self, jint buttons)
380 {
381 TRY;
382
383 AwtRobot::GetRobot(self)->MouseRelease(buttons);
384
385 CATCH_BAD_ALLOC;
386 }
387
Java_sun_awt_windows_WRobotPeer_mouseWheel(JNIEnv * env,jobject self,jint wheelAmt)388 JNIEXPORT void JNICALL Java_sun_awt_windows_WRobotPeer_mouseWheel(
389 JNIEnv * env, jobject self, jint wheelAmt)
390 {
391 TRY;
392
393 AwtRobot::GetRobot(self)->MouseWheel(wheelAmt);
394
395 CATCH_BAD_ALLOC;
396 }
397
Java_sun_awt_windows_WRobotPeer_getRGBPixels(JNIEnv * env,jobject self,jint x,jint y,jint width,jint height,jintArray pixelArray)398 JNIEXPORT void JNICALL Java_sun_awt_windows_WRobotPeer_getRGBPixels(
399 JNIEnv *env, jobject self, jint x, jint y, jint width, jint height, jintArray pixelArray)
400 {
401 TRY;
402
403 AwtRobot::GetRobot(self)->GetRGBPixels(x, y, width, height, pixelArray);
404
405 CATCH_BAD_ALLOC;
406 }
407
Java_sun_awt_windows_WRobotPeer_keyPress(JNIEnv *,jobject self,jint javakey)408 JNIEXPORT void JNICALL Java_sun_awt_windows_WRobotPeer_keyPress(
409 JNIEnv *, jobject self, jint javakey )
410 {
411 TRY;
412
413 AwtRobot::GetRobot(self)->KeyPress(javakey);
414
415 CATCH_BAD_ALLOC;
416 }
417
Java_sun_awt_windows_WRobotPeer_keyRelease(JNIEnv *,jobject self,jint javakey)418 JNIEXPORT void JNICALL Java_sun_awt_windows_WRobotPeer_keyRelease(
419 JNIEnv *, jobject self, jint javakey )
420 {
421 TRY;
422
423 AwtRobot::GetRobot(self)->KeyRelease(javakey);
424
425 CATCH_BAD_ALLOC;
426 }
427