| /* |
| * Copyright 1998-2006 Sun Microsystems, Inc. All Rights Reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Sun designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Sun in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
| * CA 95054 USA or visit www.sun.com if you need additional information or |
| * have any questions. |
| */ |
| |
| #include "awt_Toolkit.h" |
| #include "awt_Component.h" |
| #include "awt_Robot.h" |
| #include "sun_awt_windows_WRobotPeer.h" |
| #include "java_awt_event_InputEvent.h" |
| #include <winuser.h> |
| |
| static const int MOUSE_MAX = 65535; |
| |
| AwtRobot::AwtRobot( jobject peer ) |
| { |
| JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); |
| m_peerObject = env->NewWeakGlobalRef(peer); |
| JNI_SET_PDATA(peer, this); |
| } |
| |
| AwtRobot::~AwtRobot() |
| { |
| } |
| |
| #ifndef SPI_GETMOUSESPEED |
| #define SPI_GETMOUSESPEED 112 |
| #endif |
| |
| #ifndef SPI_SETMOUSESPEED |
| #define SPI_SETMOUSESPEED 113 |
| #endif |
| |
| void AwtRobot::MouseMove( jint x, jint y) |
| { |
| // Fix for Bug 4288230. See Q193003 from MSDN. |
| int oldAccel[3], newAccel[3]; |
| INT_PTR oldSpeed, newSpeed; |
| BOOL bResult; |
| |
| // The following values set mouse ballistics to 1 mickey/pixel. |
| newAccel[0] = 0; |
| newAccel[1] = 0; |
| newAccel[2] = 0; |
| newSpeed = 10; |
| |
| // Save the Current Mouse Acceleration Constants |
| bResult = SystemParametersInfo(SPI_GETMOUSE,0,oldAccel,0); |
| bResult = SystemParametersInfo(SPI_GETMOUSESPEED, 0, &oldSpeed,0); |
| // Set the new Mouse Acceleration Constants (Disabled). |
| bResult = SystemParametersInfo(SPI_SETMOUSE,0,newAccel,SPIF_SENDCHANGE); |
| bResult = SystemParametersInfo(SPI_SETMOUSESPEED, 0, |
| // 4504963: Though the third argument to SystemParameterInfo is |
| // declared as a PVOID, as of Windows 2000 it is apparently |
| // interpreted as an int. (The MSDN docs for SPI_SETMOUSESPEED |
| // say that it's an integer between 1 and 20, the default being |
| // 10). Instead of passing the @ of the desired value, the |
| // value itself is now passed, cast as a PVOID so as to |
| // compile. -bchristi 10/02/2001 |
| (PVOID)newSpeed, |
| SPIF_SENDCHANGE); |
| |
| POINT curPos; |
| ::GetCursorPos(&curPos); |
| x -= curPos.x; |
| y -= curPos.y; |
| |
| mouse_event(MOUSEEVENTF_MOVE,x,y,0,0); |
| // Move the cursor to the desired coordinates. |
| |
| // Restore the old Mouse Acceleration Constants. |
| bResult = SystemParametersInfo(SPI_SETMOUSE,0, oldAccel, SPIF_SENDCHANGE); |
| bResult = SystemParametersInfo(SPI_SETMOUSESPEED, 0, (PVOID)oldSpeed, |
| SPIF_SENDCHANGE); |
| } |
| |
| void AwtRobot::MousePress( jint buttonMask ) |
| { |
| DWORD dwFlags = 0L; |
| // According to MSDN: Software Driving Software |
| // application should consider SM_SWAPBUTTON to correctly emulate user with |
| // left handed mouse setup |
| BOOL bSwap = ::GetSystemMetrics(SM_SWAPBUTTON); |
| |
| if ( buttonMask & java_awt_event_InputEvent_BUTTON1_MASK ) { |
| dwFlags |= !bSwap ? MOUSEEVENTF_LEFTDOWN : MOUSEEVENTF_RIGHTDOWN; |
| } |
| |
| if ( buttonMask & java_awt_event_InputEvent_BUTTON3_MASK ) { |
| dwFlags |= !bSwap ? MOUSEEVENTF_RIGHTDOWN : MOUSEEVENTF_LEFTDOWN; |
| } |
| |
| if ( buttonMask & java_awt_event_InputEvent_BUTTON2_MASK ) { |
| dwFlags |= MOUSEEVENTF_MIDDLEDOWN; |
| } |
| |
| mouse_event(dwFlags, 0, 0, 0, 0 ); |
| } |
| |
| void AwtRobot::MouseRelease( jint buttonMask ) |
| { |
| DWORD dwFlags = 0L; |
| // According to MSDN: Software Driving Software |
| // application should consider SM_SWAPBUTTON to correctly emulate user with |
| // left handed mouse setup |
| BOOL bSwap = ::GetSystemMetrics(SM_SWAPBUTTON); |
| |
| if ( buttonMask & java_awt_event_InputEvent_BUTTON1_MASK ) { |
| dwFlags |= !bSwap ? MOUSEEVENTF_LEFTUP : MOUSEEVENTF_RIGHTUP; |
| } |
| |
| if ( buttonMask & java_awt_event_InputEvent_BUTTON3_MASK ) { |
| dwFlags |= !bSwap ? MOUSEEVENTF_RIGHTUP : MOUSEEVENTF_LEFTUP; |
| } |
| |
| if ( buttonMask & java_awt_event_InputEvent_BUTTON2_MASK ) { |
| dwFlags |= MOUSEEVENTF_MIDDLEUP; |
| } |
| |
| mouse_event(dwFlags, 0, 0, 0, 0 ); |
| } |
| |
| void AwtRobot::MouseWheel (jint wheelAmt) { |
| if (IS_WIN95 && !IS_WIN98) { |
| // Other win32 platforms do nothing for mouse_event(0), so |
| // do nothing on 95, too. |
| if (wheelAmt == 0) { |
| return; |
| } |
| |
| // Win95 doesn't understand MOUSEEVENTF_WHEEL, so use PostEvent |
| POINT curPos; |
| HWND mouseOver = NULL; |
| HWND topLevel = NULL; |
| UINT wheelMsg = NULL; |
| |
| if (::GetCursorPos((LPPOINT)&curPos) == 0) { |
| return; |
| } |
| // get hwnd of top-level container |
| mouseOver = ::WindowFromPoint(curPos); |
| DASSERT(mouseOver); |
| topLevel = AwtComponent::GetTopLevelParentForWindow(mouseOver); |
| DASSERT(topLevel); |
| |
| if (::ScreenToClient(topLevel, (LPPOINT)&curPos) == 0) { |
| return; |
| } |
| wheelMsg = AwtComponent::Wheel95GetMsg(); |
| |
| if (wheelMsg == NULL) { |
| return; |
| } |
| |
| ::PostMessage(topLevel, |
| wheelMsg, |
| wheelAmt * -1 * WHEEL_DELTA, |
| MAKELPARAM((WORD)curPos.x, (WORD)curPos.y)); |
| } |
| else { |
| mouse_event(MOUSEEVENTF_WHEEL, 0, 0, wheelAmt * -1 * WHEEL_DELTA, 0); |
| } |
| } |
| |
| inline jint AwtRobot::WinToJavaPixel(USHORT r, USHORT g, USHORT b) |
| { |
| jint value = |
| 0xFF << 24 | // alpha channel is always turned all the way up |
| r << 16 | |
| g << 8 | |
| b << 0; |
| return value; |
| } |
| |
| jint AwtRobot::GetRGBPixel( jint x, jint y) |
| { |
| HDC hdc = GetDC(NULL); |
| COLORREF ref = ::GetPixel( hdc, x, y ); |
| ReleaseDC(NULL,hdc); |
| jint value = WinToJavaPixel(GetRValue(ref), GetGValue(ref), GetBValue(ref)); |
| return value; |
| } |
| |
| void AwtRobot::GetRGBPixels(jint x, jint y, jint width, jint height, jintArray pixelArray) |
| { |
| DASSERT(width > 0 && height > 0); |
| |
| HDC hdcScreen = ::CreateDC(TEXT("DISPLAY"), NULL, NULL, NULL); |
| HDC hdcMem = ::CreateCompatibleDC(hdcScreen); |
| HBITMAP hbitmap; |
| HBITMAP hOldBitmap; |
| HPALETTE hOldPalette = NULL; |
| JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); |
| |
| // create an offscreen bitmap |
| hbitmap = ::CreateCompatibleBitmap(hdcScreen, width, height); |
| if (hbitmap == NULL) { |
| throw std::bad_alloc(); |
| } |
| hOldBitmap = (HBITMAP)::SelectObject(hdcMem, hbitmap); |
| |
| // REMIND: not multimon-friendly... |
| int primaryIndex = AwtWin32GraphicsDevice::GetDefaultDeviceIndex(); |
| hOldPalette = |
| AwtWin32GraphicsDevice::SelectPalette(hdcMem, primaryIndex); |
| AwtWin32GraphicsDevice::RealizePalette(hdcMem, primaryIndex); |
| |
| // copy screen image to offscreen bitmap |
| // CAPTUREBLT flag is required to capture WS_EX_LAYERED windows' contents |
| // correctly on Win2K/XP |
| VERIFY(::BitBlt(hdcMem, 0, 0, width, height, hdcScreen, x, y, |
| SRCCOPY|CAPTUREBLT) != 0); |
| |
| static const int BITS_PER_PIXEL = 32; |
| static const int BYTES_PER_PIXEL = BITS_PER_PIXEL/8; |
| |
| int numPixels = width*height; |
| int pixelDataSize = BYTES_PER_PIXEL*numPixels; |
| DASSERT(pixelDataSize > 0 && pixelDataSize % 4 == 0); |
| // allocate memory for BITMAPINFO + pixel data |
| // 4620932: When using BI_BITFIELDS, GetDIBits expects an array of 3 |
| // RGBQUADS to follow the BITMAPINFOHEADER, but we were only allocating the |
| // 1 that is included in BITMAPINFO. Thus, GetDIBits was writing off the |
| // end of our block of memory. Now we allocate sufficient memory. |
| // See MSDN docs for BITMAPINFOHEADER -bchristi |
| |
| BITMAPINFO * pinfo = (BITMAPINFO *)(new BYTE[sizeof(BITMAPINFOHEADER) + 3 * sizeof(RGBQUAD) + pixelDataSize]); |
| |
| // pixel data starts after 3 RGBQUADS for color masks |
| RGBQUAD *pixelData = &pinfo->bmiColors[3]; |
| |
| // prepare BITMAPINFO for a 32-bit RGB bitmap |
| ::memset(pinfo, 0, sizeof(*pinfo)); |
| pinfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); |
| pinfo->bmiHeader.biWidth = width; |
| pinfo->bmiHeader.biHeight = -height; // negative height means a top-down DIB |
| pinfo->bmiHeader.biPlanes = 1; |
| pinfo->bmiHeader.biBitCount = BITS_PER_PIXEL; |
| pinfo->bmiHeader.biCompression = BI_BITFIELDS; |
| |
| // Setup up color masks |
| static const RGBQUAD redMask = {0, 0, 0xFF, 0}; |
| static const RGBQUAD greenMask = {0, 0xFF, 0, 0}; |
| static const RGBQUAD blueMask = {0xFF, 0, 0, 0}; |
| |
| pinfo->bmiColors[0] = redMask; |
| pinfo->bmiColors[1] = greenMask; |
| pinfo->bmiColors[2] = blueMask; |
| |
| // Get the bitmap data in device-independent, 32-bit packed pixel format |
| ::GetDIBits(hdcMem, hbitmap, 0, height, pixelData, pinfo, DIB_RGB_COLORS); |
| |
| // convert Win32 pixel format (BGRX) to Java format (ARGB) |
| DASSERT(sizeof(jint) == sizeof(RGBQUAD)); |
| for(int nPixel = 0; nPixel < numPixels; nPixel++) { |
| RGBQUAD * prgbq = &pixelData[nPixel]; |
| jint jpixel = WinToJavaPixel(prgbq->rgbRed, prgbq->rgbGreen, prgbq->rgbBlue); |
| // stuff the 32-bit pixel back into the 32-bit RGBQUAD |
| *prgbq = *( (RGBQUAD *)(&jpixel) ); |
| } |
| |
| // copy pixels into Java array |
| env->SetIntArrayRegion(pixelArray, 0, numPixels, (jint *)pixelData); |
| delete pinfo; |
| |
| // free all the GDI objects we made |
| ::SelectObject(hdcMem, hOldBitmap); |
| if (hOldPalette != NULL) { |
| ::SelectPalette(hdcMem, hOldPalette, FALSE); |
| } |
| ::DeleteObject(hbitmap); |
| ::DeleteDC(hdcMem); |
| ::DeleteDC(hdcScreen); |
| } |
| |
| void AwtRobot::KeyPress( jint jkey ) |
| { |
| DoKeyEvent(jkey, 0); // no flags means key down |
| } |
| |
| void AwtRobot::KeyRelease( jint jkey ) |
| { |
| DoKeyEvent(jkey, KEYEVENTF_KEYUP); |
| } |
| |
| void AwtRobot::DoKeyEvent( jint jkey, DWORD dwFlags ) |
| { |
| UINT vkey; |
| UINT modifiers; |
| UINT scancode; |
| JNIEnv * env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); |
| |
| // convert Java key into Windows key (and modifiers too) |
| AwtComponent::JavaKeyToWindowsKey(jkey, &vkey, &modifiers); |
| if (vkey == 0) { |
| // no equivalent Windows key found for given Java keycode |
| JNU_ThrowIllegalArgumentException(env, "Invalid key code"); |
| } else { |
| // get the scancode from the virtual key |
| scancode = ::MapVirtualKey(vkey, 0); |
| keybd_event(vkey, scancode, dwFlags, 0); |
| } |
| } |
| |
| // |
| // utility function to get the C++ object from the Java one |
| // |
| // (static) |
| AwtRobot * AwtRobot::GetRobot( jobject self ) |
| { |
| JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); |
| AwtRobot * robot = (AwtRobot *)JNI_GET_PDATA(self); |
| DASSERT( !::IsBadWritePtr( robot, sizeof(AwtRobot))); |
| return robot; |
| } |
| |
| ////////////////////////////////////////////////////////////////////////////////////////////// |
| // Native method declarations |
| // |
| |
| JNIEXPORT void JNICALL Java_sun_awt_windows_WRobotPeer_create( |
| JNIEnv * env, jobject self) |
| { |
| TRY; |
| |
| new AwtRobot(self); |
| |
| CATCH_BAD_ALLOC; |
| } |
| |
| JNIEXPORT void JNICALL Java_sun_awt_windows_WRobotPeer__1dispose( |
| JNIEnv *env, jobject self) |
| { |
| TRY_NO_VERIFY; |
| |
| PDATA pData = JNI_GET_PDATA(self); |
| AwtObject::_Dispose(pData); |
| |
| CATCH_BAD_ALLOC; |
| } |
| |
| JNIEXPORT void JNICALL Java_sun_awt_windows_WRobotPeer_mouseMoveImpl( |
| JNIEnv * env, jobject self, jint x, jint y) |
| { |
| TRY; |
| |
| AwtRobot::GetRobot(self)->MouseMove(x, y); |
| |
| CATCH_BAD_ALLOC; |
| } |
| |
| JNIEXPORT void JNICALL Java_sun_awt_windows_WRobotPeer_mousePress( |
| JNIEnv * env, jobject self, jint buttons) |
| { |
| TRY; |
| |
| AwtRobot::GetRobot(self)->MousePress(buttons); |
| |
| CATCH_BAD_ALLOC; |
| } |
| |
| JNIEXPORT void JNICALL Java_sun_awt_windows_WRobotPeer_mouseRelease( |
| JNIEnv * env, jobject self, jint buttons) |
| { |
| TRY; |
| |
| AwtRobot::GetRobot(self)->MouseRelease(buttons); |
| |
| CATCH_BAD_ALLOC; |
| } |
| |
| JNIEXPORT void JNICALL Java_sun_awt_windows_WRobotPeer_mouseWheel( |
| JNIEnv * env, jobject self, jint wheelAmt) |
| { |
| TRY; |
| |
| AwtRobot::GetRobot(self)->MouseWheel(wheelAmt); |
| |
| CATCH_BAD_ALLOC; |
| } |
| |
| JNIEXPORT jint JNICALL Java_sun_awt_windows_WRobotPeer_getRGBPixelImpl( |
| JNIEnv * env, jobject self, jint x, jint y) |
| { |
| TRY; |
| |
| return AwtRobot::GetRobot(self)->GetRGBPixel(x, y); |
| |
| CATCH_BAD_ALLOC_RET(0); |
| } |
| JNIEXPORT void JNICALL Java_sun_awt_windows_WRobotPeer_getRGBPixels( |
| JNIEnv *env, jobject self, jint x, jint y, jint width, jint height, jintArray pixelArray) |
| { |
| TRY; |
| |
| AwtRobot::GetRobot(self)->GetRGBPixels(x, y, width, height, pixelArray); |
| |
| CATCH_BAD_ALLOC; |
| } |
| |
| JNIEXPORT void JNICALL Java_sun_awt_windows_WRobotPeer_keyPress( |
| JNIEnv *, jobject self, jint javakey ) |
| { |
| TRY; |
| |
| AwtRobot::GetRobot(self)->KeyPress(javakey); |
| |
| CATCH_BAD_ALLOC; |
| } |
| |
| JNIEXPORT void JNICALL Java_sun_awt_windows_WRobotPeer_keyRelease( |
| JNIEnv *, jobject self, jint javakey ) |
| { |
| TRY; |
| |
| AwtRobot::GetRobot(self)->KeyRelease(javakey); |
| |
| CATCH_BAD_ALLOC; |
| } |