static gboolean
message_translate (ClutterBackend *backend,
		   ClutterEvent   *event,
		   const MSG      *msg,
		   gboolean       *call_def_window_proc)
{
  ClutterBackendWin32 *backend_win32;
  ClutterStageWin32   *stage_win32;
  ClutterStage        *stage;
  ClutterStageWindow  *impl;
  gboolean            res;

  backend_win32 = CLUTTER_BACKEND_WIN32 (backend);

  /* Do further processing only on events for the stage window */
  stage = clutter_win32_get_stage_from_window (msg->hwnd);

  if (stage == NULL)
    return FALSE;
  impl        = _clutter_stage_get_window (stage);
  stage_win32 = CLUTTER_STAGE_WIN32 (impl);

  event->any.stage = stage;

  res = TRUE;

  switch (msg->message)
    {
    case WM_SIZE:
      if (!stage_win32->is_foreign_win
	  /* Ignore size changes resulting from the stage being
	     minimized - otherwise the window size will be set to
	     0,0 */
	  && msg->wParam != SIZE_MINIMIZED)
	{
	  WORD new_width = LOWORD (msg->lParam);
	  WORD new_height = HIWORD (msg->lParam);
	  guint old_width, old_height;

	  clutter_actor_get_size (CLUTTER_ACTOR (stage),
				  &old_width, &old_height);

	  if (new_width != old_width || new_height != old_height)
	    clutter_actor_set_size (CLUTTER_ACTOR (stage),
				    new_width, new_height);
	}
      res = FALSE;
      break;

    case WM_SHOWWINDOW:
      if (msg->wParam)
	clutter_stage_win32_map (stage_win32);
      else
	clutter_stage_win32_unmap (stage_win32);
      res = FALSE;
      break;

    case WM_ACTIVATE:
      if (msg->wParam == WA_INACTIVE)
	{
	  if (stage_win32->state & CLUTTER_STAGE_STATE_ACTIVATED)
	    {
	      stage_win32->state &= ~CLUTTER_STAGE_STATE_ACTIVATED;

	      event->type = CLUTTER_STAGE_STATE;
	      event->stage_state.changed_mask = CLUTTER_STAGE_STATE_ACTIVATED;
	      event->stage_state.new_state = stage_win32->state;
	    }
	  else
	    res = FALSE;
	  break;
	}
      else
	{
	  if (!(stage_win32->state & CLUTTER_STAGE_STATE_ACTIVATED))
	    {
	      stage_win32->state |= CLUTTER_STAGE_STATE_ACTIVATED;

	      event->type = CLUTTER_STAGE_STATE;
	      event->stage_state.changed_mask = CLUTTER_STAGE_STATE_ACTIVATED;
	      event->stage_state.new_state = stage_win32->state;
	    }
	  else
	    res = FALSE;
	}
      break;

    case WM_PAINT:
      CLUTTER_NOTE (MULTISTAGE, "expose for stage:%p, redrawing", stage);
      clutter_redraw (stage);
      res = FALSE;
      break;

    case WM_DESTROY:
      CLUTTER_NOTE (EVENT, "WM_DESTROY");
      event->type = CLUTTER_DESTROY_NOTIFY;
      break;

    case WM_CLOSE:
      CLUTTER_NOTE (EVENT, "WM_CLOSE");
      event->type = CLUTTER_DELETE;
      /* The default window proc will destroy the window so we want to
	 prevent this to allow applications to optionally destroy the
	 window themselves */
      if (call_def_window_proc)
	*call_def_window_proc = FALSE;
      break;

    case WM_LBUTTONDOWN:
      make_button_event (msg, event, 1, 1, FALSE);
      break;

    case WM_MBUTTONDOWN:
      make_button_event (msg, event, 2, 1, FALSE);
      break;

    case WM_RBUTTONDOWN:
      make_button_event (msg, event, 3, 1, FALSE);
      break;

    case WM_LBUTTONUP:
      make_button_event (msg, event, 1, 1, TRUE);
      break;

    case WM_MBUTTONUP:
      make_button_event (msg, event, 2, 1, TRUE);
      break;

    case WM_RBUTTONUP:
      make_button_event (msg, event, 3, 1, TRUE);
      break;

    case WM_LBUTTONDBLCLK:
      make_button_event (msg, event, 1, 2, FALSE);
      break;

    case WM_MBUTTONDBLCLK:
      make_button_event (msg, event, 2, 2, FALSE);
      break;

    case WM_RBUTTONDBLCLK:
      make_button_event (msg, event, 3, 2, FALSE);
      break;

    case WM_MOUSEWHEEL:
      stage_win32->scroll_pos += (SHORT) HIWORD (msg->wParam);

      event->type = CLUTTER_SCROLL;
      event->scroll.time = msg->time;
      event->scroll.modifier_state
	= get_modifier_state (LOWORD (msg->wParam));

      /* conversion to window coordinates is required */
      {
	POINT pt = { GET_X_LPARAM (msg->lParam), GET_Y_LPARAM (msg->lParam) };
	ScreenToClient (msg->hwnd, &pt);
	event->scroll.x = pt.x;
	event->scroll.y = pt.y;
      }

      if (stage_win32->scroll_pos >= WHEEL_DELTA)
	{
	  event->scroll.direction = CLUTTER_SCROLL_UP;
	  stage_win32->scroll_pos -= WHEEL_DELTA;
	}
      else if (stage_win32->scroll_pos <= -WHEEL_DELTA)
	{
	  event->scroll.direction = CLUTTER_SCROLL_DOWN;
	  stage_win32->scroll_pos += WHEEL_DELTA;
	}
      else
	res = FALSE;
      break;

    case WM_MOUSEMOVE:
      event->type = CLUTTER_MOTION;
      event->motion.time = msg->time;
      event->motion.x = GET_X_LPARAM (msg->lParam);
      event->motion.y = GET_Y_LPARAM (msg->lParam);
      event->motion.modifier_state = get_modifier_state (msg->wParam);
      break;

    case WM_KEYDOWN:
    case WM_KEYUP:
    case WM_SYSKEYDOWN:
    case WM_SYSKEYUP:
      {
	int scan_code = (msg->lParam >> 16) & 0xff;
	int min = 0, max = CLUTTER_WIN32_KEY_MAP_SIZE, mid;
	BYTE key_states[256];

	/* Get the keyboard modifier states. GetKeyboardState
	   conveniently gets the key state that was current when the
	   last keyboard message read was generated */
	GetKeyboardState(key_states);

	/* Binary chop to check if we have a direct mapping for this
	   key code */
	while (min < max)
	  {
	    mid = (min + max) / 2;
	    if (clutter_win32_key_map[mid].win_sym == msg->wParam)
	      {
		event->key.keyval = clutter_win32_key_map[mid].clutter_sym;
		event->key.unicode_value = 0;
		break;
	      }
	    else if (clutter_win32_key_map[mid].win_sym < msg->wParam)
	      min = mid + 1;
	    else
	      max = mid;
	  }

	/* If we don't have a direct mapping then try getting the
	   unicode value of the key sym */
	if (min >= max)
	  {
	    WCHAR ch;
	    BYTE shift_state[256];

	    /* Translate to a Unicode value, but only take into
	       account the shift key. That way Ctrl+Shift+C will
	       generate a capital C virtual key code with a zero
	       unicode value for example */
	    memset (shift_state, 0, 256);
	    shift_state[VK_SHIFT] = key_states[VK_SHIFT];
	    shift_state[VK_LSHIFT] = key_states[VK_LSHIFT];
	    shift_state[VK_RSHIFT] = key_states[VK_RSHIFT];
	    shift_state[VK_CAPITAL] = key_states[VK_CAPITAL];

	    if (ToUnicode (msg->wParam, scan_code,
			   shift_state, &ch, 1, 0) == 1
		/* The codes in this range directly match the Latin 1
		   codes so we can just use the Unicode value as the
		   key sym */
		&& ch >= 0x20 && ch <= 0xff)
	      event->key.keyval = ch;
	    else
	      /* Otherwise we don't know what the key means but the
		 application might be able to do something with the
		 scan code so we might as well still generate the
		 event */
	      event->key.keyval = CLUTTER_VoidSymbol;

	    /* Get the unicode value of the keypress again using the
	       full modifier state */
	    if (ToUnicode (msg->wParam, scan_code,
			   key_states, &ch, 1, 0) == 1)
		event->key.unicode_value = ch;
	    else
		event->key.unicode_value = 0;
	  }

	event->key.type = msg->message == WM_KEYDOWN
	  || msg->message == WM_SYSKEYDOWN
	  ? CLUTTER_KEY_PRESS : CLUTTER_KEY_RELEASE;
	event->key.time = msg->time;
	event->key.modifier_state = get_key_modifier_state (key_states);
	event->key.hardware_keycode = scan_code;
      }
      break;

    case WM_GETMINMAXINFO:
      {
	MINMAXINFO *min_max_info = (MINMAXINFO *) msg->lParam;
	_clutter_stage_win32_get_min_max_info (stage_win32, min_max_info);
	if (call_def_window_proc)
	  *call_def_window_proc = FALSE;
      }
      break;

    default:
      /* ignore every other message */
      res = FALSE;
      break;
    }

  return res;
}
Beispiel #2
0
void OS_X11::process_xevents() {

	//printf("checking events %i\n", XPending(x11_display));

	bool do_mouse_warp=false;

	while (XPending(x11_display) > 0) {
		XEvent event;
		XNextEvent(x11_display, &event);

		switch (event.type) {
		case Expose:
			Main::force_redraw();
			break;

		case NoExpose:
			minimized = true;
			break;

		case VisibilityNotify: {

			XVisibilityEvent * visibility = (XVisibilityEvent *)&event;
			minimized = (visibility->state == VisibilityFullyObscured);

		} break;

		case FocusIn:
			main_loop->notification(MainLoop::NOTIFICATION_WM_FOCUS_IN);
			if (mouse_mode==MOUSE_MODE_CAPTURED) {
				XGrabPointer(x11_display, x11_window, True,
						    ButtonPressMask | ButtonReleaseMask |
						    PointerMotionMask, GrabModeAsync, GrabModeAsync,
						    x11_window, None, CurrentTime);
			}
			break;

		case FocusOut:
			main_loop->notification(MainLoop::NOTIFICATION_WM_FOCUS_OUT);
			if (mouse_mode==MOUSE_MODE_CAPTURED) {
				//dear X11, I try, I really try, but you never work, you do whathever you want.
				XUngrabPointer(x11_display, CurrentTime);
			}
			break;

		case ConfigureNotify:
		/* call resizeGLScene only if our window-size changed */
		
			if ((event.xconfigure.width == current_videomode.width) && 
			(event.xconfigure.height == current_videomode.height))
				break;
				
			current_videomode.width=event.xconfigure.width;
			current_videomode.height=event.xconfigure.height;
			break;
		case ButtonPress:
		case ButtonRelease: {
			
			/* exit in case of a mouse button press */
			last_timestamp=event.xbutton.time;
			if (mouse_mode==MOUSE_MODE_CAPTURED) {
				event.xbutton.x=last_mouse_pos.x;
				event.xbutton.y=last_mouse_pos.y;
			}
			
			InputEvent mouse_event;
			mouse_event.ID=++event_id;
			mouse_event.type = InputEvent::MOUSE_BUTTON;
			mouse_event.device=0;
			mouse_event.mouse_button.mod = get_key_modifier_state(event.xbutton.state);
			mouse_event.mouse_button.button_mask = get_mouse_button_state(event.xbutton.state);
			mouse_event.mouse_button.x=event.xbutton.x;
			mouse_event.mouse_button.y=event.xbutton.y;
			mouse_event.mouse_button.global_x=event.xbutton.x;
			mouse_event.mouse_button.global_y=event.xbutton.y;
			mouse_event.mouse_button.button_index=event.xbutton.button;
			if (mouse_event.mouse_button.button_index==2)
				mouse_event.mouse_button.button_index=3;
			else if (mouse_event.mouse_button.button_index==3)
				mouse_event.mouse_button.button_index=2;
				
			mouse_event.mouse_button.pressed=(event.type==ButtonPress);


			if (event.type==ButtonPress && event.xbutton.button==1) {
				
				uint64_t diff = get_ticks_usec()/1000 - last_click_ms;

				if (diff<400 && Point2(last_click_pos).distance_to(Point2(event.xbutton.x,event.xbutton.y))<5) {
					
					last_click_ms=0;
					last_click_pos = Point2(-100,-100);
					mouse_event.mouse_button.doubleclick=true;					
					mouse_event.ID=++event_id;
					
				} else {
					last_click_ms+=diff;	
					last_click_pos = Point2(event.xbutton.x,event.xbutton.y);
				}
			}		

			input->parse_input_event( mouse_event);

			
		} break;	
		case MotionNotify: {
						
			
			last_timestamp=event.xmotion.time;
			
			// Motion is also simple.
			// A little hack is in order
			// to be able to send relative motion events.
			
			Point2i pos( event.xmotion.x, event.xmotion.y );

			if (mouse_mode==MOUSE_MODE_CAPTURED) {
#if 1
				Vector2 c = Point2i(current_videomode.width/2,current_videomode.height/2);
				if (pos==Point2i(current_videomode.width/2,current_videomode.height/2)) {
					//this sucks, it's a hack, etc and is a little inaccurate, etc.
					//but nothing I can do, X11 sucks.

					center=pos;
					break;
				}

				Point2i ncenter = pos;
				pos = last_mouse_pos + ( pos-center );
				center=ncenter;
				do_mouse_warp=true;
#else
				//Dear X11, thanks for making my life miserable

				center.x = current_videomode.width/2;
				center.y = current_videomode.height/2;
				pos = last_mouse_pos + ( pos-center );
				if (pos==last_mouse_pos)
					break;
				XWarpPointer(x11_display, None, x11_window,
					      0,0,0,0, (int)center.x, (int)center.y);
#endif

			}

			
			if (!last_mouse_pos_valid) {
				
				last_mouse_pos=pos;
				last_mouse_pos_valid=true;
			}
			
			Point2i rel = pos - last_mouse_pos;
			
			InputEvent motion_event;
			motion_event.ID=++event_id;
			motion_event.type=InputEvent::MOUSE_MOTION;
			motion_event.device=0;
			
			motion_event.mouse_motion.mod = get_key_modifier_state(event.xmotion.state);
			motion_event.mouse_motion.button_mask = get_mouse_button_state(event.xmotion.state);
			motion_event.mouse_motion.x=pos.x;
			motion_event.mouse_motion.y=pos.y;
			input->set_mouse_pos(pos);
			motion_event.mouse_motion.global_x=pos.x;
			motion_event.mouse_motion.global_y=pos.y;
			motion_event.mouse_motion.speed_x=input->get_mouse_speed().x;
			motion_event.mouse_motion.speed_y=input->get_mouse_speed().y;

			motion_event.mouse_motion.relative_x=rel.x;
			motion_event.mouse_motion.relative_y=rel.y;
						
			last_mouse_pos=pos;
			
			input->parse_input_event( motion_event);
			
		} break;			
		case KeyPress: 
		case KeyRelease: {

			last_timestamp=event.xkey.time;
				
			// key event is a little complex, so
			// it will be handled in it's own function.
			handle_key_event( (XKeyEvent*)&event );
		} break;			
		case SelectionRequest: {

			XSelectionRequestEvent *req;
			XEvent e, respond;
			e = event;

			req=&(e.xselectionrequest);
			if (req->target == XA_STRING || req->target == XInternAtom(x11_display, "COMPOUND_TEXT", 0) ||
				req->target == XInternAtom(x11_display, "UTF8_STRING", 0))
			{
				CharString clip = OS::get_clipboard().utf8();
				XChangeProperty (x11_display,
					req->requestor,
					req->property,
					req->target,
					8,
					PropModeReplace,
					(unsigned char*)clip.get_data(),
					clip.length());
				respond.xselection.property=req->property;
			} else if (req->target == XInternAtom(x11_display, "TARGETS", 0)) {

				Atom data[2];
				data[0] = XInternAtom(x11_display, "UTF8_STRING", 0);
				data[1] = XA_STRING;
				XChangeProperty (x11_display, req->requestor, req->property, req->target,
						 8, PropModeReplace, (unsigned char *) &data,
						 sizeof (data));
				respond.xselection.property=req->property;

			} else {
				printf ("No String %x\n",
					(int)req->target);
				respond.xselection.property= None;
			}
			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;
			XSendEvent (x11_display, req->requestor,0,0,&respond);
			XFlush (x11_display);
		} break;


		case ClientMessage:    
		
			if ((unsigned int)event.xclient.data.l[0]==(unsigned int)wm_delete)
				main_loop->notification(MainLoop::NOTIFICATION_WM_QUIT_REQUEST);
			break;
		default:
			break;
		}
	}
	
	XFlush(x11_display);

	if (do_mouse_warp) {

		XWarpPointer(x11_display, None, x11_window,
			      0,0,0,0, (int)current_videomode.width/2, (int)current_videomode.height/2);

	}
}
Beispiel #3
0
void OS_X11::process_xevents() {

	//printf("checking events %i\n", XPending(x11_display));

	do_mouse_warp=false;

	while (XPending(x11_display) > 0) {
		XEvent event;
		XNextEvent(x11_display, &event);

		switch (event.type) {
		case Expose:
			Main::force_redraw();
			break;

		case NoExpose:
			minimized = true;
			break;

		case VisibilityNotify: {
			XVisibilityEvent * visibility = (XVisibilityEvent *)&event;
			minimized = (visibility->state == VisibilityFullyObscured);
		} break;
		case LeaveNotify: {

			if (main_loop && mouse_mode!=MOUSE_MODE_CAPTURED)
				main_loop->notification(MainLoop::NOTIFICATION_WM_MOUSE_EXIT);
			if (input)
				input->set_mouse_in_window(false);

		} break;
		case EnterNotify: {

			if (main_loop && mouse_mode!=MOUSE_MODE_CAPTURED)
				main_loop->notification(MainLoop::NOTIFICATION_WM_MOUSE_ENTER);
			if (input)
				input->set_mouse_in_window(true);
		} break;
		case FocusIn:
			minimized = false;
#ifdef NEW_WM_API
			if(current_videomode.fullscreen) {
				set_wm_fullscreen(true);
			}
#endif
			main_loop->notification(MainLoop::NOTIFICATION_WM_FOCUS_IN);
			if (mouse_mode==MOUSE_MODE_CAPTURED) {
				XGrabPointer(x11_display, x11_window, True,
						    ButtonPressMask | ButtonReleaseMask |
						    PointerMotionMask, GrabModeAsync, GrabModeAsync,
						    x11_window, None, CurrentTime);
			}
			break;

		case FocusOut:
#ifdef NEW_WM_API
			if(current_videomode.fullscreen) {
				set_wm_fullscreen(false);
				set_window_minimized(true);
			}
#endif
			main_loop->notification(MainLoop::NOTIFICATION_WM_FOCUS_OUT);
			if (mouse_mode==MOUSE_MODE_CAPTURED) {
				//dear X11, I try, I really try, but you never work, you do whathever you want.
				XUngrabPointer(x11_display, CurrentTime);
			}
			break;

		case ConfigureNotify:
		/* call resizeGLScene only if our window-size changed */

			if ((event.xconfigure.width == current_videomode.width) &&
			(event.xconfigure.height == current_videomode.height))
				break;

			current_videomode.width=event.xconfigure.width;
			current_videomode.height=event.xconfigure.height;
			break;
		case ButtonPress:
		case ButtonRelease: {

			/* exit in case of a mouse button press */
			last_timestamp=event.xbutton.time;
			if (mouse_mode==MOUSE_MODE_CAPTURED) {
				event.xbutton.x=last_mouse_pos.x;
				event.xbutton.y=last_mouse_pos.y;
			}

			InputEvent mouse_event;
			mouse_event.ID=++event_id;
			mouse_event.type = InputEvent::MOUSE_BUTTON;
			mouse_event.device=0;
			mouse_event.mouse_button.mod = get_key_modifier_state(event.xbutton.state);
			mouse_event.mouse_button.button_mask = get_mouse_button_state(event.xbutton.state);
			mouse_event.mouse_button.x=event.xbutton.x;
			mouse_event.mouse_button.y=event.xbutton.y;
			mouse_event.mouse_button.global_x=event.xbutton.x;
			mouse_event.mouse_button.global_y=event.xbutton.y;
			mouse_event.mouse_button.button_index=event.xbutton.button;
			if (mouse_event.mouse_button.button_index==2)
				mouse_event.mouse_button.button_index=3;
			else if (mouse_event.mouse_button.button_index==3)
				mouse_event.mouse_button.button_index=2;

			mouse_event.mouse_button.pressed=(event.type==ButtonPress);


			if (event.type==ButtonPress && event.xbutton.button==1) {

				uint64_t diff = get_ticks_usec()/1000 - last_click_ms;

				if (diff<400 && Point2(last_click_pos).distance_to(Point2(event.xbutton.x,event.xbutton.y))<5) {

					last_click_ms=0;
					last_click_pos = Point2(-100,-100);
					mouse_event.mouse_button.doubleclick=true;
					mouse_event.ID=++event_id;

				} else {
					last_click_ms+=diff;
					last_click_pos = Point2(event.xbutton.x,event.xbutton.y);
				}
			}

			input->parse_input_event( mouse_event);


		} break;
		case MotionNotify: {

			// F**K YOU X11 API YOU SERIOUSLY GROSS ME OUT
			// YOU ARE AS GROSS AS LOOKING AT A PUTRID PILE
			// OF POOP STICKING OUT OF A CLOGGED TOILET
			// HOW THE F**K I AM SUPPOSED TO KNOW WHICH ONE
			// OF THE MOTION NOTIFY EVENTS IS THE ONE GENERATED
			// BY WARPING THE MOUSE POINTER?
			// YOU ARE FORCING ME TO FILTER ONE BY ONE TO FIND IT
			// PLEASE DO ME A FAVOR AND DIE DROWNED IN A FECAL
			// MOUNTAIN BECAUSE THAT'S WHERE YOU BELONG.


			while(true) {
				if (mouse_mode==MOUSE_MODE_CAPTURED && event.xmotion.x==current_videomode.width/2 && event.xmotion.y==current_videomode.height/2) {
					//this is likely the warp event since it was warped here
					center=Vector2(event.xmotion.x,event.xmotion.y);
					break;
				}

				if (XPending(x11_display) > 0) {
					XEvent tevent;
					XPeekEvent(x11_display, &tevent);
					if (tevent.type==MotionNotify) {
						XNextEvent(x11_display,&event);
					} else {
						break;
					}
				} else {
					break;
				}
			}

			last_timestamp=event.xmotion.time;

			// Motion is also simple.
			// A little hack is in order
			// to be able to send relative motion events.
			Point2i pos( event.xmotion.x, event.xmotion.y );

			if (mouse_mode==MOUSE_MODE_CAPTURED) {
#if 1
				//Vector2 c = Point2i(current_videomode.width/2,current_videomode.height/2);
				if (pos==Point2i(current_videomode.width/2,current_videomode.height/2)) {
					//this sucks, it's a hack, etc and is a little inaccurate, etc.
					//but nothing I can do, X11 sucks.

					center=pos;
					break;
				}

				Point2i new_center = pos;
				pos = last_mouse_pos + ( pos - center );
				center=new_center;
				do_mouse_warp=true;
#else
				//Dear X11, thanks for making my life miserable

				center.x = current_videomode.width/2;
				center.y = current_videomode.height/2;
				pos = last_mouse_pos + ( pos-center );
				if (pos==last_mouse_pos)
					break;
				XWarpPointer(x11_display, None, x11_window,
					      0,0,0,0, (int)center.x, (int)center.y);
#endif
			}

			if (!last_mouse_pos_valid) {

				last_mouse_pos=pos;
				last_mouse_pos_valid=true;
			}

			Point2i rel = pos - last_mouse_pos;

#ifdef NEW_WM_API
			if (mouse_mode==MOUSE_MODE_CAPTURED) {
				pos.x = current_videomode.width / 2;
				pos.y = current_videomode.height / 2;
			}
#endif

			InputEvent motion_event;
			motion_event.ID=++event_id;
			motion_event.type=InputEvent::MOUSE_MOTION;
			motion_event.device=0;

			motion_event.mouse_motion.mod = get_key_modifier_state(event.xmotion.state);
			motion_event.mouse_motion.button_mask = get_mouse_button_state(event.xmotion.state);
			motion_event.mouse_motion.x=pos.x;
			motion_event.mouse_motion.y=pos.y;
			input->set_mouse_pos(pos);
			motion_event.mouse_motion.global_x=pos.x;
			motion_event.mouse_motion.global_y=pos.y;
			motion_event.mouse_motion.speed_x=input->get_mouse_speed().x;
			motion_event.mouse_motion.speed_y=input->get_mouse_speed().y;

			motion_event.mouse_motion.relative_x=rel.x;
			motion_event.mouse_motion.relative_y=rel.y;

			last_mouse_pos=pos;

			// printf("rel: %d,%d\n", rel.x, rel.y );

			input->parse_input_event( motion_event);

		} break;
		case KeyPress:
		case KeyRelease: {

			last_timestamp=event.xkey.time;

			// key event is a little complex, so
			// it will be handled in it's own function.
			handle_key_event( (XKeyEvent*)&event );
		} break;
		case SelectionRequest: {

			XSelectionRequestEvent *req;
			XEvent e, respond;
			e = event;

			req=&(e.xselectionrequest);
			if (req->target == XA_STRING || req->target == XInternAtom(x11_display, "COMPOUND_TEXT", 0) ||
				req->target == XInternAtom(x11_display, "UTF8_STRING", 0))
			{
				CharString clip = OS::get_clipboard().utf8();
				XChangeProperty (x11_display,
					req->requestor,
					req->property,
					req->target,
					8,
					PropModeReplace,
					(unsigned char*)clip.get_data(),
					clip.length());
				respond.xselection.property=req->property;
			} else if (req->target == XInternAtom(x11_display, "TARGETS", 0)) {

				Atom data[2];
				data[0] = XInternAtom(x11_display, "UTF8_STRING", 0);
				data[1] = XA_STRING;
				XChangeProperty (x11_display, req->requestor, req->property, req->target,
						 8, PropModeReplace, (unsigned char *) &data,
						 sizeof (data));
				respond.xselection.property=req->property;

			} else {
				printf ("No String %x\n",
					(int)req->target);
				respond.xselection.property= None;
			}
			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;
			XSendEvent (x11_display, req->requestor,0,0,&respond);
			XFlush (x11_display);
		} break;


		case ClientMessage:

			if ((unsigned int)event.xclient.data.l[0]==(unsigned int)wm_delete)
				main_loop->notification(MainLoop::NOTIFICATION_WM_QUIT_REQUEST);
			break;
		default:
			break;
		}
	}

	XFlush(x11_display);

	if (do_mouse_warp) {

		XWarpPointer(x11_display, None, x11_window,
		 	      0,0,0,0, (int)current_videomode.width/2, (int)current_videomode.height/2);

		/*
		Window root, child;
		int root_x, root_y;
		int win_x, win_y;
		unsigned int mask;
		XQueryPointer( x11_display, x11_window, &root, &child, &root_x, &root_y, &win_x, &win_y, &mask );

		printf("Root: %d,%d\n", root_x, root_y);
		printf("Win: %d,%d\n", win_x, win_y);
		*/
	}
}
Beispiel #4
0
void OS_X11::handle_key_event(XKeyEvent *p_event, bool p_echo) {

			
	// X11 functions don't know what const is
	XKeyEvent *xkeyevent = p_event;
	
	// This code was pretty difficult to write.
	// The docs stink and every toolkit seems to
	// do it in a different way. 
	
	/* Phase 1, obtain a proper keysym */
	
	// This was also very difficult to figure out.
	// You'd expect you could just use Keysym provided by
	// XKeycodeToKeysym to obtain internationalized 
	// input.. WRONG!! 
	// you must use XLookupString (???) which not only wastes
	// cycles generating an unnecesary string, but also
	// still works in half the cases. (won't handle deadkeys)
	// For more complex input methods (deadkeys and more advanced)
	// you have to use XmbLookupString (??).
	// So.. then you have to chosse which of both results
	// you want to keep.
	// This is a real bizarreness and cpu waster.
		
	KeySym keysym_keycode=0; // keysym used to find a keycode
	KeySym keysym_unicode=0; // keysym used to find unicode
					
	int nbytes=0; // bytes the string takes
						 
	// XLookupString returns keysyms usable as nice scancodes/
	char str[256+1];
	nbytes=XLookupString(xkeyevent, str, 256, &keysym_keycode, NULL);
						 
 	// Meanwhile, XLookupString returns keysyms useful for unicode.
	
	
	if (!xmbstring) {
		// keep a temporary buffer for the string
		xmbstring=(char*)memalloc(sizeof(char)*8);
		xmblen=8;
	}			 
	
	if (xkeyevent->type == KeyPress && xic) {

		Status status;
		do {
			
			int mnbytes = XmbLookupString (xic, xkeyevent, xmbstring, xmblen - 1, &keysym_unicode, &status);
			xmbstring[mnbytes] = '\0';

			if (status == XBufferOverflow) {
				xmblen = mnbytes + 1;
				xmbstring = (char*)memrealloc (xmbstring, xmblen);
			} 
		} while (status == XBufferOverflow);
	} 		

	
	/* Phase 2, obtain a pigui keycode from the keysym */
	
	// KeyMappingX11 just translated the X11 keysym to a PIGUI
	// keysym, so it works in all platforms the same.

	unsigned int keycode = KeyMappingX11::get_keycode(keysym_keycode);
	
	/* Phase 3, obtain an unicode character from the keysym */
	
	// KeyMappingX11 also translates keysym to unicode.
	// It does a binary search on a table to translate
	// most properly. 
	//print_line("keysym_unicode: "+rtos(keysym_unicode));
	unsigned int unicode = keysym_unicode>0? KeyMappingX11::get_unicode_from_keysym(keysym_unicode):0;
	

	/* Phase 4, determine if event must be filtered */
	
	// This seems to be a side-effect of using XIM.
	// XEventFilter looks like a core X11 funciton,
	// but it's actually just used to see if we must
	// ignore a deadkey, or events XIM determines
	// must not reach the actual gui.
	// Guess it was a design problem of the extension

	bool keypress = xkeyevent->type == KeyPress;
	
	if (xkeyevent->type == KeyPress && xic) {
                if (XFilterEvent((XEvent*)xkeyevent, x11_window))
                	return;  
	}
	
	if (keycode==0 && unicode==0)
		return;

	/* Phase 5, determine modifier mask */
		
	// No problems here, except I had no way to
	// know Mod1 was ALT and Mod4 was META (applekey/winkey)
	// just tried Mods until i found them.

	//print_line("mod1: "+itos(xkeyevent->state&Mod1Mask)+" mod 5: "+itos(xkeyevent->state&Mod5Mask));
	
	InputModifierState state = get_key_modifier_state(xkeyevent->state);
	
	/* Phase 6, determine echo character */
	
	// Echo characters in X11 are a keyrelease and a keypress
	// one after the other with the (almot) same timestamp.
	// To detect them, i use XPeekEvent and check that their
	// difference in time is below a treshold.
	

	if (xkeyevent->type != KeyPress) {
				
		// make sure there are events pending,
		// so this call won't block.
		if (XPending(x11_display)>0) {
			XEvent peek_event;
			XPeekEvent(x11_display, &peek_event);
			
			// I'm using a treshold of 5 msecs, 
			// since sometimes there seems to be a little
			// jitter. I'm still not convinced that all this approach
			// is correct, but the xorg developers are
			// not very helpful today.
			
			::Time tresh=ABS(peek_event.xkey.time-xkeyevent->time);
			if (peek_event.type == KeyPress && tresh<5 ) {
				KeySym rk;
				nbytes=XLookupString((XKeyEvent*)&peek_event, str, 256, &rk, NULL);
				if (rk==keysym_keycode) {
					XEvent event;
					XNextEvent(x11_display, &event); //erase next event
					handle_key_event( (XKeyEvent*)&event,true );
					return; //ignore current, echo next
				}
			}
				
			// use the time from peek_event so it always works
		}
	
		// save the time to check for echo when keypress happens		
	}
	
	
	/* Phase 7, send event to Window */
	
	InputEvent event;
	event.ID=++event_id;
	event.type = InputEvent::KEY;
	event.device=0;
	event.key.mod=state;
	event.key.pressed=keypress;

	if (keycode>='a' && keycode<='z')
		keycode-='a'-'A';

	event.key.scancode=keycode;
	event.key.unicode=unicode;
	event.key.echo=p_echo;

	if (event.key.scancode==KEY_BACKTAB) {
		//make it consistent accross platforms.
		event.key.scancode=KEY_TAB;
		event.key.mod.shift=true;
	}

	//printf("key: %x\n",event.key.scancode);
	input->parse_input_event( event);

	
}
Beispiel #5
0
/**
 * clutter_win32_handle_event:
 * @msg: A pointer to a structure describing a Win32 message.
 *
 * This function processes a single Win32 message. It can be used to
 * hook into external windows message processing (for example, a GDK
 * filter function).
 *
 * If clutter_win32_disable_event_retrieval() has been called, you must
 * let this function process events to update Clutter's internal state.
 *
 * Return value: %TRUE if the message was handled entirely by Clutter
 * and no further processing (such as calling the default window
 * procedure) should take place. %FALSE is returned if is the message
 * was not handled at all or if Clutter expects processing to take
 * place.
 *
 * Since: 1.6
 */
