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; } }
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); } }
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; }
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; }
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); }
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; }
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); } }
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); } }
/** * 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; }