예제 #1
0
GHOST_EventCursor *GHOST_SystemWin32::processCursorEvent(GHOST_TEventType type, GHOST_IWindow *Iwindow)
{
	GHOST_TInt32 x_screen, y_screen;
	GHOST_SystemWin32 *system = (GHOST_SystemWin32 *) getSystem();
	GHOST_WindowWin32 *window = (GHOST_WindowWin32 *) Iwindow;
	
	system->getCursorPosition(x_screen, y_screen);

	/* TODO: CHECK IF THIS IS A TABLET EVENT */
	bool is_tablet = false;

	if (is_tablet == false && window->getCursorGrabModeIsWarp()) {
		GHOST_TInt32 x_new = x_screen;
		GHOST_TInt32 y_new = y_screen;
		GHOST_TInt32 x_accum, y_accum;
		GHOST_Rect bounds;

		/* fallback to window bounds */
		if (window->getCursorGrabBounds(bounds) == GHOST_kFailure) {
			window->getClientBounds(bounds);
		}

		/* could also clamp to screen bounds
		 * wrap with a window outside the view will fail atm  */

		bounds.wrapPoint(x_new, y_new, 2); /* offset of one incase blender is at screen bounds */

		window->getCursorGrabAccum(x_accum, y_accum);
		if (x_new != x_screen || y_new != y_screen) {
			/* when wrapping we don't need to add an event because the
			 * setCursorPosition call will cause a new event after */
			system->setCursorPosition(x_new, y_new); /* wrap */
			window->setCursorGrabAccum(x_accum + (x_screen - x_new), y_accum + (y_screen - y_new));
		}
		else {
			return new GHOST_EventCursor(system->getMilliSeconds(),
			                             GHOST_kEventCursorMove,
			                             window,
			                             x_screen + x_accum,
			                             y_screen + y_accum
			                             );
		}

	}
	else {
		return new GHOST_EventCursor(system->getMilliSeconds(),
		                             GHOST_kEventCursorMove,
		                             window,
		                             x_screen,
		                             y_screen
		                             );
	}
	return NULL;
}
예제 #2
0
GHOST_EventKey* GHOST_SystemWin32::processKeyEvent(GHOST_IWindow *window, RAWINPUT const& raw)
{
	int keyDown=0;
	char vk;
	GHOST_SystemWin32 * system = (GHOST_SystemWin32 *)getSystem();
	GHOST_TKey key = system->hardKey(window, raw, &keyDown, &vk);
	GHOST_EventKey* event;

	if (key != GHOST_kKeyUnknown) {
		char utf8_char[6] = {0} ;

		wchar_t utf16[2]={0};
		BYTE state[256];
		GetKeyboardState((PBYTE)state);  

		if(ToUnicodeEx(vk, 0, state, utf16, 2, 0, system->m_keylayout))
			WideCharToMultiByte(CP_UTF8, 0, 
									(wchar_t*)utf16, 1,
									(LPSTR) utf8_char, 5,
									NULL,NULL); else *utf8_char = 0;

		if(!keyDown) utf8_char[0] = '\0';
		
		event = new GHOST_EventKey(system->getMilliSeconds(), keyDown ? GHOST_kEventKeyDown: GHOST_kEventKeyUp, window, key, (*utf8_char & 0x80)?'?':*utf8_char, utf8_char);
		
#ifdef GHOST_DEBUG
		std::cout << ascii << std::endl;
#endif
	}
	else {
		event = 0;
	}
	return event;
}
예제 #3
0
GHOST_EventKey* GHOST_SystemWin32::processKeyEvent(GHOST_IWindow *window, RAWINPUT const& raw)
{
	int keyDown=0;
	char vk;
	GHOST_SystemWin32 * system = (GHOST_SystemWin32 *)getSystem();
	GHOST_TKey key = system->hardKey(window, raw, &keyDown, &vk);
	GHOST_EventKey* event;
	if (key != GHOST_kKeyUnknown) {
		char ascii = '\0';

		unsigned short utf16[2]={0};
		BYTE state[256];
		GetKeyboardState((PBYTE)state);

		if(ToAsciiEx(vk, 0, state, utf16, 0, system->m_keylayout))
				WideCharToMultiByte(CP_ACP, 0x00000400, 
									(wchar_t*)utf16, 1,
									(LPSTR) &ascii, 1,
									NULL,NULL);

		event = new GHOST_EventKey(system->getMilliSeconds(), keyDown ? GHOST_kEventKeyDown: GHOST_kEventKeyUp, window, key, ascii);
		
#ifdef GHOST_DEBUG
		std::cout << ascii << std::endl;
#endif
	}
	else {
		event = 0;
	}
	return event;
}
예제 #4
0
GHOST_TSuccess GHOST_SystemWin32::pushDragDropEvent(GHOST_TEventType eventType, 
		GHOST_TDragnDropTypes draggedObjectType,
		GHOST_IWindow *window,
		int mouseX, int mouseY,
		void *data)
{
	GHOST_SystemWin32 *system = ((GHOST_SystemWin32 *)getSystem());
	return system->pushEvent(new GHOST_EventDragnDrop(system->getMilliSeconds(),
	                                                  eventType,
	                                                  draggedObjectType,
	                                                  window, mouseX, mouseY, data)
	                         );
}
예제 #5
0
GHOST_EventKey *GHOST_SystemWin32::processKeyEvent(GHOST_IWindow *window, RAWINPUT const& raw)
{
	int keyDown = 0;
	char vk;
	GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem();
	GHOST_TKey key = system->hardKey(window, raw, &keyDown, &vk);
	GHOST_EventKey *event;

	if (key != GHOST_kKeyUnknown) {
		char utf8_char[6] = {0};
		char ascii = 0;

		wchar_t utf16[3] = {0};
		BYTE state[256] = {0};
		int r;
		GetKeyboardState((PBYTE)state);

		// don't call ToUnicodeEx on dead keys as it clears the buffer and so won't allow diacritical composition.
		if (MapVirtualKeyW(vk,2) != 0) {
			// todo: ToUnicodeEx can respond with up to 4 utf16 chars (only 2 here). Could be up to 24 utf8 bytes.
			if ((r = ToUnicodeEx(vk, raw.data.keyboard.MakeCode, state, utf16, 2, 0, system->m_keylayout))) {
				if ((r > 0 && r < 3)) {
					utf16[r] = 0;
					conv_utf_16_to_8(utf16, utf8_char, 6);
				}
				else if (r == -1) {
					utf8_char[0] = '\0';
				}
			}
		}

		if (!keyDown) {
			utf8_char[0] = '\0';
			ascii = '\0';
		}
		else {
			ascii = utf8_char[0] & 0x80 ? '?' : utf8_char[0];
		}

		event = new GHOST_EventKey(system->getMilliSeconds(), keyDown ? GHOST_kEventKeyDown : GHOST_kEventKeyUp, window, key, ascii, utf8_char);
		
#ifdef GHOST_DEBUG
		std::cout << ascii << std::endl;
#endif
	}
	else {
		event = 0;
	}
	return event;
}
예제 #6
0
LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	GHOST_Event* event = 0;
	LRESULT lResult = 0;
	GHOST_SystemWin32* system = ((GHOST_SystemWin32*)getSystem());
	GHOST_ASSERT(system, "GHOST_SystemWin32::s_wndProc(): system not initialized")

	if (hwnd) {
		GHOST_WindowWin32* window = (GHOST_WindowWin32*)::GetWindowLong(hwnd, GWL_USERDATA);
		if (window) {
			switch (msg) {
				// we need to check if new key layout has AltGr
				case WM_INPUTLANGCHANGE:
					system->handleKeyboardChange();
					break;
				////////////////////////////////////////////////////////////////////////
				// Keyboard events, processed
				////////////////////////////////////////////////////////////////////////
				case WM_KEYDOWN:
				case WM_SYSKEYDOWN:
					event = processKeyEvent(window, true, wParam, lParam);
					if (!event) {
						GHOST_PRINT("GHOST_SystemWin32::wndProc: key event ")
						GHOST_PRINT(msg)
						GHOST_PRINT(" key ignored\n")
					}
					break;

				case WM_KEYUP:
				case WM_SYSKEYUP:
					event = processKeyEvent(window, false, wParam, lParam);
					if (!event) {
						GHOST_PRINT("GHOST_SystemWin32::wndProc: key event ")
						GHOST_PRINT(msg)
						GHOST_PRINT(" key ignored\n")
					}
					break;

				////////////////////////////////////////////////////////////////////////
				// Keyboard events, ignored
				////////////////////////////////////////////////////////////////////////
				case WM_CHAR:
					/* The WM_CHAR message is posted to the window with the keyboard focus when 
					 * a WM_KEYDOWN message is translated by the TranslateMessage function. WM_CHAR 
					 * contains the character code of the key that was pressed. 
					 */
				case WM_DEADCHAR:
					/* The WM_DEADCHAR message is posted to the window with the keyboard focus when a
					 * WM_KEYUP message is translated by the TranslateMessage function. WM_DEADCHAR 
					 * specifies a character code generated by a dead key. A dead key is a key that 
					 * generates a character, such as the umlaut (double-dot), that is combined with 
					 * another character to form a composite character. For example, the umlaut-O 
					 * character (Ö) is generated by typing the dead key for the umlaut character, and
					 * then typing the O key.
					 */
				case WM_SYSDEADCHAR:
					/* The WM_SYSDEADCHAR message is sent to the window with the keyboard focus when 
					 * a WM_SYSKEYDOWN message is translated by the TranslateMessage function. 
					 * WM_SYSDEADCHAR specifies the character code of a system dead key - that is, 
					 * a dead key that is pressed while holding down the alt key. 
					 */
					break;
				////////////////////////////////////////////////////////////////////////
				// Tablet events, processed
				////////////////////////////////////////////////////////////////////////
				case WT_PACKET:
					((GHOST_WindowWin32*)window)->processWin32TabletEvent(wParam, lParam);
					break;
				case WT_CSRCHANGE:
				case WT_PROXIMITY:
					((GHOST_WindowWin32*)window)->processWin32TabletInitEvent();
					break;
				////////////////////////////////////////////////////////////////////////
				// Mouse events, processed
				////////////////////////////////////////////////////////////////////////
				case WM_LBUTTONDOWN:
					window->registerMouseClickEvent(true);
					event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskLeft);
					break;
				case WM_MBUTTONDOWN:
					window->registerMouseClickEvent(true);
					event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskMiddle);
					break;
				case WM_RBUTTONDOWN:
					window->registerMouseClickEvent(true);
					event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskRight);
					break;
				case WM_XBUTTONDOWN:
					window->registerMouseClickEvent(true);
					if ((short) HIWORD(wParam) == XBUTTON1){
						event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskButton4);
					}else if((short) HIWORD(wParam) == XBUTTON2){
						event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskButton5);
					}
					break;
				case WM_LBUTTONUP:
					window->registerMouseClickEvent(false);
					event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskLeft);
					break;
				case WM_MBUTTONUP:
					window->registerMouseClickEvent(false);
					event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskMiddle);
					break;
				case WM_RBUTTONUP:
					window->registerMouseClickEvent(false);
					event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskRight);
					break;
				case WM_XBUTTONUP:
					window->registerMouseClickEvent(false);
					if ((short) HIWORD(wParam) == XBUTTON1){
						event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskButton4);
					}else if((short) HIWORD(wParam) == XBUTTON2){
						event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskButton5);
					}
					break;
				case WM_MOUSEMOVE:
					event = processCursorEvent(GHOST_kEventCursorMove, window);
					break;
				case WM_MOUSEWHEEL:
					/* The WM_MOUSEWHEEL message is sent to the focus window 
					 * when the mouse wheel is rotated. The DefWindowProc 
					 * function propagates the message to the window's parent.
					 * There should be no internal forwarding of the message, 
					 * since DefWindowProc propagates it up the parent chain 
					 * until it finds a window that processes it.
					 */
					event = processWheelEvent(window, wParam, lParam);
					break;
				case WM_SETCURSOR:
					/* The WM_SETCURSOR message is sent to a window if the mouse causes the cursor
					 * to move within a window and mouse input is not captured.
					 * This means we have to set the cursor shape every time the mouse moves!
					 * The DefWindowProc function uses this message to set the cursor to an 
					 * arrow if it is not in the client area.
					 */
					if (LOWORD(lParam) == HTCLIENT) {
						// Load the current cursor
						window->loadCursor(window->getCursorVisibility(), window->getCursorShape());
						// Bypass call to DefWindowProc
						return 0;
					} 
					else {
						// Outside of client area show standard cursor
						window->loadCursor(true, GHOST_kStandardCursorDefault);
					}
					break;

				////////////////////////////////////////////////////////////////////////
				// Mouse events, ignored
				////////////////////////////////////////////////////////////////////////
				case WM_NCMOUSEMOVE:
					/* The WM_NCMOUSEMOVE message is posted to a window when the cursor is moved 
					 * within the nonclient area of the window. This message is posted to the window 
					 * that contains the cursor. If a window has captured the mouse, this message is not posted.
					 */
				case WM_NCHITTEST:
					/* The WM_NCHITTEST message is sent to a window when the cursor moves, or 
					 * when a mouse button is pressed or released. If the mouse is not captured, 
					 * the message is sent to the window beneath the cursor. Otherwise, the message 
					 * is sent to the window that has captured the mouse. 
					 */
					break;

				////////////////////////////////////////////////////////////////////////
				// Window events, processed
				////////////////////////////////////////////////////////////////////////
				case WM_CLOSE:
					/* The WM_CLOSE message is sent as a signal that a window or an application should terminate. */
					event = processWindowEvent(GHOST_kEventWindowClose, window);
					break;
				case WM_ACTIVATE:
					/* The WM_ACTIVATE message is sent to both the window being activated and the window being 
					 * deactivated. If the windows use the same input queue, the message is sent synchronously, 
					 * first to the window procedure of the top-level window being deactivated, then to the window
					 * procedure of the top-level window being activated. If the windows use different input queues,
					 * the message is sent asynchronously, so the window is activated immediately. 
					 */
					event = processWindowEvent(LOWORD(wParam) ? GHOST_kEventWindowActivate : GHOST_kEventWindowDeactivate, window);
					/* WARNING: Let DefWindowProc handle WM_ACTIVATE, otherwise WM_MOUSEWHEEL
					will not be dispatched to OUR active window if we minimize one of OUR windows. */
					lResult = ::DefWindowProc(hwnd, msg, wParam, lParam);
					break;
				case WM_PAINT:
					/* An application sends the WM_PAINT message when the system or another application 
					 * makes a request to paint a portion of an application's window. The message is sent
					 * when the UpdateWindow or RedrawWindow function is called, or by the DispatchMessage 
					 * function when the application obtains a WM_PAINT message by using the GetMessage or 
					 * PeekMessage function. 
					 */
					event = processWindowEvent(GHOST_kEventWindowUpdate, window);
					::ValidateRect(hwnd, NULL);
					break;
				case WM_GETMINMAXINFO:
					/* The WM_GETMINMAXINFO message is sent to a window when the size or 
					 * position of the window is about to change. An application can use 
					 * this message to override the window's default maximized size and 
					 * position, or its default minimum or maximum tracking size. 
					 */
					processMinMaxInfo((MINMAXINFO *) lParam);
					/* Let DefWindowProc handle it. */
					break;
				case WM_SIZE:
					/* The WM_SIZE message is sent to a window after its size has changed.
					 * The WM_SIZE and WM_MOVE messages are not sent if an application handles the 
					 * WM_WINDOWPOSCHANGED message without calling DefWindowProc. It is more efficient
					 * to perform any move or size change processing during the WM_WINDOWPOSCHANGED 
					 * message without calling DefWindowProc.
					 */
					event = processWindowEvent(GHOST_kEventWindowSize, window);
					break;
				case WM_CAPTURECHANGED:
					window->lostMouseCapture();
					break;
				case WM_MOVING:
					/* The WM_MOVING message is sent to a window that the user is moving. By processing 
					 * this message, an application can monitor the size and position of the drag rectangle
					 * and, if needed, change its size or position.
					 */
				case WM_MOVE:
					/* The WM_SIZE and WM_MOVE messages are not sent if an application handles the 
					 * WM_WINDOWPOSCHANGED message without calling DefWindowProc. It is more efficient
					 * to perform any move or size change processing during the WM_WINDOWPOSCHANGED 
					 * message without calling DefWindowProc. 
					 */
					event = processWindowEvent(GHOST_kEventWindowMove, window);
					break;
				////////////////////////////////////////////////////////////////////////
				// Window events, ignored
				////////////////////////////////////////////////////////////////////////
				case WM_WINDOWPOSCHANGED:
					/* The WM_WINDOWPOSCHANGED message is sent to a window whose size, position, or place
					 * in the Z order has changed as a result of a call to the SetWindowPos function or 
					 * another window-management function.
					 * The WM_SIZE and WM_MOVE messages are not sent if an application handles the 
					 * WM_WINDOWPOSCHANGED message without calling DefWindowProc. It is more efficient
					 * to perform any move or size change processing during the WM_WINDOWPOSCHANGED 
					 * message without calling DefWindowProc.
					 */
				case WM_ERASEBKGND:
					/* An application sends the WM_ERASEBKGND message when the window background must be 
					 * erased (for example, when a window is resized). The message is sent to prepare an 
					 * invalidated portion of a window for painting. 
					 */
				case WM_NCPAINT:
					/* An application sends the WM_NCPAINT message to a window when its frame must be painted. */
				case WM_NCACTIVATE:
					/* The WM_NCACTIVATE message is sent to a window when its nonclient area needs to be changed 
					 * to indicate an active or inactive state. 
					 */
				case WM_DESTROY:
					/* The WM_DESTROY message is sent when a window is being destroyed. It is sent to the window 
					 * procedure of the window being destroyed after the window is removed from the screen.	
					 * This message is sent first to the window being destroyed and then to the child windows 
					 * (if any) as they are destroyed. During the processing of the message, it can be assumed 
					 * that all child windows still exist. 
					 */
				case WM_NCDESTROY:
					/* The WM_NCDESTROY message informs a window that its nonclient area is being destroyed. The 
					 * DestroyWindow function sends the WM_NCDESTROY message to the window following the WM_DESTROY
					 * message. WM_DESTROY is used to free the allocated memory object associated with the window. 
					 */
				case WM_KILLFOCUS:
					/* The WM_KILLFOCUS message is sent to a window immediately before it loses the keyboard focus. */
				case WM_SHOWWINDOW:
					/* The WM_SHOWWINDOW message is sent to a window when the window is about to be hidden or shown. */
				case WM_WINDOWPOSCHANGING:
					/* The WM_WINDOWPOSCHANGING message is sent to a window whose size, position, or place in 
					 * the Z order is about to change as a result of a call to the SetWindowPos function or 
					 * another window-management function. 
					 */
				case WM_SETFOCUS:
					/* The WM_SETFOCUS message is sent to a window after it has gained the keyboard focus. */
				case WM_ENTERSIZEMOVE:
					/* The WM_ENTERSIZEMOVE message is sent one time to a window after it enters the moving 
					 * or sizing modal loop. The window enters the moving or sizing modal loop when the user 
					 * clicks the window's title bar or sizing border, or when the window passes the 
					 * WM_SYSCOMMAND message to the DefWindowProc function and the wParam parameter of the 
					 * message specifies the SC_MOVE or SC_SIZE value. The operation is complete when 
					 * DefWindowProc returns. 
					 */
					break;
					
				////////////////////////////////////////////////////////////////////////
				// Other events
				////////////////////////////////////////////////////////////////////////
				case WM_GETTEXT:
					/* An application sends a WM_GETTEXT message to copy the text that 
					 * corresponds to a window into a buffer provided by the caller. 
					 */
				case WM_ACTIVATEAPP:
					/* The WM_ACTIVATEAPP message is sent when a window belonging to a 
					 * different application than the active window is about to be activated.
					 * The message is sent to the application whose window is being activated
					 * and to the application whose window is being deactivated. 
					 */
				case WM_TIMER:
					/* The WIN32 docs say:
					 * The WM_TIMER message is posted to the installing thread's message queue
					 * when a timer expires. You can process the message by providing a WM_TIMER
					 * case in the window procedure. Otherwise, the default window procedure will
					 * call the TimerProc callback function specified in the call to the SetTimer
					 * function used to install the timer. 
					 *
					 * In GHOST, we let DefWindowProc call the timer callback.
					 */
					break;
				case WM_BLND_NDOF_AXIS:
					{
						GHOST_TEventNDOFData ndofdata;
						system->m_ndofManager->GHOST_NDOFGetDatas(ndofdata);
						system->m_eventManager->
							pushEvent(new GHOST_EventNDOF(
								system->getMilliSeconds(), 
								GHOST_kEventNDOFMotion, 
								window, ndofdata));
					}
					break;
				case WM_BLND_NDOF_BTN:
					{
						GHOST_TEventNDOFData ndofdata;
						system->m_ndofManager->GHOST_NDOFGetDatas(ndofdata);
						system->m_eventManager->
							pushEvent(new GHOST_EventNDOF(
								system->getMilliSeconds(), 
								GHOST_kEventNDOFButton, 
								window, ndofdata));
					}
					break;
			}
		}
		else {
			// Event found for a window before the pointer to the class has been set.
			GHOST_PRINT("GHOST_SystemWin32::wndProc: GHOST window event before creation\n")
			/* These are events we typically miss at this point:
			   WM_GETMINMAXINFO	0x24
			   WM_NCCREATE			0x81
			   WM_NCCALCSIZE		0x83
			   WM_CREATE			0x01
			   We let DefWindowProc do the work.
			*/
		}
	}