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); // no flags means key down 303 } 304 305 void AwtRobot::KeyRelease( jint jkey ) 306 { 307 DoKeyEvent(jkey, KEYEVENTF_KEYUP); 308 } 309 310 void AwtRobot::DoKeyEvent( jint jkey, DWORD dwFlags ) 311 { 312 UINT vkey; 313 UINT modifiers; 314 UINT scancode; 315 JNIEnv * env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 316 317 // convert Java key into Windows key (and modifiers too) 318 AwtComponent::JavaKeyToWindowsKey(jkey, &vkey, &modifiers); 319 320 if (vkey == 0) { 321 /* vkey would be 0 for all non-ascii inputs. If non-ascii 322 then we assume they are unicode characters and will 323 supply such input to SendInput() which can handle unicode 324 characters as well as ascii chars. Windows provides api's to 325 handle ascii and unicode characters. All ascii characters 326 (both OEM and standard ascii) would be supplied to keybd_event(). 327 328 HandleUnicodeKeys() returns the status of the SendInput() 329 which returns 0 if there is a fail else non-zero. 330 The status 0 tells that the SendInput() in unable to interpret 331 the supplied input upon which the illegal argument exception 332 would be raised. 333 */ 334 if(!HandleUnicodeKeys(jkey, dwFlags)) { 335 // no equivalent Windows key found for given Java keycode 336 JNU_ThrowIllegalArgumentException(env, "Invalid key code"); 337 } 338 } else { 339 // get the scancode from the virtual key 340 scancode = ::MapVirtualKey(vkey, 0); 341 if (vkey == VK_RMENU || 342 vkey == VK_DELETE || 343 vkey == VK_INSERT || 344 vkey == VK_NEXT || 345 vkey == VK_PRIOR || 346 vkey == VK_HOME || 347 vkey == VK_END || 348 vkey == VK_LEFT || 349 vkey == VK_RIGHT || 350 vkey == VK_UP || 351 vkey == VK_DOWN) { 352 dwFlags |= KEYEVENTF_EXTENDEDKEY; 353 } 354 keybd_event(vkey, scancode, dwFlags, 0); 355 } 356 } 357 358 UINT AwtRobot::HandleUnicodeKeys(jint key, DWORD dwFlags) 359 { 360 NSWinInput::INPUT ip; 361 ip.type = 1; //INPUT_KEYBOARD; 362 ip.ki.wVk = 0; 363 ip.ki.wScan = key; 364 ip.ki.dwFlags = (DWORD)(dwFlags | 4); //KEYEVENTF_UNICODE(4) 365 ip.ki.dwExtraInfo = 0; 366 return SendInput(1, (LPINPUT)&ip, sizeof(INPUT)); 367 } 368 369 // 370 // utility function to get the C++ object from the Java one 371 // 372 // (static) 373 AwtRobot * AwtRobot::GetRobot( jobject self ) 374 { 375 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 376 AwtRobot * robot = (AwtRobot *)JNI_GET_PDATA(self); 377 DASSERT( !::IsBadWritePtr( robot, sizeof(AwtRobot))); 378 return robot; 379 } 380 381 ////////////////////////////////////////////////////////////////////////////////////////////// 382 // Native method declarations 383 // 384 385 JNIEXPORT void JNICALL Java_sun_awt_windows_WRobotPeer_create( 386 JNIEnv * env, jobject self) 387 { 388 TRY; 389 390 new AwtRobot(self); 391 392 CATCH_BAD_ALLOC; 393 } 394 395 JNIEXPORT void JNICALL Java_sun_awt_windows_WRobotPeer__1dispose( 396 JNIEnv *env, jobject self) 397 { 398 TRY_NO_VERIFY; 399 400 AwtObject::_Dispose(self); 401 402 CATCH_BAD_ALLOC; 403 } 404 405 JNIEXPORT void JNICALL Java_sun_awt_windows_WRobotPeer_mouseMoveImpl( 406 JNIEnv * env, jobject self, jint x, jint y) 407 { 408 TRY; 409 410 AwtRobot::GetRobot(self)->MouseMove(x, y); 411 412 CATCH_BAD_ALLOC; 413 } 414 415 JNIEXPORT void JNICALL Java_sun_awt_windows_WRobotPeer_mousePress( 416 JNIEnv * env, jobject self, jint buttons) 417 { 418 TRY; 419 420 AwtRobot::GetRobot(self)->MousePress(buttons); 421 422 CATCH_BAD_ALLOC; 423 } 424 425 JNIEXPORT void JNICALL Java_sun_awt_windows_WRobotPeer_mouseRelease( 426 JNIEnv * env, jobject self, jint buttons) 427 { 428 TRY; 429 430 AwtRobot::GetRobot(self)->MouseRelease(buttons); 431 432 CATCH_BAD_ALLOC; 433 } 434 435 JNIEXPORT void JNICALL Java_sun_awt_windows_WRobotPeer_mouseWheel( 436 JNIEnv * env, jobject self, jint wheelAmt) 437 { 438 TRY; 439 440 AwtRobot::GetRobot(self)->MouseWheel(wheelAmt); 441 442 CATCH_BAD_ALLOC; 443 } 444 445 JNIEXPORT void JNICALL Java_sun_awt_windows_WRobotPeer_getRGBPixels( 446 JNIEnv *env, jobject self, jint x, jint y, jint width, jint height, jintArray pixelArray) 447 { 448 TRY; 449 450 AwtRobot::GetRobot(self)->GetRGBPixels(x, y, width, height, pixelArray); 451 452 CATCH_BAD_ALLOC; 453 } 454 455 JNIEXPORT void JNICALL Java_sun_awt_windows_WRobotPeer_keyPress( 456 JNIEnv *, jobject self, jint javakey ) 457 { 458 TRY; 459 460 AwtRobot::GetRobot(self)->KeyPress(javakey); 461 462 CATCH_BAD_ALLOC; 463 } 464 465 JNIEXPORT void JNICALL Java_sun_awt_windows_WRobotPeer_keyRelease( 466 JNIEnv *, jobject self, jint javakey ) 467 { 468 TRY; 469 470 AwtRobot::GetRobot(self)->KeyRelease(javakey); 471 472 CATCH_BAD_ALLOC; 473 }