1 /* 2 * Copyright (c) 1998, 2017, 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 int primaryIndex = AwtWin32GraphicsDevice::GetDefaultDeviceIndex(); 84 Devices::InstanceAccess devices; 85 AwtWin32GraphicsDevice *device = devices->GetDevice(primaryIndex); 86 87 x = (device == NULL) ? x : device->ScaleUpX(x); 88 y = (device == NULL) ? y : device->ScaleUpY(y); 89 90 POINT curPos; 91 ::GetCursorPos(&curPos); 92 x -= curPos.x; 93 y -= curPos.y; 94 95 mouse_event(MOUSEEVENTF_MOVE,x,y,0,0); 96 // Move the cursor to the desired coordinates. 97 98 // Restore the old Mouse Acceleration Constants. 99 bResult = SystemParametersInfo(SPI_SETMOUSE,0, oldAccel, SPIF_SENDCHANGE); 100 bResult = SystemParametersInfo(SPI_SETMOUSESPEED, 0, (PVOID)oldSpeed, 101 SPIF_SENDCHANGE); 102 } 103 104 void AwtRobot::MousePress( jint buttonMask ) 105 { 106 DWORD dwFlags = 0L; 107 // According to MSDN: Software Driving Software 108 // application should consider SM_SWAPBUTTON to correctly emulate user with 109 // left handed mouse setup 110 BOOL bSwap = ::GetSystemMetrics(SM_SWAPBUTTON); 111 112 if ( buttonMask & java_awt_event_InputEvent_BUTTON1_MASK || 113 buttonMask & java_awt_event_InputEvent_BUTTON1_DOWN_MASK) 114 { 115 dwFlags |= !bSwap ? MOUSEEVENTF_LEFTDOWN : MOUSEEVENTF_RIGHTDOWN; 116 } 117 118 if ( buttonMask & java_awt_event_InputEvent_BUTTON3_MASK || 119 buttonMask & java_awt_event_InputEvent_BUTTON3_DOWN_MASK) 120 { 121 dwFlags |= !bSwap ? MOUSEEVENTF_RIGHTDOWN : MOUSEEVENTF_LEFTDOWN; 122 } 123 124 if ( buttonMask & java_awt_event_InputEvent_BUTTON2_MASK || 125 buttonMask & java_awt_event_InputEvent_BUTTON2_DOWN_MASK) 126 { 127 dwFlags |= MOUSEEVENTF_MIDDLEDOWN; 128 } 129 130 INPUT mouseInput = {0}; 131 mouseInput.type = INPUT_MOUSE; 132 mouseInput.mi.time = 0; 133 mouseInput.mi.dwFlags = dwFlags; 134 if ( buttonMask & AwtComponent::masks[3] ) { 135 mouseInput.mi.dwFlags = mouseInput.mi.dwFlags | MOUSEEVENTF_XDOWN; 136 mouseInput.mi.mouseData = XBUTTON1; 137 } 138 139 if ( buttonMask & AwtComponent::masks[4] ) { 140 mouseInput.mi.dwFlags = mouseInput.mi.dwFlags | MOUSEEVENTF_XDOWN; 141 mouseInput.mi.mouseData = XBUTTON2; 142 } 143 ::SendInput(1, &mouseInput, sizeof(mouseInput)); 144 } 145 146 void AwtRobot::MouseRelease( jint buttonMask ) 147 { 148 DWORD dwFlags = 0L; 149 // According to MSDN: Software Driving Software 150 // application should consider SM_SWAPBUTTON to correctly emulate user with 151 // left handed mouse setup 152 BOOL bSwap = ::GetSystemMetrics(SM_SWAPBUTTON); 153 154 if ( buttonMask & java_awt_event_InputEvent_BUTTON1_MASK || 155 buttonMask & java_awt_event_InputEvent_BUTTON1_DOWN_MASK) 156 { 157 dwFlags |= !bSwap ? MOUSEEVENTF_LEFTUP : MOUSEEVENTF_RIGHTUP; 158 } 159 160 if ( buttonMask & java_awt_event_InputEvent_BUTTON3_MASK || 161 buttonMask & java_awt_event_InputEvent_BUTTON3_DOWN_MASK) 162 { 163 dwFlags |= !bSwap ? MOUSEEVENTF_RIGHTUP : MOUSEEVENTF_LEFTUP; 164 } 165 166 if ( buttonMask & java_awt_event_InputEvent_BUTTON2_MASK || 167 buttonMask & java_awt_event_InputEvent_BUTTON2_DOWN_MASK) 168 { 169 dwFlags |= MOUSEEVENTF_MIDDLEUP; 170 } 171 172 INPUT mouseInput = {0}; 173 mouseInput.type = INPUT_MOUSE; 174 mouseInput.mi.time = 0; 175 mouseInput.mi.dwFlags = dwFlags; 176 177 if ( buttonMask & AwtComponent::masks[3] ) { 178 mouseInput.mi.dwFlags = mouseInput.mi.dwFlags | MOUSEEVENTF_XUP; 179 mouseInput.mi.mouseData = XBUTTON1; 180 } 181 182 if ( buttonMask & AwtComponent::masks[4] ) { 183 mouseInput.mi.dwFlags = mouseInput.mi.dwFlags | MOUSEEVENTF_XUP; 184 mouseInput.mi.mouseData = XBUTTON2; 185 } 186 ::SendInput(1, &mouseInput, sizeof(mouseInput)); 187 } 188 189 void AwtRobot::MouseWheel (jint wheelAmt) { 190 mouse_event(MOUSEEVENTF_WHEEL, 0, 0, wheelAmt * -1 * WHEEL_DELTA, 0); 191 } 192 193 inline jint AwtRobot::WinToJavaPixel(USHORT r, USHORT g, USHORT b) 194 { 195 jint value = 196 0xFF << 24 | // alpha channel is always turned all the way up 197 r << 16 | 198 g << 8 | 199 b << 0; 200 return value; 201 } 202 203 void AwtRobot::GetRGBPixels(jint x, jint y, jint width, jint height, jintArray pixelArray) 204 { 205 DASSERT(width > 0 && height > 0); 206 207 HDC hdcScreen = ::CreateDC(TEXT("DISPLAY"), NULL, NULL, NULL); 208 HDC hdcMem = ::CreateCompatibleDC(hdcScreen); 209 HBITMAP hbitmap; 210 HBITMAP hOldBitmap; 211 HPALETTE hOldPalette = NULL; 212 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 213 214 // create an offscreen bitmap 215 hbitmap = ::CreateCompatibleBitmap(hdcScreen, width, height); 216 if (hbitmap == NULL) { 217 throw std::bad_alloc(); 218 } 219 hOldBitmap = (HBITMAP)::SelectObject(hdcMem, hbitmap); 220 221 // REMIND: not multimon-friendly... 222 int primaryIndex = AwtWin32GraphicsDevice::GetDefaultDeviceIndex(); 223 hOldPalette = 224 AwtWin32GraphicsDevice::SelectPalette(hdcMem, primaryIndex); 225 AwtWin32GraphicsDevice::RealizePalette(hdcMem, primaryIndex); 226 227 // copy screen image to offscreen bitmap 228 // CAPTUREBLT flag is required to capture WS_EX_LAYERED windows' contents 229 // correctly on Win2K/XP 230 VERIFY(::BitBlt(hdcMem, 0, 0, width, height, hdcScreen, x, y, 231 SRCCOPY | CAPTUREBLT) != 0); 232 233 static const int BITS_PER_PIXEL = 32; 234 static const int BYTES_PER_PIXEL = BITS_PER_PIXEL/8; 235 236 if (!IS_SAFE_SIZE_MUL(width, height)) throw std::bad_alloc(); 237 int numPixels = width*height; 238 if (!IS_SAFE_SIZE_MUL(BYTES_PER_PIXEL, numPixels)) throw std::bad_alloc(); 239 int pixelDataSize = BYTES_PER_PIXEL*numPixels; 240 DASSERT(pixelDataSize > 0 && pixelDataSize % 4 == 0); 241 // allocate memory for BITMAPINFO + pixel data 242 // 4620932: When using BI_BITFIELDS, GetDIBits expects an array of 3 243 // RGBQUADS to follow the BITMAPINFOHEADER, but we were only allocating the 244 // 1 that is included in BITMAPINFO. Thus, GetDIBits was writing off the 245 // end of our block of memory. Now we allocate sufficient memory. 246 // See MSDN docs for BITMAPINFOHEADER -bchristi 247 248 if (!IS_SAFE_SIZE_ADD(sizeof(BITMAPINFOHEADER) + 3 * sizeof(RGBQUAD), pixelDataSize)) { 249 throw std::bad_alloc(); 250 } 251 BITMAPINFO * pinfo = (BITMAPINFO *)(new BYTE[sizeof(BITMAPINFOHEADER) + 3 * sizeof(RGBQUAD) + pixelDataSize]); 252 253 // pixel data starts after 3 RGBQUADS for color masks 254 RGBQUAD *pixelData = &pinfo->bmiColors[3]; 255 256 // prepare BITMAPINFO for a 32-bit RGB bitmap 257 ::memset(pinfo, 0, sizeof(*pinfo)); 258 pinfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 259 pinfo->bmiHeader.biWidth = width; 260 pinfo->bmiHeader.biHeight = -height; // negative height means a top-down DIB 261 pinfo->bmiHeader.biPlanes = 1; 262 pinfo->bmiHeader.biBitCount = BITS_PER_PIXEL; 263 pinfo->bmiHeader.biCompression = BI_BITFIELDS; 264 265 // Setup up color masks 266 static const RGBQUAD redMask = {0, 0, 0xFF, 0}; 267 static const RGBQUAD greenMask = {0, 0xFF, 0, 0}; 268 static const RGBQUAD blueMask = {0xFF, 0, 0, 0}; 269 270 pinfo->bmiColors[0] = redMask; 271 pinfo->bmiColors[1] = greenMask; 272 pinfo->bmiColors[2] = blueMask; 273 274 // Get the bitmap data in device-independent, 32-bit packed pixel format 275 ::GetDIBits(hdcMem, hbitmap, 0, height, pixelData, pinfo, DIB_RGB_COLORS); 276 277 // convert Win32 pixel format (BGRX) to Java format (ARGB) 278 DASSERT(sizeof(jint) == sizeof(RGBQUAD)); 279 for(int nPixel = 0; nPixel < numPixels; nPixel++) { 280 RGBQUAD * prgbq = &pixelData[nPixel]; 281 jint jpixel = WinToJavaPixel(prgbq->rgbRed, prgbq->rgbGreen, prgbq->rgbBlue); 282 // stuff the 32-bit pixel back into the 32-bit RGBQUAD 283 *prgbq = *( (RGBQUAD *)(&jpixel) ); 284 } 285 286 // copy pixels into Java array 287 env->SetIntArrayRegion(pixelArray, 0, numPixels, (jint *)pixelData); 288 delete pinfo; 289 290 // free all the GDI objects we made 291 ::SelectObject(hdcMem, hOldBitmap); 292 if (hOldPalette != NULL) { 293 ::SelectPalette(hdcMem, hOldPalette, FALSE); 294 } 295 ::DeleteObject(hbitmap); 296 ::DeleteDC(hdcMem); 297 ::DeleteDC(hdcScreen); 298 } 299 300 void AwtRobot::KeyPress( jint jkey ) 301 { 302 DoKeyEvent(jkey, 0, false); // no flags means key down 303 } 304 305 void AwtRobot::KeyRelease( jint jkey ) 306 { 307 DoKeyEvent(jkey, KEYEVENTF_KEYUP, false); 308 } 309 310 void AwtRobot::KeyPressUnicode( jint unicodeKey ) 311 { 312 DoKeyEvent(unicodeKey, 0, true); // no flags means key down 313 } 314 315 void AwtRobot::KeyReleaseUnicode( jint unicodeKey ) 316 { 317 DoKeyEvent(unicodeKey, KEYEVENTF_KEYUP, true); 318 } 319 320 void AwtRobot::DoKeyEvent( jint jkey, DWORD dwFlags, BOOL isUnicode ) 321 { 322 UINT vkey; 323 UINT modifiers; 324 UINT scancode; 325 JNIEnv * env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 326 327 if(isUnicode) { 328 /* 329 HandleUnicodeKeys() returns the status of the SendInput() 330 which returns 0 if there is a fail else non-zero. 331 The status 0 tells that the SendInput() in unable to interpret 332 the supplied input upon which the illegal argument exception 333 would be raised. 334 */ 335 if(!HandleUnicodeKeys(jkey, dwFlags)) { 336 // no equivalent Windows key found for given unicode key 337 JNU_ThrowIllegalArgumentException(env, "Invalid unicode key"); 338 } 339 } 340 else { 341 // convert Java key into Windows key (and modifiers too) 342 AwtComponent::JavaKeyToWindowsKey(jkey, &vkey, &modifiers); 343 344 if (vkey == 0) { 345 // no equivalent Windows key found for given Java keycode 346 JNU_ThrowIllegalArgumentException(env, "Invalid key code"); 347 } else { 348 // get the scancode from the virtual key 349 scancode = ::MapVirtualKey(vkey, 0); 350 if (vkey == VK_RMENU || 351 vkey == VK_DELETE || 352 vkey == VK_INSERT || 353 vkey == VK_NEXT || 354 vkey == VK_PRIOR || 355 vkey == VK_HOME || 356 vkey == VK_END || 357 vkey == VK_LEFT || 358 vkey == VK_RIGHT || 359 vkey == VK_UP || 360 vkey == VK_DOWN) { 361 dwFlags |= KEYEVENTF_EXTENDEDKEY; 362 } 363 keybd_event(vkey, scancode, dwFlags, 0); 364 } 365 } 366 } 367 368 UINT AwtRobot::HandleUnicodeKeys(jint unicodeKey, DWORD dwFlags) 369 { 370 NSWinInput::INPUT ip; 371 ip.type = 1; //INPUT_KEYBOARD; 372 ip.ki.wVk = 0; 373 ip.ki.wScan = unicodeKey; 374 ip.ki.dwFlags = (DWORD)(dwFlags | 4); //KEYEVENTF_UNICODE(4) 375 ip.ki.dwExtraInfo = 0; 376 return SendInput(1, (LPINPUT)&ip, sizeof(INPUT)); 377 } 378 379 // 380 // utility function to get the C++ object from the Java one 381 // 382 // (static) 383 AwtRobot * AwtRobot::GetRobot( jobject self ) 384 { 385 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 386 AwtRobot * robot = (AwtRobot *)JNI_GET_PDATA(self); 387 DASSERT( !::IsBadWritePtr( robot, sizeof(AwtRobot))); 388 return robot; 389 } 390 391 ////////////////////////////////////////////////////////////////////////////////////////////// 392 // Native method declarations 393 // 394 395 JNIEXPORT void JNICALL Java_sun_awt_windows_WRobotPeer_create( 396 JNIEnv * env, jobject self) 397 { 398 TRY; 399 400 new AwtRobot(self); 401 402 CATCH_BAD_ALLOC; 403 } 404 405 JNIEXPORT void JNICALL Java_sun_awt_windows_WRobotPeer__1dispose( 406 JNIEnv *env, jobject self) 407 { 408 TRY_NO_VERIFY; 409 410 AwtObject::_Dispose(self); 411 412 CATCH_BAD_ALLOC; 413 } 414 415 JNIEXPORT void JNICALL Java_sun_awt_windows_WRobotPeer_mouseMoveImpl( 416 JNIEnv * env, jobject self, jint x, jint y) 417 { 418 TRY; 419 420 AwtRobot::GetRobot(self)->MouseMove(x, y); 421 422 CATCH_BAD_ALLOC; 423 } 424 425 JNIEXPORT void JNICALL Java_sun_awt_windows_WRobotPeer_mousePress( 426 JNIEnv * env, jobject self, jint buttons) 427 { 428 TRY; 429 430 AwtRobot::GetRobot(self)->MousePress(buttons); 431 432 CATCH_BAD_ALLOC; 433 } 434 435 JNIEXPORT void JNICALL Java_sun_awt_windows_WRobotPeer_mouseRelease( 436 JNIEnv * env, jobject self, jint buttons) 437 { 438 TRY; 439 440 AwtRobot::GetRobot(self)->MouseRelease(buttons); 441 442 CATCH_BAD_ALLOC; 443 } 444 445 JNIEXPORT void JNICALL Java_sun_awt_windows_WRobotPeer_mouseWheel( 446 JNIEnv * env, jobject self, jint wheelAmt) 447 { 448 TRY; 449 450 AwtRobot::GetRobot(self)->MouseWheel(wheelAmt); 451 452 CATCH_BAD_ALLOC; 453 } 454 455 JNIEXPORT void JNICALL Java_sun_awt_windows_WRobotPeer_getRGBPixels( 456 JNIEnv *env, jobject self, jint x, jint y, jint width, jint height, jintArray pixelArray) 457 { 458 TRY; 459 460 AwtRobot::GetRobot(self)->GetRGBPixels(x, y, width, height, pixelArray); 461 462 CATCH_BAD_ALLOC; 463 } 464 465 JNIEXPORT void JNICALL Java_sun_awt_windows_WRobotPeer_keyPress( 466 JNIEnv *, jobject self, jint javakey ) 467 { 468 TRY; 469 470 AwtRobot::GetRobot(self)->KeyPress(javakey); 471 472 CATCH_BAD_ALLOC; 473 } 474 475 JNIEXPORT void JNICALL Java_sun_awt_windows_WRobotPeer_keyRelease( 476 JNIEnv *, jobject self, jint javakey ) 477 { 478 TRY; 479 480 AwtRobot::GetRobot(self)->KeyRelease(javakey); 481 482 CATCH_BAD_ALLOC; 483 } 484 485 JNIEXPORT void JNICALL Java_sun_awt_windows_WRobotPeer_keyPressUnicode( 486 JNIEnv *, jobject self, jint javakey ) 487 { 488 TRY; 489 490 AwtRobot::GetRobot(self)->KeyPressUnicode(javakey); 491 492 CATCH_BAD_ALLOC; 493 } 494 495 JNIEXPORT void JNICALL Java_sun_awt_windows_WRobotPeer_keyReleaseUnicode( 496 JNIEnv *, jobject self, jint javakey ) 497 { 498 TRY; 499 500 AwtRobot::GetRobot(self)->KeyReleaseUnicode(javakey); 501 502 CATCH_BAD_ALLOC; 503 } 504