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 }