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