コード例 #1
0
ファイル: gdkmireventsource.c プロジェクト: csoriano89/gtk-1
static void
handle_key_event (GdkWindow *window, const MirInputEvent *event)
{
  const MirKeyboardEvent *keyboard_event = mir_input_event_get_keyboard_event (event);
  GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (window->impl);
  GdkKeymap *keymap;
  guint modifier_state;
  guint button_state;

  if (!keyboard_event)
    return;

  switch (mir_keyboard_event_action (keyboard_event))
    {
    case mir_keyboard_action_up:
    case mir_keyboard_action_down:
      // FIXME: Convert keycode
      _gdk_mir_window_impl_get_cursor_state (impl, NULL, NULL, NULL, &button_state);
      modifier_state = get_modifier_state (mir_keyboard_event_modifiers (keyboard_event), button_state);
      keymap = gdk_keymap_get_for_display (gdk_window_get_display (window));

      generate_key_event (window,
                          mir_keyboard_event_action (keyboard_event) == mir_keyboard_action_down ? GDK_KEY_PRESS : GDK_KEY_RELEASE,
                          modifier_state,
                          mir_keyboard_event_key_code (keyboard_event),
                          mir_keyboard_event_scan_code (keyboard_event),
                          _gdk_mir_keymap_key_is_modifier (keymap, mir_keyboard_event_key_code (keyboard_event)),
                          NANO_TO_MILLI (mir_input_event_get_event_time (event)));
      break;
    default:
    //case mir_key_action_multiple:
      // FIXME
      break;
    }
}
コード例 #2
0
ファイル: gdkmireventsource.c プロジェクト: endlessm/gtk
static void
handle_touch_event (GdkWindow           *window,
                    const MirTouchEvent *mir_touch_event)
{
  const MirInputEvent *mir_input_event = mir_touch_event_input_event (mir_touch_event);
  guint n = mir_touch_event_point_count (mir_touch_event);
  GdkEvent *gdk_event;
  guint i;

  for (i = 0; i < n; i++)
    {
      MirTouchAction action = mir_touch_event_action (mir_touch_event, i);
      if (action == mir_touch_action_up)
        gdk_event = gdk_event_new (GDK_TOUCH_END);
      else if (action == mir_touch_action_down)
        gdk_event = gdk_event_new (GDK_TOUCH_BEGIN);
      else
        gdk_event = gdk_event_new (GDK_TOUCH_UPDATE);

      gdk_event->touch.window = window;
      gdk_event->touch.sequence = GINT_TO_POINTER (mir_touch_event_id (mir_touch_event, i));
      gdk_event->touch.time = mir_input_event_get_event_time (mir_input_event);
      gdk_event->touch.state = get_modifier_state (mir_touch_event_modifiers (mir_touch_event), 0);
      gdk_event->touch.x = mir_touch_event_axis_value (mir_touch_event, i, mir_touch_axis_x);
      gdk_event->touch.y = mir_touch_event_axis_value (mir_touch_event, i, mir_touch_axis_y);
      gdk_event->touch.x_root = mir_touch_event_axis_value (mir_touch_event, i, mir_touch_axis_x);
      gdk_event->touch.y_root = mir_touch_event_axis_value (mir_touch_event, i, mir_touch_axis_y);
      gdk_event->touch.emulating_pointer = TRUE;
      gdk_event_set_pointer_emulated (gdk_event, TRUE);

      send_event (window, get_pointer (window), gdk_event);
    }
}
コード例 #3
0
ファイル: keybindings.c プロジェクト: Ygrex/termit
int termit_parse_keys_str(const gchar* keybinding, struct KeyWithState* kws)
{
    gchar *modifier = NULL, *key = NULL;
    // token[0] - modifier. Only Alt, Ctrl or Shift allowed.
    gchar** tokens = g_strsplit(keybinding, "-", 2);
    if (!tokens[0]) {
        ERROR("failed to parse: [%s]", keybinding);
        return -1;
    }
    if (!tokens[1]) {
        key = tokens[0];
    } else {
        modifier = tokens[0];
        key = tokens[1];
    }
    gint tmp_state = 0;
    if (modifier) {
        tmp_state = get_modifier_state(modifier);
        if (tmp_state == GDK_NOTHING) {
            TRACE("Bad modifier: %s", keybinding);
            return -1;
        }
    }
    guint tmp_keyval = gdk_keyval_from_name(key);
    if (tmp_keyval == GDK_KEY_VoidSymbol) {
        TRACE("Bad keyval: %s", keybinding);
        return -1;
    }
    g_strfreev(tokens);
    kws->state = tmp_state;
    kws->keyval = gdk_keyval_to_lower(tmp_keyval);
    return 0;
}
コード例 #4
0
static void
make_button_event (const MSG *msg, ClutterEvent *event,
		   int button, int click_count, gboolean release)
{
  event->type = release ? CLUTTER_BUTTON_RELEASE : CLUTTER_BUTTON_PRESS;
  event->button.time = msg->time;
  event->button.x = GET_X_LPARAM (msg->lParam);
  event->button.y = GET_Y_LPARAM (msg->lParam);
  event->button.modifier_state = get_modifier_state (msg->wParam);
  event->button.button = button;
  event->button.click_count = click_count;
}
コード例 #5
0
ファイル: clutter-event-win32.c プロジェクト: nobled/clutter
static inline void
make_button_event (const MSG *msg,
                   ClutterStage *stage,
		   int button,
                   int click_count,
                   gboolean release,
                   ClutterInputDevice *device)
{
  ClutterEvent *event = clutter_event_new (release ?
                                           CLUTTER_BUTTON_RELEASE :
                                           CLUTTER_BUTTON_PRESS);

  event->any.stage = stage;

  event->button.time = msg->time;
  event->button.x = GET_X_LPARAM (msg->lParam);
  event->button.y = GET_Y_LPARAM (msg->lParam);
  event->button.modifier_state = get_modifier_state (msg->wParam);
  event->button.button = button;
  event->button.click_count = click_count;
  clutter_event_set_device (event, device);

  take_and_queue_event (event);
}
コード例 #6
0
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;
}
コード例 #7
0
ファイル: gdkmireventsource.c プロジェクト: csoriano89/gtk-1
static void
handle_motion_event (GdkWindow *window, const MirInputEvent *event)
{
  const MirPointerEvent *pointer_event = mir_input_event_get_pointer_event (event);
  GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (window->impl);
  gdouble x, y;
  gboolean cursor_inside;
  guint button_state;
  guint modifier_state;
  guint32 event_time;
  GdkEventType event_type;
  guint changed_button_state;

  if (!pointer_event)
    return;

  _gdk_mir_window_impl_get_cursor_state (impl, &x, &y, &cursor_inside, &button_state);
  modifier_state = get_modifier_state (mir_pointer_event_modifiers (pointer_event), mir_pointer_event_get_button_state (pointer_event));
  event_time = NANO_TO_MILLI (mir_input_event_get_event_time (event));

  /* TODO: Remove once we have proper transient window support. */
  if (mir_pointer_event_action (pointer_event) == mir_pointer_action_leave)
    {
      LeaveInfo info;

      info.x = x;
      info.y = y;
      info.time = event_time;
      info.except = window;

      /* Leave all transient children from leaf to root, except the root since we do it later. */
      _gdk_mir_window_transient_children_foreach (window, leave_windows_except, &info);
    }
  else
    {
      LeaveInfo info;

      info.x = x;
      info.y = y;
      info.time = event_time;
      info.except = _gdk_mir_window_get_visible_transient_child (window, x, y, &x, &y);

      /* Leave all transient children from leaf to root, except the pointer window since we enter it. */
      _gdk_mir_window_transient_children_foreach (window, leave_windows_except, &info);

      window = info.except;

      if (window)
        {
          /* Enter the pointer window. */
          gboolean cursor_inside_pointer_window;

          impl = GDK_MIR_WINDOW_IMPL (window->impl);
          _gdk_mir_window_impl_get_cursor_state (impl, NULL, NULL, &cursor_inside_pointer_window, NULL);

          if (!cursor_inside_pointer_window)
            {
              generate_crossing_event (window, GDK_ENTER_NOTIFY, x, y, event_time);
              _gdk_mir_window_impl_set_cursor_state (impl, x, y, TRUE, mir_pointer_event_get_button_state (pointer_event));
            }
        }
    }

  if (window)
    {
      gdouble new_x;
      gdouble new_y;
      gdouble hscroll;
      gdouble vscroll;

      /* Update which window has focus */
      _gdk_mir_pointer_set_location (get_pointer (window), x, y, window, modifier_state);
      switch (mir_pointer_event_action (pointer_event))
        {
        case mir_pointer_action_button_up:
        case mir_pointer_action_button_down:
          event_type = mir_pointer_event_action (pointer_event) == mir_pointer_action_button_down ? GDK_BUTTON_PRESS : GDK_BUTTON_RELEASE;
          changed_button_state = button_state ^ mir_pointer_event_get_button_state (pointer_event);
          if (changed_button_state == 0 || (changed_button_state & mir_pointer_button_primary) != 0)
            generate_button_event (window, event_type, x, y, GDK_BUTTON_PRIMARY, modifier_state, event_time);
          if ((changed_button_state & mir_pointer_button_secondary) != 0)
            generate_button_event (window, event_type, x, y, GDK_BUTTON_SECONDARY, modifier_state, event_time);
          if ((changed_button_state & mir_pointer_button_tertiary) != 0)
            generate_button_event (window, event_type, x, y, GDK_BUTTON_MIDDLE, modifier_state, event_time);
          button_state = mir_pointer_event_get_button_state (pointer_event);
          break;
        case mir_pointer_action_motion:
          new_x = mir_pointer_event_axis_value (pointer_event, mir_pointer_axis_x);
          new_y = mir_pointer_event_axis_value (pointer_event, mir_pointer_axis_y);
          hscroll = mir_pointer_event_axis_value (pointer_event, mir_pointer_axis_hscroll);
          vscroll = mir_pointer_event_axis_value (pointer_event, mir_pointer_axis_vscroll);

          if (hscroll > 0.5 || vscroll > 0.5)
            generate_scroll_event (window, x, y, hscroll, vscroll, modifier_state, event_time);
          if (ABS (new_x - x) > 0.5 || ABS (new_y - y) > 0.5)
            generate_motion_event (window, new_x, new_y, modifier_state, event_time);

          break;
        case mir_pointer_action_leave:
          if (cursor_inside)
            {
              cursor_inside = FALSE;
              generate_crossing_event (window, GDK_LEAVE_NOTIFY, x, y, event_time);
            }
          break;
        default:
          break;
        }

      _gdk_mir_window_impl_set_cursor_state (impl, x, y, cursor_inside, button_state);
    }
}
コード例 #8
0
ファイル: gdkmireventsource.c プロジェクト: endlessm/gtk
static void
handle_motion_event (GdkWindow *window, const MirInputEvent *event)
{
  const MirPointerEvent *pointer_event = mir_input_event_get_pointer_event (event);
  GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (window->impl);
  gdouble x, y;
  gboolean cursor_inside;
  guint button_state;
  guint new_button_state;
  guint modifier_state;
  guint32 event_time;
  GdkEventType event_type;
  guint changed_button_state;

  if (!pointer_event)
    return;

  _gdk_mir_window_impl_get_cursor_state (impl, &x, &y, &cursor_inside, &button_state);
  new_button_state = get_button_state (pointer_event);
  modifier_state = get_modifier_state (mir_pointer_event_modifiers (pointer_event), new_button_state);
  event_time = NANO_TO_MILLI (mir_input_event_get_event_time (event));

  if (window)
    {
      gdouble new_x;
      gdouble new_y;
      gdouble hscroll;
      gdouble vscroll;

      /* Update which window has focus */
      _gdk_mir_pointer_set_location (get_pointer (window), x, y, window, modifier_state);
      switch (mir_pointer_event_action (pointer_event))
        {
        case mir_pointer_action_button_up:
        case mir_pointer_action_button_down:
          event_type = mir_pointer_event_action (pointer_event) == mir_pointer_action_button_down ? GDK_BUTTON_PRESS : GDK_BUTTON_RELEASE;
          changed_button_state = button_state ^ new_button_state;
          if (changed_button_state == 0 || (changed_button_state & GDK_BUTTON1_MASK) != 0)
            generate_button_event (window, event_type, x, y, GDK_BUTTON_PRIMARY, modifier_state, event_time);
          if ((changed_button_state & GDK_BUTTON2_MASK) != 0)
            generate_button_event (window, event_type, x, y, GDK_BUTTON_MIDDLE, modifier_state, event_time);
          if ((changed_button_state & GDK_BUTTON3_MASK) != 0)
            generate_button_event (window, event_type, x, y, GDK_BUTTON_SECONDARY, modifier_state, event_time);
          button_state = new_button_state;
          break;
        case mir_pointer_action_motion:
          new_x = mir_pointer_event_axis_value (pointer_event, mir_pointer_axis_x);
          new_y = mir_pointer_event_axis_value (pointer_event, mir_pointer_axis_y);
          hscroll = mir_pointer_event_axis_value (pointer_event, mir_pointer_axis_hscroll);
          vscroll = mir_pointer_event_axis_value (pointer_event, mir_pointer_axis_vscroll);

          if (hscroll != 0.0 || vscroll != 0.0)
            generate_scroll_event (window, x, y, hscroll, vscroll, modifier_state, event_time);
          if (ABS (new_x - x) > 0.5 || ABS (new_y - y) > 0.5)
            {
              generate_motion_event (window, new_x, new_y, modifier_state, event_time);
              x = new_x;
              y = new_y;
            }

          break;
        case mir_pointer_action_enter:
          if (!cursor_inside)
            {
              cursor_inside = TRUE;
              generate_crossing_event (window, GDK_ENTER_NOTIFY, x, y, event_time);
            }
          break;
        case mir_pointer_action_leave:
          if (cursor_inside)
            {
              cursor_inside = FALSE;
              generate_crossing_event (window, GDK_LEAVE_NOTIFY, x, y, event_time);
            }
          break;
        default:
          break;
        }

      _gdk_mir_window_impl_set_cursor_state (impl, x, y, cursor_inside, button_state);
    }
}
コード例 #9
0
ファイル: clutter-event-win32.c プロジェクト: nobled/clutter
/**
 * 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;
}