gboolean
clutter_win32_handle_event (const MSG *msg)
{
  ClutterBackendWin32  *backend_win32;
  ClutterStageWin32    *stage_win32;
  ClutterDeviceManager *manager;
  ClutterInputDevice   *core_pointer, *core_keyboard;
  ClutterStage         *stage;
  ClutterStageWindow   *impl;
  gboolean              return_value = FALSE;

  stage = clutter_win32_get_stage_from_window (msg->hwnd);

  /* Ignore any messages for windows which we don't have a stage for */
  if (stage == NULL)
    return FALSE;

  impl = _clutter_stage_get_window (stage);
  stage_win32 = CLUTTER_STAGE_WIN32 (impl);
  backend_win32 = stage_win32->backend;

  manager = clutter_device_manager_get_default ();
  core_pointer =
    clutter_device_manager_get_core_device (manager, CLUTTER_POINTER_DEVICE);
  core_keyboard =
    clutter_device_manager_get_core_device (manager, CLUTTER_KEYBOARD_DEVICE);

  switch (msg->message)
    {
    case WM_SIZE:
      if (!stage_win32->is_foreign_win
	  /* Ignore size changes resulting from the stage being
	     minimized - otherwise the window size will be set to
	     0,0 */
	  && msg->wParam != SIZE_MINIMIZED)
	{
	  WORD new_width = LOWORD (msg->lParam);
	  WORD new_height = HIWORD (msg->lParam);
	  gfloat old_width, old_height;

	  clutter_actor_get_size (CLUTTER_ACTOR (stage),
				  &old_width, &old_height);

	  if (new_width != old_width || new_height != old_height)
	    clutter_actor_set_size (CLUTTER_ACTOR (stage),
				    new_width, new_height);
	}
      break;

    case WM_SHOWWINDOW:
      if (msg->wParam)
	clutter_stage_win32_map (stage_win32);
      else
	clutter_stage_win32_unmap (stage_win32);
      break;

    case WM_ACTIVATE:
      if (msg->wParam == WA_INACTIVE)
        {
          if (stage_win32->state & CLUTTER_STAGE_STATE_ACTIVATED)
            {
              ClutterEvent *event = clutter_event_new (CLUTTER_STAGE_STATE);

              stage_win32->state &= ~CLUTTER_STAGE_STATE_ACTIVATED;

              event->any.stage = stage;
              event->stage_state.changed_mask = CLUTTER_STAGE_STATE_ACTIVATED;
              event->stage_state.new_state = stage_win32->state;

              take_and_queue_event (event);
            }
        }
      else if (!(stage_win32->state & CLUTTER_STAGE_STATE_ACTIVATED))
        {
          ClutterEvent *event = clutter_event_new (CLUTTER_STAGE_STATE);

          stage_win32->state |= CLUTTER_STAGE_STATE_ACTIVATED;

          event->any.stage = stage;
          event->stage_state.changed_mask = CLUTTER_STAGE_STATE_ACTIVATED;
          event->stage_state.new_state = stage_win32->state;

          take_and_queue_event (event);
        }
      break;

    case WM_PAINT:
      CLUTTER_NOTE (MULTISTAGE, "expose for stage:%p, redrawing", stage);
      clutter_redraw (stage);
      break;

    case WM_DESTROY:
      {
        ClutterEvent *event = clutter_event_new (CLUTTER_DESTROY_NOTIFY);

        CLUTTER_NOTE (EVENT, "WM_DESTROY");

        event->any.stage = stage;

        take_and_queue_event (event);
      }
      break;

    case WM_CLOSE:
      {
        ClutterEvent *event = clutter_event_new (CLUTTER_DELETE);

        CLUTTER_NOTE (EVENT, "WM_CLOSE");

        event->any.stage = stage;

        take_and_queue_event (event);

        /* The default window proc will destroy the window so we want to
           prevent this to allow applications to optionally destroy the
           window themselves */
        return_value = TRUE;
      }
      break;

    case WM_LBUTTONDOWN:
      make_button_event (msg, stage, 1, 1, FALSE, core_pointer);
      break;

    case WM_MBUTTONDOWN:
      make_button_event (msg, stage, 2, 1, FALSE, core_pointer);
      break;

    case WM_RBUTTONDOWN:
      make_button_event (msg, stage, 3, 1, FALSE, core_pointer);
      break;

    case WM_LBUTTONUP:
      make_button_event (msg, stage, 1, 1, TRUE, core_pointer);
      break;

    case WM_MBUTTONUP:
      make_button_event (msg, stage, 2, 1, TRUE, core_pointer);
      break;

    case WM_RBUTTONUP:
      make_button_event (msg, stage, 3, 1, TRUE, core_pointer);
      break;

    case WM_LBUTTONDBLCLK:
      make_button_event (msg, stage, 1, 2, FALSE, core_pointer);
      break;

    case WM_MBUTTONDBLCLK:
      make_button_event (msg, stage, 2, 2, FALSE, core_pointer);
      break;

    case WM_RBUTTONDBLCLK:
      make_button_event (msg, stage, 3, 2, FALSE, core_pointer);
      break;

    case WM_MOUSEWHEEL:
      stage_win32->scroll_pos += (SHORT) HIWORD (msg->wParam);

      while (abs (stage_win32->scroll_pos) >= WHEEL_DELTA)
        {
          ClutterEvent *event = clutter_event_new (CLUTTER_SCROLL);
          POINT pt;

          event->scroll.time = msg->time;
          event->scroll.modifier_state =
            get_modifier_state (LOWORD (msg->wParam));
          event->any.stage = stage;

          clutter_event_set_device (event, core_pointer);

          /* conversion to window coordinates is required */
          pt.x = GET_X_LPARAM (msg->lParam);
          pt.y = GET_Y_LPARAM (msg->lParam);
          ScreenToClient (msg->hwnd, &pt);
          event->scroll.x = pt.x;
          event->scroll.y = pt.y;

          if (stage_win32->scroll_pos > 0)
            {
              event->scroll.direction = CLUTTER_SCROLL_UP;
              stage_win32->scroll_pos -= WHEEL_DELTA;
            }
          else
            {
              event->scroll.direction = CLUTTER_SCROLL_DOWN;
              stage_win32->scroll_pos += WHEEL_DELTA;
            }

          take_and_queue_event (event);
        }
      break;

    case WM_MOUSEMOVE:
      {
        ClutterEvent *event = clutter_event_new (CLUTTER_MOTION);

        event->motion.time = msg->time;
        event->motion.x = GET_X_LPARAM (msg->lParam);
        event->motion.y = GET_Y_LPARAM (msg->lParam);
        event->motion.modifier_state = get_modifier_state (msg->wParam);
        event->any.stage = stage;

        clutter_event_set_device (event, core_pointer);

        /* We need to start tracking when the mouse enters the stage if
           we're not already */
        if (!stage_win32->tracking_mouse)
          {
            ClutterEvent *crossing = clutter_event_new (CLUTTER_ENTER);
            TRACKMOUSEEVENT tmevent;

            tmevent.cbSize = sizeof (tmevent);
            tmevent.dwFlags = TME_LEAVE;
            tmevent.hwndTrack = stage_win32->hwnd;
            TrackMouseEvent (&tmevent);

            event->crossing.time = msg->time;
            event->crossing.x = event->motion.x;
            event->crossing.y = event->motion.y;
            event->crossing.stage = stage;
            event->crossing.source = CLUTTER_ACTOR (stage);
            event->crossing.related = NULL;

            clutter_event_set_device (event, core_pointer);

            /* we entered the stage */
            _clutter_stage_add_device (stage, event->crossing.device);

            take_and_queue_event (crossing);

            stage_win32->tracking_mouse = TRUE;
          }

        take_and_queue_event (event);
      }
      break;

    case WM_MOUSELEAVE:
      {
        ClutterEvent *event = clutter_event_new (CLUTTER_LEAVE);

        event->crossing.time = msg->time;
        event->crossing.x = msg->pt.x;
        event->crossing.y = msg->pt.y;
        event->crossing.stage = stage;
        event->crossing.source = CLUTTER_ACTOR (stage);
        event->crossing.related = NULL;

        clutter_event_set_device (event, core_pointer);

        /* we left the stage */
        _clutter_stage_remove_device (stage, core_pointer);

        /* When we get a leave message the mouse tracking is
           automatically cancelled so we'll need to start it again when
           the mouse next enters the window */
        stage_win32->tracking_mouse = FALSE;

        take_and_queue_event (event);
      }
      break;

    case WM_KEYDOWN:
    case WM_KEYUP:
    case WM_SYSKEYDOWN:
    case WM_SYSKEYUP:
      {
        ClutterEvent *event = clutter_event_new (CLUTTER_EVENT_NONE);
	int scan_code = (msg->lParam >> 16) & 0xff;
	int min = 0, max = CLUTTER_WIN32_KEY_MAP_SIZE, mid;
	BYTE key_states[256];

	/* Get the keyboard modifier states. GetKeyboardState
	   conveniently gets the key state that was current when the
	   last keyboard message read was generated */
	GetKeyboardState(key_states);

	/* Binary chop to check if we have a direct mapping for this
	   key code */
	while (min < max)
	  {
	    mid = (min + max) / 2;
	    if (clutter_win32_key_map[mid].win_sym == msg->wParam)
	      {
		event->key.keyval = clutter_win32_key_map[mid].clutter_sym;
		event->key.unicode_value = 0;
		break;
	      }
	    else if (clutter_win32_key_map[mid].win_sym < msg->wParam)
	      min = mid + 1;
	    else
	      max = mid;
	  }

	/* If we don't have a direct mapping then try getting the
	   unicode value of the key sym */
	if (min >= max)
	  {
	    WCHAR ch;
	    BYTE shift_state[256];

	    /* Translate to a Unicode value, but only take into
	       account the shift key. That way Ctrl+Shift+C will
	       generate a capital C virtual key code with a zero
	       unicode value for example */
	    memset (shift_state, 0, 256);
	    shift_state[VK_SHIFT] = key_states[VK_SHIFT];
	    shift_state[VK_LSHIFT] = key_states[VK_LSHIFT];
	    shift_state[VK_RSHIFT] = key_states[VK_RSHIFT];
	    shift_state[VK_CAPITAL] = key_states[VK_CAPITAL];

	    if (ToUnicode (msg->wParam, scan_code,
			   shift_state, &ch, 1, 0) == 1
		/* The codes in this range directly match the Latin 1
		   codes so we can just use the Unicode value as the
		   key sym */
		&& ch >= 0x20 && ch <= 0xff)
	      event->key.keyval = ch;
	    else
	      /* Otherwise we don't know what the key means but the
		 application might be able to do something with the
		 scan code so we might as well still generate the
		 event */
	      event->key.keyval = CLUTTER_KEY_VoidSymbol;

	    /* Get the unicode value of the keypress again using the
	       full modifier state */
	    if (ToUnicode (msg->wParam, scan_code,
			   key_states, &ch, 1, 0) == 1)
		event->key.unicode_value = ch;
	    else
		event->key.unicode_value = 0;
	  }

	event->key.type = msg->message == WM_KEYDOWN
	  || msg->message == WM_SYSKEYDOWN
	  ? CLUTTER_KEY_PRESS : CLUTTER_KEY_RELEASE;
	event->key.time = msg->time;
	event->key.modifier_state = get_key_modifier_state (key_states);
	event->key.hardware_keycode = scan_code;
        event->any.stage = stage;

        clutter_event_set_device (event, core_keyboard);

        take_and_queue_event (event);
      }
      break;

    case WM_GETMINMAXINFO:
      {
	MINMAXINFO *min_max_info = (MINMAXINFO *) msg->lParam;
	_clutter_stage_win32_get_min_max_info (stage_win32, min_max_info);
        return_value = TRUE;
      }
      break;

    case WM_SETCURSOR:
      /* If the cursor is in the window's client area and the stage's
         cursor should be invisible then we'll set a blank cursor
         instead */
      if (LOWORD (msg->lParam) == HTCLIENT && !stage_win32->is_cursor_visible)
        {
          return_value = TRUE;
          _clutter_stage_win32_update_cursor (stage_win32);
        }
      break;
    }

  return return_value;
}