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