bool CUnixEventEmitter::processMessage (XEvent &event, CEventServer *server)
{
	if (!server)
		server=&_InternalServer;

	XWindowAttributes xwa;
	XGetWindowAttributes (_dpy, _win, &xwa);

	switch (event.type)
	{
	case ButtonPress:
	{
		//nlinfo("%d %d %d", event.xbutton.button, event.xbutton.x, event.xbutton.y);
		float fX = (float) event.xbutton.x / (float) xwa.width;
		float fY = 1.0f - (float) event.xbutton.y / (float) xwa.height;
		TMouseButton button=getMouseButton(event.xbutton.state);
		switch(event.xbutton.button)
		{
		case Button1:
			server->postEvent(new CEventMouseDown(fX, fY, (TMouseButton)(leftButton|(button&~(leftButton|middleButton|rightButton))), this));
			break;
		case Button2:
			server->postEvent(new CEventMouseDown(fX, fY, (TMouseButton)(middleButton|(button&~(leftButton|middleButton|rightButton))), this));
			break;
		case Button3:
			server->postEvent(new CEventMouseDown(fX, fY, (TMouseButton)(rightButton|(button&~(leftButton|middleButton|rightButton))), this));
			break;
		case Button4:
			server->postEvent(new CEventMouseWheel(fX, fY, button, true, this));
			break;
		case Button5:
			server->postEvent(new CEventMouseWheel(fX, fY, button, false, this));
			break;
		}
		break;
	}
	case ButtonRelease:
	{
		//nlinfo("%d %d %d", event.xbutton.button, event.xbutton.x, event.xbutton.y);
		float fX = (float) event.xbutton.x / (float) xwa.width;
		float fY = 1.0f - (float) event.xbutton.y / (float) xwa.height;
		switch(event.xbutton.button)
		{
		case Button1:
			server->postEvent(new CEventMouseUp(fX, fY, leftButton, this));
			break;
		case Button2:
			server->postEvent(new CEventMouseUp(fX, fY, middleButton, this));
			break;
		case Button3:
			server->postEvent(new CEventMouseUp(fX, fY, rightButton, this));
			break;
		}
		break;
	}
	case MotionNotify:
	{
		TMouseButton button=getMouseButton (event.xbutton.state);

		// if raw mode should be emulated
		if(_emulateRawMode)
		{
			// when we just wrapped back the pointer to 0.5 / 0.5, ignore event
			if(event.xbutton.x == xwa.width / 2 && event.xbutton.y == xwa.height / 2)
				break;

			// post a CGDMouseMove with the movement delta to the event server
			server->postEvent(
				new CGDMouseMove(this, NULL /* no mouse device */,
					event.xbutton.x - (xwa.width / 2),
					(xwa.height / 2) - event.xbutton.y));

			// move the pointer back to the center of the window
			XWarpPointer(_dpy, None, _win, None, None, None, None,
				(xwa.width / 2), (xwa.height / 2));
		}
		// if in normal mouse mode
		else
		{
			// get the relative mouse position
			float fX = (float) event.xbutton.x / (float) xwa.width;
			float fY = 1.0f - (float) event.xbutton.y / (float) xwa.height;

			// post a normal mouse move event to the event server
			server->postEvent (new CEventMouseMove (fX, fY, button, this));
		}
		break;
	}
	case KeyPress:
	{
		// save keycode because XFilterEvent could set it to 0
		uint keyCode = event.xkey.keycode;
		KeySym k;
		static char Text[256];
		int c = 0;

		// check if event is filtered
		bool filtered = XFilterEvent(&event, _win);

		// if key event is filtered, we shouldn't use XLookupString to retrieve KeySym
		if (!filtered)
		{
			Status status = XLookupNone;

#ifdef X_HAVE_UTF8_STRING
			if (_ic)
				c = Xutf8LookupString(_ic, &event.xkey, Text, sizeof(Text), &k, &status);
#endif

			if (status == XLookupNone)
				c = XLookupString(&event.xkey, Text, sizeof(Text), &k, NULL);
		}
		else
		{
			k = XKeycodeToKeysym(_dpy, keyCode, 0);
		}

		// send CEventKeyDown event only if keyCode is defined
		if (keyCode)
		{
			TKey key = getKeyFromKeySym(k);
			if(key == KeyNOKEY)
				key = getKeyFromKeycode(keyCode);

			// search for key in map
			std::map<TKey, bool>::const_iterator it = _PressedKeys.find(key);

			// if key is not found or value is false, that's the first time
			bool firstTime = (it == _PressedKeys.end()) || !it->second;

			server->postEvent (new CEventKeyDown (key, getKeyButton(event.xbutton.state), firstTime, this));
			_PressedKeys[key] = true;

			// don't send a control character when deleting
			if (key == KeyDELETE)
				c = 0;
		}

		Text[c] = '\0';
		if(c>0)
		{
#ifdef X_HAVE_UTF8_STRING
			ucstring ucstr;
			ucstr.fromUtf8(Text);

			CEventChar *charEvent = new CEventChar (ucstr[0], getKeyButton(event.xbutton.state), this);

			// raw if not processed by IME
			charEvent->setRaw(keyCode != 0);

			server->postEvent (charEvent);
#else
			for (int i = 0; i < c; i++)
			{
				CEventChar *charEvent = new CEventChar ((ucchar)(unsigned char)Text[i], getKeyButton(event.xbutton.state), this);

				// raw if not processed by IME
				charEvent->setRaw(keyCode != 0);

				server->postEvent (charEvent);
			}
#endif
		}
		break;
	}
	case KeyRelease:
	{
		if (!keyRepeat(_dpy, &event))
		{
			KeySym k;
			// only need to get correct KeySym
			int c = XLookupString(&event.xkey, NULL, 0, &k, NULL);

			TKey key = getKeyFromKeySym(k);
			if(key == KeyNOKEY)
				key = getKeyFromKeycode(event.xkey.keycode);

			server->postEvent (new CEventKeyUp (key, getKeyButton(event.xbutton.state), this));
			_PressedKeys[key] = false;
		}
		break;
	}
	case SelectionRequest:
	{
		XEvent respond;
		XSelectionRequestEvent req = event.xselectionrequest;

		respond.xselection.type= SelectionNotify;
		respond.xselection.display= req.display;
		respond.xselection.requestor= req.requestor;
		respond.xselection.selection=req.selection;
		respond.xselection.target= req.target;
		respond.xselection.time = req.time;
		respond.xselection.property = req.property;

		if (req.property == None)
		{
			respond.xselection.property = req.target;
		}
		if (req.target == XA_TARGETS)
		{
			Atom targets[] =
			{
				XA_TARGETS,
				XA_STRING,
				XA_UTF8_STRING
			};

			respond.xselection.property = req.property;

			XChangeProperty(req.display, req.requestor, req.property, XA_ATOM, 32, PropModeReplace, (unsigned char *)targets, 3 /* number of element */);
		}
		else if (req.target == XA_STRING)
		{
			respond.xselection.property = req.property;
			std::string str = _CopiedString.toString();
			XChangeProperty(req.display, req.requestor, req.property, XA_STRING, 8, PropModeReplace, (const unsigned char*)str.c_str(), str.length());
		}
		else if (req.target == XA_UTF8_STRING)
		{
			respond.xselection.property = req.property;
			std::string str = _CopiedString.toUtf8();
			XChangeProperty(req.display, req.requestor, respond.xselection.property, XA_UTF8_STRING, 8, PropModeReplace, (const unsigned char*)str.c_str(), str.length());
		}
		else
		{
			// Note: Calling XGetAtomName with arbitrary value crash the client, maybe req.target have been sanitized by X11 server
			respond.xselection.property = None;
		}

		XSendEvent (_dpy, req.requestor, 0, 0, &respond);

		break;
	}
	case SelectionClear:
		_SelectionOwned = false;
		_CopiedString = "";
		break;
	case SelectionNotify:
	{
		Atom target = event.xselection.target;

		Atom actualType = 0;
		int actualFormat = 0;
		unsigned long nitems = 0, bytesLeft = 0;

		// some applications are sending ATOM and other TARGETS
		if (target == XA_TARGETS || target == XA_ATOM)
		{
			Atom *supportedTargets = NULL;

			// list NeL selection properties
			if (XGetWindowProperty(_dpy, _win, XA_NEL_SEL, 0, XMaxRequestSize(_dpy), False, AnyPropertyType, &actualType, &actualFormat, &nitems, &bytesLeft, (unsigned char**)&supportedTargets) != Success)
				return false;

			if (bytesLeft > 0)
			{
				nlwarning("Paste: Supported TARGETS list too long.");
			}

			Atom bestTarget = 0;
			sint bestTargetElect = 0;

			// Elect best type
			for (uint i=0; i < nitems; i++)
			{
				// nlwarning(" - Type=%s (%u)", XGetAtomName(_dpy, supportedTargets[i]), (uint)supportedTargets[i]);
				if (supportedTargets[i] == XA_UTF8_STRING )
				{
					if (bestTargetElect < 2)
					{
						bestTarget = XA_UTF8_STRING;
						bestTargetElect = 2;
					}
				}
				else if (supportedTargets[i] == XA_STRING )
				{
					if (bestTargetElect < 1)
					{
						bestTarget = XA_STRING;
						bestTargetElect = 1;
					}
				}
			}

			XFree(supportedTargets);

			if (!bestTargetElect)
			{
				nlwarning("Paste buffer is not a text buffer.");
				return false;
			}

			// request string conversion
			XConvertSelection(_dpy, XA_CLIPBOARD, bestTarget, XA_NEL_SEL, _win, CurrentTime);
		}
		else if (target == XA_UTF8_STRING || target == XA_STRING)
		{
			uint8 *data = NULL;

			// get selection
			if (XGetWindowProperty(_dpy, _win, XA_NEL_SEL, 0, XMaxRequestSize(_dpy), False, AnyPropertyType, &actualType, &actualFormat, &nitems, &bytesLeft, (unsigned char**)&data) != Success)
				return false;

			ucstring text;
			std::string tmpData = (const char*)data;
			XFree(data);

			// convert buffer to ucstring
			if (target == XA_UTF8_STRING)
			{
				text = ucstring::makeFromUtf8(tmpData);
			}
			else if (target == XA_STRING)
			{
				text = tmpData;
			}
			else
			{
				nlwarning("Unknow format %u", (uint)target);
			}

			// sent string event to event server
			server->postEvent (new CEventString (text, this));
		}
		else
		{
			nlwarning("Unknow target %u", (uint)target);
		}

		break;
	}
	case FocusIn:
		// keyboard focus
//		server->postEvent (new CEventSetFocus (true, this));
		if (_ic) XSetICFocus(_ic);
		break;
	case FocusOut:
		// keyboard focus
//		server->postEvent (new CEventSetFocus (false, this));
		if (_ic) XUnsetICFocus(_ic);
		break;
	case KeymapNotify:
		break;
	case MappingNotify:
		// update keymap
		XRefreshKeyboardMapping((XMappingEvent *)&event);
		break;
	case DestroyNotify:
		// XIM server has crashed
		createIM();
		break;
	case ClientMessage:
		if ((event.xclient.format == 32) && ((Atom)event.xclient.data.l[0] == XA_WM_DELETE_WINDOW))
		{
			server->postEvent(new CEventDestroyWindow(this));
		}
		break;
	default:
		//	nlinfo("UnknownEvent");
		//	XtDispatchEvent(&event);
		return false;
	}

	return true;
}
Esempio n. 2
0
bool CWinEventEmitter::processMessage (HWND hWnd, uint32 msg, WPARAM wParam, LPARAM lParam, CEventServer *server)
{
	if (!server)
		server=&_InternalServer;

	/// Process IME messages
	/*if ( _IMEEventsEnabled && (ImmIsUIMessage( ImmGetDefaultIMEWnd((HWND)_HWnd), msg, wParam, lParam) == TRUE) )
	{
		server->postEvent( new CEventIME(msg, wParam, lParam, this) );
		return true; // trap message (however DefWindowProc will still be called in some instances by the event listener)
	}*/

	switch (msg)
	{
	case WM_KEYDOWN:
	case WM_SYSKEYDOWN:
		if (_KeyboardEventsEnabled)
		{
			// Ctrl, shit or alt ?
			if ((sint)wParam==VK_MENU)
				_AltButton=true;
			if ((sint)wParam==VK_CONTROL)
				_CtrlButton=true;
			if ((sint)wParam==VK_SHIFT)
				_ShiftButton=true;

			// Post the message
			if (wParam < KeyCount)
				server->postEvent (new CEventKeyDown ((NLMISC::TKey)wParam, getKeyButton(_AltButton, _ShiftButton, _CtrlButton), (((int) lParam)&(1<<30))==0, this));
		}
		break;

	case WM_SYSKEYUP:
	case WM_KEYUP:
		if (_KeyboardEventsEnabled)
		{
			// Ctrl, shit or alt ?
			if ((int)wParam==VK_MENU)
				_AltButton=false;
			if ((int)wParam==VK_CONTROL)
				_CtrlButton=false;
			if ((int)wParam==VK_SHIFT)
				_ShiftButton=false;

			// As Print Screen button does not trigger a WM_KEYDOWN msg, simulate it here
			if ((int)wParam==VK_SNAPSHOT)
			{
				if (wParam < KeyCount)
					server->postEvent (new CEventKeyDown ((NLMISC::TKey)wParam, getKeyButton(_AltButton, _ShiftButton, _CtrlButton), true, this));
			}

			// Post the message
			if (wParam < KeyCount)
				server->postEvent (new CEventKeyUp ((NLMISC::TKey)wParam, getKeyButton(_AltButton, _ShiftButton, _CtrlButton), this));
		}
		break;
	case WM_CHAR:
		if (_KeyboardEventsEnabled)
		{
			//if (wParam < KeyCount)
			//nlinfo("WM_CHAR with %u", wParam);
			server->postEvent (new CEventChar ((ucchar)wParam, getKeyButton(_AltButton, _ShiftButton, _CtrlButton), this));
		}
		break;
	/*case WM_IME_CHAR:
		if (_KeyboardEventsEnabled && _IMEEventsEnabled)
		{
			server->postEvent (new CEventChar ((ucchar)wParam, getKeyButton(_AltButton, _ShiftButton, _CtrlButton), this));
		}
		break;*/
	case WM_ACTIVATE:
		if (WA_INACTIVE==LOWORD(wParam))
			server->postEvent (new CEventActivate (false, this));
		else
		{
			// Reset flags state
			resetButtonFlagState ();

			// Post the message
			server->postEvent (new CEventActivate (true, this));
		}
		break;
	case WM_KILLFOCUS:
		server->postEvent (new CEventSetFocus (false, this));
		break;
	case WM_SETFOCUS:
		// Reset flags state
		resetButtonFlagState ();

		// Post the message
		server->postEvent (new CEventSetFocus (true, this));
		break;
	case WM_MOUSEMOVE:
	case WM_RBUTTONDOWN:
	case WM_LBUTTONDOWN:
	case WM_MBUTTONDOWN:
	case WM_RBUTTONUP:
	case WM_LBUTTONUP:
	case WM_MBUTTONUP:
	case WM_RBUTTONDBLCLK:
	case WM_MBUTTONDBLCLK:
	case WM_LBUTTONDBLCLK:
		{
			if (_MouseEventsEnabled)
			{
				// MSWindows coordinates to NeL window coordinate
				float fX, fY;
				RECT client;

				float xPos = (float)GET_X_LPARAM(lParam);
				float yPos = (float)GET_Y_LPARAM(lParam);

				GetClientRect (hWnd, &client);
				fX=xPos/(float)(client.right-client.left);
				fY=1.f-yPos/(float)(client.bottom-client.top);

				// buttons
				TMouseButton button=getButtons();

				// Reswitch
				switch (msg)
				{
				case WM_MOUSEMOVE:
					server->postEvent (new CEventMouseMove (fX, fY, button, this));
					break;

				case WM_RBUTTONDOWN:
					_MouseButtons[1] = true;
					server->postEvent (new CEventMouseDown (fX, fY, (TMouseButton)(rightButton|(button&~(leftButton|middleButton|rightButton))), this));
					break;
				case WM_MBUTTONDOWN:
					_MouseButtons[2] = true;
					server->postEvent (new CEventMouseDown (fX, fY, (TMouseButton)(middleButton|(button&~(leftButton|middleButton|rightButton))), this));
					break;
				case WM_LBUTTONDOWN:
					_MouseButtons[0] = true;
					server->postEvent (new CEventMouseDown (fX, fY, (TMouseButton)(leftButton|(button&~(leftButton|middleButton|rightButton))), this));
					break;

				case WM_RBUTTONUP:
					_MouseButtons[1] = false;
					server->postEvent (new CEventMouseUp (fX, fY, (TMouseButton)(rightButton|(button&~(leftButton|middleButton|rightButton))), this));
					break;
				case WM_MBUTTONUP:
					_MouseButtons[2] = false;
					server->postEvent (new CEventMouseUp (fX, fY, (TMouseButton)(middleButton|(button&~(leftButton|middleButton|rightButton))), this));
					break;
				case WM_LBUTTONUP:
					_MouseButtons[0] = false;
					server->postEvent (new CEventMouseUp (fX, fY, (TMouseButton)(leftButton|(button&~(leftButton|middleButton|rightButton))), this));
					break;

				case WM_RBUTTONDBLCLK:
					server->postEvent (new CEventMouseDblClk (fX, fY, (TMouseButton)(rightButton|(button&~(leftButton|middleButton|rightButton))), this));
					break;
				case WM_MBUTTONDBLCLK:
					server->postEvent (new CEventMouseDblClk (fX, fY, (TMouseButton)(middleButton|(button&~(leftButton|middleButton|rightButton))), this));
					break;
				case WM_LBUTTONDBLCLK:
					server->postEvent (new CEventMouseDblClk (fX, fY, (TMouseButton)(leftButton|(button&~(leftButton|middleButton|rightButton))), this));
					break;
				}
				break;
			}
			break;
		}
	case WM_DESTROY:
		server->postEvent (new CEventDestroyWindow (this));
		break;
	case WM_DISPLAYCHANGE:
		server->postEvent (new CEventDisplayChange (LOWORD(lParam), HIWORD(lParam), (uint)wParam, this));
		break;
	case WM_MOUSEWHEEL:
		if (_MouseEventsEnabled)
		{
			// MSWindows coordinates to NeL window coordinate
			float fX, fY;
			RECT client;
			GetClientRect (hWnd, &client);
			if (client.right-client.left > 0)
				fX=(float)LOWORD(lParam)/(float)(client.right-client.left);
			else
				fX=0;
			if (client.bottom-client.top > 0)
				fY=1.f-(float)HIWORD(lParam)/(float)(client.bottom-client.top);
			else
				fY=0;

			// buttons
			TMouseButton button=getButtons();

			server->postEvent (new CEventMouseWheel (fX, fY, button, (short) HIWORD(wParam)>=0, this));
			break;
		}
	case WM_IME_SETCONTEXT:
	case WM_IME_STARTCOMPOSITION:
	case WM_IME_COMPOSITION:
	case WM_IME_ENDCOMPOSITION:
	case WM_IME_NOTIFY:
	//case WM_INPUTLANGCHANGEREQUEST:
	case WM_INPUTLANGCHANGE:
		if ( _IMEEventsEnabled )
		{
			// wParam = Specifies the character set of the new locale. 
			// lParam = Input locale identifier.
			server->postEvent( new CEventIME( msg, (uint32)wParam, (uint32)lParam, this ) );
			return true; // trap message
		}
		break;
	}
	return false;
}