diff -r 000000000000 -r cec860690d41 emulator/emulatorbsp/specific/multitouch.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/emulator/emulatorbsp/specific/multitouch.cpp Tue Feb 02 01:39:10 2010 +0200 @@ -0,0 +1,522 @@ +// Copyright (c) 1995-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// wins\specific\multitouch.cpp +// +// +#include "multitouch.h" +#include "resource.h" + +#define KDefaultMaxProximity -100 +#define KDefaultMaxPressure 5000 +#define KDefaultPressureStep 500 +#define KDefaultProximityStep 5 + +// Static members +DMultiMouse DMultiMouse::iMice[KMaxMice]; +int DMultiMouse::iNumMice = 0; +DMultiMouse* DMultiMouse::iPrimary = 0; +int DMultiMouse::iMouseId = 0; +int DMultiTouch::iNumberOfMice = 0; +bool DMultiTouch::iMultiTouchSupported= FALSE; +bool DMultiTouch::iMultiTouchCreated= FALSE; +bool DMultiTouch::iMultiTouchTempEnabled= FALSE; + +// Function pointers for raw input APIs +TYPEOF_RegisterRawInputDevices pfnRegisterRawInputDevices= NULL; +TYPEOF_GetRawInputData pfnGetRawInputData= NULL; +TYPEOF_GetRawInputDeviceList pfnGetRawInputDeviceList=NULL; + +/** + * Initialise the proximity and pressure information if undefined by the user + */ +DMultiTouch::DMultiTouch(TInt aProximityStep, TInt aPressureStep) + { + iZMaxRange = KDefaultMaxProximity; + iMaxPressure = KDefaultMaxPressure; + iProximityStep = (aProximityStep == -1) ? KDefaultProximityStep : aProximityStep; + iPressureStep = (aPressureStep == -1) ? KDefaultPressureStep : aPressureStep; + } + +/** + * Register all the mice +*/ +BOOL DMultiTouch::Register() + { + RAWINPUTDEVICE device; + device.usUsagePage = 0x01; + device.usUsage = 0x02; + device.dwFlags = RIDEV_NOLEGACY; // adds HID mouse and also ignores legacy mouse messages + device.hwndTarget = 0; + ShowCursors(); + return pfnRegisterRawInputDevices(&device, 1, sizeof(RAWINPUTDEVICE)); + } + +/** + * Unregister mice devices + */ +BOOL DMultiTouch::UnRegister() + { + RAWINPUTDEVICE device; + device.usUsagePage = 0x01; + device.usUsage = 0x02; + device.dwFlags = RIDEV_REMOVE; + device.hwndTarget = NULL; + HideCursors(); + return pfnRegisterRawInputDevices(&device, 1, sizeof(RAWINPUTDEVICE)); + } + + +/* * Handle multi-input Window messages + */ +void DMultiTouch::OnWmInput(HWND aHWnd,TUint aMessage,TUint aWParam,TUint aLParam,HWND aParentHwnd) + { + RAWINPUT ri; + UINT dwSize = sizeof(ri); + if (pfnGetRawInputData((HRAWINPUT)aLParam, RID_INPUT, &ri, &dwSize, sizeof(RAWINPUTHEADER))==(UINT)-1) + { + OutputDebugString(TEXT("GetRawInputData has an error !\n")); + } + else if (ri.header.dwType == RIM_TYPEMOUSE) + { + DMultiMouse* mouse = DMultiMouse::Find(ri.header.hDevice); + if (mouse) + { + if (!DMultiMouse::iPrimary) + { + DMultiMouse::iPrimary = mouse; + DMultiMouse::iPrimary->iIsPrimary = TRUE; + } + mouse->HandleRawMouseEvent(ri.data.mouse, aParentHwnd); + } + } + DefWindowProcA(aHWnd, aMessage, aWParam, aLParam); + } + +void DMultiTouch::HideCursors() + { + for (int ii=0; iiiCursor,0,0,0,NULL, DI_NORMAL | DI_DEFAULTSIZE); + EndPaint(hwnd, &ps); + return 0; + } + return DefWindowProc(hwnd, msg, wp, lp); + } + +CursorWindow::CursorWindow(): iHwnd(NULL),iCursor(NULL),iNumber(0) + { + } + +HWND CursorWindow::Create(HMODULE hm, HWND hwndParent, int number) + { + // Create the window + static ATOM atom = NULL; + if (!atom) + { + WNDCLASSEX wcex; + ZeroMemory(&wcex, sizeof(wcex)); + wcex.cbSize = sizeof(WNDCLASSEX); + wcex.style = CS_OWNDC; + wcex.lpfnWndProc = (WNDPROC)CursorWndProc; + wcex.hInstance = (HINSTANCE)hm; + wcex.lpszClassName = TEXT("CursorWndClass"); + wcex.hbrBackground = CreateSolidBrush(RGB(255,0,0));//Background color is also for the number + atom = RegisterClassEx(&wcex); + } + iHwnd = CreateWindowA((LPCSTR)atom, NULL, WS_CHILD|WS_CLIPSIBLINGS, 0,0,64,64, hwndParent, NULL, hm, NULL); + SetWindowLong(iHwnd, GWL_USERDATA, (LONG)this); + iNumber = number; + return iHwnd; + } + +void CursorWindow::Show() + { + ShowWindow(iHwnd, SW_NORMAL); + } + +void CursorWindow::Hide() + { + ShowWindow(iHwnd, SW_HIDE); + } + +BOOL CursorWindow::SetCursor(HCURSOR hc) + { + // Duplicate the cursor (because we're going to draw a number on the mask) + if (iCursor) + { + DestroyCursor(iCursor); + iCursor = NULL; + } + iCursor = CopyCursor(hc); + + // Get information about the cursor, and select its mask bitmap into a temporary DC. + ICONINFO ii; + GetIconInfo(iCursor, &ii); + iHotspot.x = ii.xHotspot; + iHotspot.y = ii.yHotspot; + HDC hdc = CreateCompatibleDC(NULL); + SelectObject(hdc, ii.hbmMask); + + // Get the cursor's pixel size + BITMAPINFO bmi; + bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi.bmiHeader.biBitCount = 0; + GetDIBits(hdc, ii.hbmMask, 0, 0, NULL, &bmi, DIB_RGB_COLORS); + int cx = bmi.bmiHeader.biWidth; + int cy = bmi.bmiHeader.biHeight; + + // Monochrome cursors have a double-height hbmMask. The top half contains the AND + // bitmap (which we do want) and the bottom half contains the XOR bitmap (which we + // dont want). Colour cursors have a single normal-height AND mask. + BOOL isMonochrome = (ii.hbmColor==NULL); + int cyy = isMonochrome ? (cy>>1) : cy; + + // Draw the number into the mask + char ach[4]; + int ld = iNumber/10; + int rd = iNumber % 10; + if (ld > 0) + { + wsprintf((LPTSTR)ach, (LPCTSTR)TEXT("%d%d"), ld,rd); + } + else + { + wsprintf((LPTSTR)ach, (LPCTSTR)TEXT("%d"), rd); + } + + HFONT hf = CreateFontA(12,0, 0,0,FW_THIN, FALSE,FALSE,FALSE, 0,DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, 0, "Arial"); + SelectObject(hdc, hf); + SetBkMode(hdc, TRANSPARENT); + TextOutA(hdc, 0,cyy-12, ach, 2); + DeleteObject(hf); + + // Get the bits of the mask (in 32-bit colour) + HANDLE heap = GetProcessHeap(); + bmi.bmiHeader.biBitCount = 32; + DWORD* bits = (DWORD*)HeapAlloc(heap, 0, cx*cy*4); + GetDIBits(hdc, ii.hbmMask, 0, cy, bits, &bmi, DIB_RGB_COLORS); + + // Set the window to the size of the cursor + SetWindowPos(iHwnd, NULL,0,0,cx,cyy, SWP_NOMOVE); + + // Create a cursor-shaped region by starting out with an empty region + // and ORing in each zero-valued mask pixel. + HRGN rgn = CreateRectRgn(0,0,0,0); + for (int y=0 ; yiX; + iY = iPrimary->iY; + } + + if (aEvent.usFlags & MOUSE_MOVE_ABSOLUTE) + { + // absolute position info can update all pointers + iX = aEvent.lLastX; + iY = aEvent.lLastY; + } + else if (!iIsPrimary) + { + // relative position info updates non-primary pointers, + iX += aEvent.lLastX; + iY += aEvent.lLastY; + } + + // Show the cursor window + ShowMousePos(aWnd); + + TInt message = WM_MOUSEMOVE; + + // get button state + if (aEvent.usButtonFlags & RI_MOUSE_LEFT_BUTTON_DOWN) + { + message = WM_LBUTTONDOWN; + iZ = 0; + } + + if (aEvent.usButtonFlags & RI_MOUSE_LEFT_BUTTON_UP) + { + message = WM_LBUTTONUP; + iZ = 0; + } + + if (aEvent.usButtonFlags & RI_MOUSE_RIGHT_BUTTON_DOWN) + { + message = WM_RBUTTONDOWN; + } + + if (aEvent.usButtonFlags & RI_MOUSE_RIGHT_BUTTON_UP) + { + message = WM_RBUTTONUP; + } + + if (aEvent.usButtonFlags & RI_MOUSE_WHEEL) + { + message = WM_MOUSEWHEEL; + if ((TInt16)(aEvent.usButtonData&0x8000)== 0) // positive number + { + if (iZ < TheMultiTouch->iMaxPressure) + { + if (iZ>=0) + { // pressure range + iZ += TheMultiTouch->iPressureStep;//Pressure step + if (iZ > TheMultiTouch->iMaxPressure) + { + iZ = TheMultiTouch->iMaxPressure; + } + } + else + { // proximity range + iZ += TheMultiTouch->iProximityStep; //Proximity step + } + } + } + else + { + if (iZ > TheMultiTouch->iZMaxRange) + { + if (iZ <= 0) + {// proximity range + iZ -= TheMultiTouch->iProximityStep;//Proximity step + if (iZ < TheMultiTouch->iZMaxRange) + { + iZ = TheMultiTouch->iZMaxRange; + } + } + else + {// pressure range + iZ -= TheMultiTouch->iPressureStep;//Pressure step + } + } + } + } + + MultiTouchWndPointer(message, iX, iY, iZ, iId); + + } + +/** + * Show the cursor window when the cursor is inside the client area + */ +void DMultiMouse::ShowMousePos(HWND aHWnd) + { + RECT client = {0,0,0,0}; + if(aHWnd) + { + GetWindowRect(aHWnd, &client); + POINT pt = {iX-client.left,iY-client.top}; + iCursorWnd.SetPosition(pt); + } + iCursorWnd.Show(); + } + +void DMultiMouse::CorrectSystemMouse() + { + if (iIsPrimary) + { + POINT pos; + if (GetCursorPos(&pos)) // if failed, pos contains garbage. + { + iX = pos.x; + iY = pos.y; + } + } + else + { + SetCursorPos(iPrimary->iX,iPrimary->iY); + } + } + +/** + * a static function to check how many mice are connected +*/ +bool DMultiTouch::Init() + { + HMODULE hModule = GetModuleHandleA("user32.dll"); + if(hModule == NULL) + return FALSE; + + OSVERSIONINFO osvi; + ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + + GetVersionEx(&osvi); + // Check for Win 2K or higher version + if (osvi.dwMajorVersion < 5) + { + return FALSE; + } + + // Not supported on Win2K + if ((osvi.dwMajorVersion == 5) && (osvi.dwMinorVersion == 0)) + { + return FALSE; + } + + pfnRegisterRawInputDevices = (TYPEOF_RegisterRawInputDevices)GetProcAddress(hModule, "RegisterRawInputDevices"); + pfnGetRawInputData = (TYPEOF_GetRawInputData)GetProcAddress(hModule, "GetRawInputData"); + pfnGetRawInputDeviceList = (TYPEOF_GetRawInputDeviceList)GetProcAddress(hModule, "GetRawInputDeviceList"); + + if((pfnRegisterRawInputDevices == NULL) || (pfnGetRawInputData == NULL) || (pfnGetRawInputDeviceList == NULL)) + { + return FALSE; + } + + UINT nDevices; + + if (pfnGetRawInputDeviceList(NULL, &nDevices, sizeof(RAWINPUTDEVICELIST)) != 0) + { + return FALSE; + } + + RAWINPUTDEVICELIST* pRawInputDeviceList = new RAWINPUTDEVICELIST[ nDevices ]; + if (!pRawInputDeviceList) + { + return FALSE; + } + + pfnGetRawInputDeviceList(pRawInputDeviceList, &nDevices, + sizeof(RAWINPUTDEVICELIST)); + + + for (UINT i=0; i