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 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 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 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 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 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 182 void AwtRobot::MouseWheel (jint wheelAmt) { 183 mouse_event(MOUSEEVENTF_WHEEL, 0, 0, wheelAmt * -1 * WHEEL_DELTA, 0); 184 } 185 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 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 293 void AwtRobot::KeyPress( jint jkey ) 294 { 295 DoKeyEvent(jkey, 0); // no flags means key down 296 } 297 298 void AwtRobot::KeyRelease( jint jkey ) 299 { 300 DoKeyEvent(jkey, KEYEVENTF_KEYUP); 301 } 302 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) 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 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 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 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 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 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 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 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 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 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 }