|
|
|
@@ -1718,6 +1718,367 @@ _gdk_win32_surface_fill_min_max_info (GdkSurface *surface,
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
handle_keyboard_event (GdkDisplay *display,
|
|
|
|
|
GdkSurface *surface,
|
|
|
|
|
MSG *msg,
|
|
|
|
|
int *ret_valp,
|
|
|
|
|
gboolean *goto_done)
|
|
|
|
|
{
|
|
|
|
|
GdkEvent *event;
|
|
|
|
|
GdkWin32Display *win32_display = GDK_WIN32_DISPLAY (display);
|
|
|
|
|
GdkWin32Keymap *win32_keymap;
|
|
|
|
|
GdkTranslatedKey translated;
|
|
|
|
|
gboolean return_val = FALSE;
|
|
|
|
|
|
|
|
|
|
switch (msg->message)
|
|
|
|
|
{
|
|
|
|
|
case WM_INPUTLANGCHANGE:
|
|
|
|
|
{
|
|
|
|
|
HKL input_locale;
|
|
|
|
|
|
|
|
|
|
win32_keymap = GDK_WIN32_KEYMAP (gdk_display_get_keymap (display));
|
|
|
|
|
|
|
|
|
|
input_locale = (HKL) msg->lParam;
|
|
|
|
|
gdk_win32_display_set_input_locale (win32_display, input_locale);
|
|
|
|
|
_gdk_win32_keymap_set_active_layout (win32_keymap, input_locale);
|
|
|
|
|
gdk_win32_display_increment_keymap_serial (win32_display);
|
|
|
|
|
GDK_NOTE (EVENTS,
|
|
|
|
|
g_print (" cs:%lu hkl:%p%s",
|
|
|
|
|
(gulong) msg->wParam,
|
|
|
|
|
(gpointer) msg->lParam,
|
|
|
|
|
gdk_win32_display_input_locale_is_ime (win32_display) ? " (IME)" : ""));
|
|
|
|
|
gdk_display_setting_changed (display, "gtk-im-module");
|
|
|
|
|
|
|
|
|
|
/* Generate a dummy key event to "nudge" IMContext */
|
|
|
|
|
translated.keyval = GDK_KEY_VoidSymbol;
|
|
|
|
|
translated.consumed = 0;
|
|
|
|
|
translated.layout = 0;
|
|
|
|
|
translated.level = 0;
|
|
|
|
|
event = gdk_key_event_new (GDK_KEY_PRESS,
|
|
|
|
|
surface,
|
|
|
|
|
win32_display->device_manager->core_keyboard,
|
|
|
|
|
_gdk_win32_get_next_tick (msg->time),
|
|
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
FALSE,
|
|
|
|
|
&translated,
|
|
|
|
|
&translated,
|
|
|
|
|
NULL);
|
|
|
|
|
_gdk_win32_append_event (event);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case WM_SYSKEYUP:
|
|
|
|
|
case WM_SYSKEYDOWN:
|
|
|
|
|
GDK_NOTE (EVENTS,
|
|
|
|
|
g_print (" %s ch:%.02x %s",
|
|
|
|
|
_gdk_win32_key_to_string (msg->lParam),
|
|
|
|
|
(int) msg->wParam,
|
|
|
|
|
decode_key_lparam (msg->lParam)));
|
|
|
|
|
|
|
|
|
|
/* If posted without us having keyboard focus, ignore */
|
|
|
|
|
if ((msg->wParam != VK_F10 && msg->wParam != VK_MENU) &&
|
|
|
|
|
!(HIWORD (msg->lParam) & KF_ALTDOWN))
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* Let the system handle Alt-Tab, Alt-Space and Alt-F4 unless
|
|
|
|
|
* the keyboard is grabbed.
|
|
|
|
|
*/
|
|
|
|
|
if (!_gdk_display_get_last_device_grab (display, win32_display->device_manager->core_keyboard) &&
|
|
|
|
|
(msg->wParam == VK_TAB ||
|
|
|
|
|
msg->wParam == VK_SPACE ||
|
|
|
|
|
msg->wParam == VK_F4))
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* Jump to code in common with WM_KEYUP and WM_KEYDOWN */
|
|
|
|
|
G_GNUC_FALLTHROUGH;
|
|
|
|
|
|
|
|
|
|
case WM_KEYUP:
|
|
|
|
|
case WM_KEYDOWN:
|
|
|
|
|
{
|
|
|
|
|
GdkModifierType state;
|
|
|
|
|
guint keyval;
|
|
|
|
|
guint16 keycode;
|
|
|
|
|
guint8 group;
|
|
|
|
|
gboolean is_modifier;
|
|
|
|
|
GdkTranslatedKey no_lock;
|
|
|
|
|
BYTE key_state[256];
|
|
|
|
|
GArray *translation;
|
|
|
|
|
MSG msg2;
|
|
|
|
|
int level = 0;
|
|
|
|
|
int effective_group = 0;
|
|
|
|
|
GdkModifierType consumed = 0;
|
|
|
|
|
char *composed = NULL;
|
|
|
|
|
GdkWin32Surface *impl;
|
|
|
|
|
|
|
|
|
|
if (msg->message == WM_KEYUP || msg->message == WM_KEYDOWN)
|
|
|
|
|
{
|
|
|
|
|
GDK_NOTE (EVENTS,
|
|
|
|
|
g_print (" %s ch:%.02x %s",
|
|
|
|
|
_gdk_win32_key_to_string (msg->lParam),
|
|
|
|
|
(int) msg->wParam,
|
|
|
|
|
decode_key_lparam (msg->lParam)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Ignore key messages intended for the IME */
|
|
|
|
|
if (msg->wParam == VK_PROCESSKEY || win32_display->event_record->in_ime_composition)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* Ignore autorepeats on modifiers */
|
|
|
|
|
if (msg->message == WM_KEYDOWN &&
|
|
|
|
|
(msg->wParam == VK_MENU || msg->wParam == VK_CONTROL || msg->wParam == VK_SHIFT) &&
|
|
|
|
|
((HIWORD(msg->lParam) & KF_REPEAT) >= 1))
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
if (GDK_SURFACE_DESTROYED (surface))
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
win32_keymap = GDK_WIN32_KEYMAP (gdk_display_get_keymap (display));
|
|
|
|
|
impl = GDK_WIN32_SURFACE (surface);
|
|
|
|
|
|
|
|
|
|
API_CALL (GetKeyboardState, (key_state));
|
|
|
|
|
|
|
|
|
|
keyval = GDK_KEY_VoidSymbol;
|
|
|
|
|
keycode = msg->wParam;
|
|
|
|
|
|
|
|
|
|
/* Get the WinAPI translation of the WM_KEY messages to characters.
|
|
|
|
|
|
|
|
|
|
The WM_CHAR messages are generated by a previous call to TranslateMessage() and always
|
|
|
|
|
follow directly after the corresponding WM_KEY* messages.
|
|
|
|
|
There could be 0 or more WM_CHAR messages following (for example dead keys don't generate
|
|
|
|
|
WM_CHAR messages - they generate WM_DEAD_CHAR instead, but we are not interested in those
|
|
|
|
|
messages). */
|
|
|
|
|
|
|
|
|
|
translation = g_array_sized_new (FALSE, FALSE, sizeof (gunichar2), 2);
|
|
|
|
|
while (PeekMessageW (&msg2, msg->hwnd, 0, 0, 0) && (msg2.message == WM_CHAR || msg2.message == WM_SYSCHAR))
|
|
|
|
|
{
|
|
|
|
|
/* The character is encoded in WPARAM as UTF-16. */
|
|
|
|
|
gunichar2 c = msg2.wParam;
|
|
|
|
|
|
|
|
|
|
/* Append character to translation string. */
|
|
|
|
|
g_array_append_val (translation, c);
|
|
|
|
|
|
|
|
|
|
/* Remove message from queue */
|
|
|
|
|
GetMessageW (&msg2, msg->hwnd, 0, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (translation->len > 0)
|
|
|
|
|
composed = g_utf16_to_utf8 ((gunichar2*)translation->data,
|
|
|
|
|
translation->len, NULL, NULL, NULL);
|
|
|
|
|
|
|
|
|
|
g_array_unref (translation);
|
|
|
|
|
translation = NULL;
|
|
|
|
|
|
|
|
|
|
/* Ignore control sequences like Backspace */
|
|
|
|
|
if (composed && g_unichar_iscntrl (g_utf8_get_char (composed)))
|
|
|
|
|
g_clear_pointer (&composed, g_free);
|
|
|
|
|
|
|
|
|
|
if (HIWORD (msg->lParam) & KF_EXTENDED)
|
|
|
|
|
{
|
|
|
|
|
switch (msg->wParam)
|
|
|
|
|
{
|
|
|
|
|
case VK_CONTROL:
|
|
|
|
|
keycode = VK_RCONTROL;
|
|
|
|
|
break;
|
|
|
|
|
case VK_SHIFT: /* Actually, KF_EXTENDED is not set
|
|
|
|
|
* for the right shift key.
|
|
|
|
|
*/
|
|
|
|
|
keycode = VK_RSHIFT;
|
|
|
|
|
break;
|
|
|
|
|
case VK_MENU:
|
|
|
|
|
keycode = VK_RMENU;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (msg->wParam == VK_SHIFT &&
|
|
|
|
|
LOBYTE (HIWORD (msg->lParam)) == _gdk_win32_keymap_get_rshift_scancode (win32_keymap))
|
|
|
|
|
keycode = VK_RSHIFT;
|
|
|
|
|
|
|
|
|
|
is_modifier = (msg->wParam == VK_CONTROL ||
|
|
|
|
|
msg->wParam == VK_SHIFT ||
|
|
|
|
|
msg->wParam == VK_MENU);
|
|
|
|
|
|
|
|
|
|
state = build_key_event_state (display, key_state);
|
|
|
|
|
group = get_active_group (display);
|
|
|
|
|
|
|
|
|
|
gdk_keymap_translate_keyboard_state ((GdkKeymap*) win32_keymap, keycode, state, group,
|
|
|
|
|
&keyval, &effective_group, &level, &consumed);
|
|
|
|
|
translated.keyval = keyval;
|
|
|
|
|
translated.consumed = consumed;
|
|
|
|
|
translated.layout = effective_group;
|
|
|
|
|
translated.level = level;
|
|
|
|
|
|
|
|
|
|
gdk_keymap_translate_keyboard_state ((GdkKeymap*) win32_keymap, keycode,
|
|
|
|
|
state & ~GDK_LOCK_MASK, group, &keyval,
|
|
|
|
|
&effective_group, &level, &consumed);
|
|
|
|
|
no_lock.keyval = keyval;
|
|
|
|
|
no_lock.consumed = consumed;
|
|
|
|
|
no_lock.layout = effective_group;
|
|
|
|
|
no_lock.level = level;
|
|
|
|
|
|
|
|
|
|
/* Only one release key event is fired when both shift keys are pressed together
|
|
|
|
|
and then released. In order to send the missing event, press events for shift
|
|
|
|
|
keys are recorded and sent together when the release event occurs.
|
|
|
|
|
Other modifiers (e.g. ctrl, alt) don't have this problem. */
|
|
|
|
|
if (msg->message == WM_KEYDOWN && msg->wParam == VK_SHIFT)
|
|
|
|
|
{
|
|
|
|
|
int pressed_shift = msg->lParam & 0xffffff; /* mask shift modifier */
|
|
|
|
|
|
|
|
|
|
if (win32_display->event_record->both_shift_pressed[0] == 0)
|
|
|
|
|
win32_display->event_record->both_shift_pressed[0] = pressed_shift;
|
|
|
|
|
else if (win32_display->event_record->both_shift_pressed[0] != pressed_shift)
|
|
|
|
|
win32_display->event_record->both_shift_pressed[1] = pressed_shift;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (msg->message == WM_KEYUP && msg->wParam == VK_SHIFT)
|
|
|
|
|
{
|
|
|
|
|
if (win32_display->event_record->both_shift_pressed[0] != 0 &&
|
|
|
|
|
win32_display->event_record->both_shift_pressed[1] != 0)
|
|
|
|
|
{
|
|
|
|
|
int tmp_retval;
|
|
|
|
|
MSG fake_release = *msg;
|
|
|
|
|
int pressed_shift = msg->lParam & 0xffffff;
|
|
|
|
|
|
|
|
|
|
if (win32_display->event_record->both_shift_pressed[0] == pressed_shift)
|
|
|
|
|
fake_release.lParam = win32_display->event_record->both_shift_pressed[1];
|
|
|
|
|
else
|
|
|
|
|
fake_release.lParam = win32_display->event_record->both_shift_pressed[0];
|
|
|
|
|
|
|
|
|
|
win32_display->event_record->both_shift_pressed[0] = win32_display->event_record->both_shift_pressed[1] = 0;
|
|
|
|
|
gdk_event_translate (&fake_release, &tmp_retval);
|
|
|
|
|
}
|
|
|
|
|
win32_display->event_record->both_shift_pressed[0] = win32_display->event_record->both_shift_pressed[1] = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Reset ALT_MASK if it is the Alt key itself */
|
|
|
|
|
if (msg->wParam == VK_MENU)
|
|
|
|
|
state &= ~GDK_ALT_MASK;
|
|
|
|
|
|
|
|
|
|
event = gdk_key_event_new ((msg->message == WM_KEYDOWN || msg->message == WM_SYSKEYDOWN) ? GDK_KEY_PRESS : GDK_KEY_RELEASE,
|
|
|
|
|
surface,
|
|
|
|
|
win32_display->device_manager->core_keyboard,
|
|
|
|
|
_gdk_win32_get_next_tick (msg->time),
|
|
|
|
|
keycode,
|
|
|
|
|
state,
|
|
|
|
|
is_modifier,
|
|
|
|
|
&translated,
|
|
|
|
|
&no_lock,
|
|
|
|
|
composed);
|
|
|
|
|
|
|
|
|
|
_gdk_win32_append_event (event);
|
|
|
|
|
|
|
|
|
|
g_free (composed);
|
|
|
|
|
return_val = TRUE;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case WM_SYSCHAR:
|
|
|
|
|
if (msg->wParam != VK_SPACE)
|
|
|
|
|
{
|
|
|
|
|
/* To prevent beeps, don't let DefWindowProcW() be called */
|
|
|
|
|
return_val = TRUE;
|
|
|
|
|
*goto_done = TRUE;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case WM_IME_STARTCOMPOSITION:
|
|
|
|
|
win32_display->event_record->in_ime_composition = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case WM_IME_ENDCOMPOSITION:
|
|
|
|
|
win32_display->event_record->in_ime_composition = FALSE;
|
|
|
|
|
break;
|
|
|
|
|
case WM_IME_COMPOSITION:
|
|
|
|
|
{
|
|
|
|
|
BYTE key_state[256];
|
|
|
|
|
wchar_t wbuf[100];
|
|
|
|
|
int ccount = 0;
|
|
|
|
|
HIMC himc;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
/* On Win2k WM_IME_CHAR doesn't work correctly for non-Unicode
|
|
|
|
|
* applications. Thus, handle WM_IME_COMPOSITION with
|
|
|
|
|
* GCS_RESULTSTR instead, fetch the Unicode chars from the IME
|
|
|
|
|
* with ImmGetCompositionStringW().
|
|
|
|
|
*
|
|
|
|
|
* See for instance
|
|
|
|
|
* http://groups.google.com/groups?selm=natX5.57%24g77.19788%40nntp2.onemain.com
|
|
|
|
|
* and
|
|
|
|
|
* http://groups.google.com/groups?selm=u2XfrXw5BHA.1628%40tkmsftngp02
|
|
|
|
|
* for comments by other people that seems to have the same
|
|
|
|
|
* experience. WM_IME_CHAR just gives question marks, apparently
|
|
|
|
|
* because of going through some conversion to the current code
|
|
|
|
|
* page.
|
|
|
|
|
*
|
|
|
|
|
* WM_IME_CHAR might work on NT4 or Win9x with ActiveIMM, but
|
|
|
|
|
* use WM_IME_COMPOSITION there, too, to simplify the code.
|
|
|
|
|
*/
|
|
|
|
|
GDK_NOTE (EVENTS, g_print (" %#lx", (long) msg->lParam));
|
|
|
|
|
|
|
|
|
|
if (!(msg->lParam & GCS_RESULTSTR))
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
if (GDK_SURFACE_DESTROYED (surface))
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
himc = ImmGetContext (msg->hwnd);
|
|
|
|
|
ccount = ImmGetCompositionStringW (himc, GCS_RESULTSTR,
|
|
|
|
|
wbuf, sizeof (wbuf));
|
|
|
|
|
ImmReleaseContext (msg->hwnd, himc);
|
|
|
|
|
|
|
|
|
|
ccount /= 2;
|
|
|
|
|
|
|
|
|
|
API_CALL (GetKeyboardState, (key_state));
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < ccount; i++)
|
|
|
|
|
{
|
|
|
|
|
GdkTranslatedKey translated;
|
|
|
|
|
|
|
|
|
|
/* Build a key press event */
|
|
|
|
|
translated.keyval = gdk_unicode_to_keyval (wbuf[i]);
|
|
|
|
|
translated.consumed = 0;
|
|
|
|
|
translated.layout = get_active_group (display);
|
|
|
|
|
translated.level = 0;
|
|
|
|
|
event = gdk_key_event_new (GDK_KEY_PRESS,
|
|
|
|
|
surface,
|
|
|
|
|
win32_display->device_manager->core_keyboard,
|
|
|
|
|
_gdk_win32_get_next_tick (msg->time),
|
|
|
|
|
0,
|
|
|
|
|
build_key_event_state (display, key_state),
|
|
|
|
|
FALSE,
|
|
|
|
|
&translated,
|
|
|
|
|
&translated,
|
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
|
|
_gdk_win32_append_event (event);
|
|
|
|
|
|
|
|
|
|
/* Build a key release event. */
|
|
|
|
|
event = gdk_key_event_new (GDK_KEY_RELEASE,
|
|
|
|
|
surface,
|
|
|
|
|
win32_display->device_manager->core_keyboard,
|
|
|
|
|
_gdk_win32_get_next_tick (msg->time),
|
|
|
|
|
0,
|
|
|
|
|
build_key_event_state (display, key_state),
|
|
|
|
|
FALSE,
|
|
|
|
|
&translated,
|
|
|
|
|
&translated,
|
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
|
|
_gdk_win32_append_event (event);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return_val = TRUE;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
g_warning ("Maybe this was reached because this is not a keyboard-related event");
|
|
|
|
|
g_assert_not_reached ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return return_val;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define GDK_ANY_BUTTON_MASK (GDK_BUTTON1_MASK | \
|
|
|
|
|
GDK_BUTTON2_MASK | \
|
|
|
|
|
GDK_BUTTON3_MASK | \
|
|
|
|
@@ -1732,7 +2093,6 @@ gdk_event_translate (MSG *msg,
|
|
|
|
|
POINT point;
|
|
|
|
|
MINMAXINFO *mmi;
|
|
|
|
|
HWND hwnd;
|
|
|
|
|
HIMC himc;
|
|
|
|
|
WINDOWPOS *hwndpos;
|
|
|
|
|
gboolean ignore_leave;
|
|
|
|
|
|
|
|
|
@@ -1754,8 +2114,7 @@ gdk_event_translate (MSG *msg,
|
|
|
|
|
int button;
|
|
|
|
|
|
|
|
|
|
gboolean return_val = FALSE;
|
|
|
|
|
|
|
|
|
|
int i;
|
|
|
|
|
gboolean goto_done = FALSE;
|
|
|
|
|
|
|
|
|
|
display = gdk_display_get_default ();
|
|
|
|
|
win32_display = GDK_WIN32_DISPLAY (display);
|
|
|
|
@@ -1811,346 +2170,19 @@ gdk_event_translate (MSG *msg,
|
|
|
|
|
|
|
|
|
|
switch (msg->message)
|
|
|
|
|
{
|
|
|
|
|
/* keyboard inpout related events (including IME events) */
|
|
|
|
|
case WM_INPUTLANGCHANGE:
|
|
|
|
|
{
|
|
|
|
|
GdkWin32Keymap *win32_keymap;
|
|
|
|
|
GdkTranslatedKey translated;
|
|
|
|
|
HKL input_locale;
|
|
|
|
|
|
|
|
|
|
win32_keymap = GDK_WIN32_KEYMAP (gdk_display_get_keymap (display));
|
|
|
|
|
|
|
|
|
|
input_locale = (HKL) msg->lParam;
|
|
|
|
|
gdk_win32_display_set_input_locale (win32_display, input_locale);
|
|
|
|
|
_gdk_win32_keymap_set_active_layout (win32_keymap, input_locale);
|
|
|
|
|
gdk_win32_display_increment_keymap_serial (win32_display);
|
|
|
|
|
GDK_NOTE (EVENTS,
|
|
|
|
|
g_print (" cs:%lu hkl:%p%s",
|
|
|
|
|
(gulong) msg->wParam,
|
|
|
|
|
(gpointer) msg->lParam,
|
|
|
|
|
gdk_win32_display_input_locale_is_ime (win32_display) ? " (IME)" : ""));
|
|
|
|
|
gdk_display_setting_changed (display, "gtk-im-module");
|
|
|
|
|
|
|
|
|
|
/* Generate a dummy key event to "nudge" IMContext */
|
|
|
|
|
translated.keyval = GDK_KEY_VoidSymbol;
|
|
|
|
|
translated.consumed = 0;
|
|
|
|
|
translated.layout = 0;
|
|
|
|
|
translated.level = 0;
|
|
|
|
|
event = gdk_key_event_new (GDK_KEY_PRESS,
|
|
|
|
|
surface,
|
|
|
|
|
win32_display->device_manager->core_keyboard,
|
|
|
|
|
_gdk_win32_get_next_tick (msg->time),
|
|
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
FALSE,
|
|
|
|
|
&translated,
|
|
|
|
|
&translated,
|
|
|
|
|
NULL);
|
|
|
|
|
_gdk_win32_append_event (event);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case WM_SYSKEYUP:
|
|
|
|
|
case WM_SYSKEYDOWN:
|
|
|
|
|
GDK_NOTE (EVENTS,
|
|
|
|
|
g_print (" %s ch:%.02x %s",
|
|
|
|
|
_gdk_win32_key_to_string (msg->lParam),
|
|
|
|
|
(int) msg->wParam,
|
|
|
|
|
decode_key_lparam (msg->lParam)));
|
|
|
|
|
|
|
|
|
|
/* If posted without us having keyboard focus, ignore */
|
|
|
|
|
if ((msg->wParam != VK_F10 && msg->wParam != VK_MENU) &&
|
|
|
|
|
!(HIWORD (msg->lParam) & KF_ALTDOWN))
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* Let the system handle Alt-Tab, Alt-Space and Alt-F4 unless
|
|
|
|
|
* the keyboard is grabbed.
|
|
|
|
|
*/
|
|
|
|
|
if (!keyboard_grab &&
|
|
|
|
|
(msg->wParam == VK_TAB ||
|
|
|
|
|
msg->wParam == VK_SPACE ||
|
|
|
|
|
msg->wParam == VK_F4))
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* Jump to code in common with WM_KEYUP and WM_KEYDOWN */
|
|
|
|
|
goto keyup_or_down;
|
|
|
|
|
|
|
|
|
|
case WM_KEYUP:
|
|
|
|
|
case WM_KEYDOWN:
|
|
|
|
|
GDK_NOTE (EVENTS,
|
|
|
|
|
g_print (" %s ch:%.02x %s",
|
|
|
|
|
_gdk_win32_key_to_string (msg->lParam),
|
|
|
|
|
(int) msg->wParam,
|
|
|
|
|
decode_key_lparam (msg->lParam)));
|
|
|
|
|
|
|
|
|
|
keyup_or_down:
|
|
|
|
|
{
|
|
|
|
|
GdkWin32Keymap *win32_keymap;
|
|
|
|
|
GdkModifierType state;
|
|
|
|
|
guint keyval;
|
|
|
|
|
guint16 keycode;
|
|
|
|
|
guint8 group;
|
|
|
|
|
gboolean is_modifier;
|
|
|
|
|
GdkTranslatedKey translated;
|
|
|
|
|
GdkTranslatedKey no_lock;
|
|
|
|
|
BYTE key_state[256];
|
|
|
|
|
GArray *translation;
|
|
|
|
|
MSG msg2;
|
|
|
|
|
int level = 0;
|
|
|
|
|
int effective_group = 0;
|
|
|
|
|
GdkModifierType consumed = 0;
|
|
|
|
|
char *composed = NULL;
|
|
|
|
|
|
|
|
|
|
/* Ignore key messages intended for the IME */
|
|
|
|
|
if (msg->wParam == VK_PROCESSKEY || win32_display->event_record->in_ime_composition)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* Ignore autorepeats on modifiers */
|
|
|
|
|
if (msg->message == WM_KEYDOWN &&
|
|
|
|
|
(msg->wParam == VK_MENU ||
|
|
|
|
|
msg->wParam == VK_CONTROL ||
|
|
|
|
|
msg->wParam == VK_SHIFT) &&
|
|
|
|
|
((HIWORD(msg->lParam) & KF_REPEAT) >= 1))
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
if (GDK_SURFACE_DESTROYED (surface))
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
win32_keymap = GDK_WIN32_KEYMAP (gdk_display_get_keymap (display));
|
|
|
|
|
impl = GDK_WIN32_SURFACE (surface);
|
|
|
|
|
|
|
|
|
|
API_CALL (GetKeyboardState, (key_state));
|
|
|
|
|
|
|
|
|
|
keyval = GDK_KEY_VoidSymbol;
|
|
|
|
|
keycode = msg->wParam;
|
|
|
|
|
|
|
|
|
|
/* Get the WinAPI translation of the WM_KEY messages to characters.
|
|
|
|
|
|
|
|
|
|
The WM_CHAR messages are generated by a previous call to TranslateMessage() and always
|
|
|
|
|
follow directly after the corresponding WM_KEY* messages.
|
|
|
|
|
There could be 0 or more WM_CHAR messages following (for example dead keys don't generate
|
|
|
|
|
WM_CHAR messages - they generate WM_DEAD_CHAR instead, but we are not interested in those
|
|
|
|
|
messages). */
|
|
|
|
|
|
|
|
|
|
translation = g_array_sized_new (FALSE, FALSE, sizeof (gunichar2), 2);
|
|
|
|
|
while (PeekMessageW (&msg2, msg->hwnd, 0, 0, 0) && (msg2.message == WM_CHAR || msg2.message == WM_SYSCHAR))
|
|
|
|
|
{
|
|
|
|
|
/* The character is encoded in WPARAM as UTF-16. */
|
|
|
|
|
gunichar2 c = msg2.wParam;
|
|
|
|
|
|
|
|
|
|
/* Append character to translation string. */
|
|
|
|
|
g_array_append_val (translation, c);
|
|
|
|
|
|
|
|
|
|
/* Remove message from queue */
|
|
|
|
|
GetMessageW (&msg2, msg->hwnd, 0, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (translation->len > 0)
|
|
|
|
|
composed = g_utf16_to_utf8 ((gunichar2*)translation->data,
|
|
|
|
|
translation->len, NULL, NULL, NULL);
|
|
|
|
|
|
|
|
|
|
g_array_unref (translation);
|
|
|
|
|
translation = NULL;
|
|
|
|
|
|
|
|
|
|
/* Ignore control sequences like Backspace */
|
|
|
|
|
if (composed && g_unichar_iscntrl (g_utf8_get_char (composed)))
|
|
|
|
|
g_clear_pointer (&composed, g_free);
|
|
|
|
|
|
|
|
|
|
if (HIWORD (msg->lParam) & KF_EXTENDED)
|
|
|
|
|
{
|
|
|
|
|
switch (msg->wParam)
|
|
|
|
|
{
|
|
|
|
|
case VK_CONTROL:
|
|
|
|
|
keycode = VK_RCONTROL;
|
|
|
|
|
break;
|
|
|
|
|
case VK_SHIFT: /* Actually, KF_EXTENDED is not set
|
|
|
|
|
* for the right shift key.
|
|
|
|
|
*/
|
|
|
|
|
keycode = VK_RSHIFT;
|
|
|
|
|
break;
|
|
|
|
|
case VK_MENU:
|
|
|
|
|
keycode = VK_RMENU;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (msg->wParam == VK_SHIFT &&
|
|
|
|
|
LOBYTE (HIWORD (msg->lParam)) == _gdk_win32_keymap_get_rshift_scancode (win32_keymap))
|
|
|
|
|
keycode = VK_RSHIFT;
|
|
|
|
|
|
|
|
|
|
is_modifier = (msg->wParam == VK_CONTROL ||
|
|
|
|
|
msg->wParam == VK_SHIFT ||
|
|
|
|
|
msg->wParam == VK_MENU);
|
|
|
|
|
|
|
|
|
|
state = build_key_event_state (display, key_state);
|
|
|
|
|
group = get_active_group (display);
|
|
|
|
|
|
|
|
|
|
gdk_keymap_translate_keyboard_state ((GdkKeymap*) win32_keymap, keycode, state, group,
|
|
|
|
|
&keyval, &effective_group, &level, &consumed);
|
|
|
|
|
translated.keyval = keyval;
|
|
|
|
|
translated.consumed = consumed;
|
|
|
|
|
translated.layout = effective_group;
|
|
|
|
|
translated.level = level;
|
|
|
|
|
|
|
|
|
|
gdk_keymap_translate_keyboard_state ((GdkKeymap*) win32_keymap, keycode,
|
|
|
|
|
state & ~GDK_LOCK_MASK, group, &keyval,
|
|
|
|
|
&effective_group, &level, &consumed);
|
|
|
|
|
no_lock.keyval = keyval;
|
|
|
|
|
no_lock.consumed = consumed;
|
|
|
|
|
no_lock.layout = effective_group;
|
|
|
|
|
no_lock.level = level;
|
|
|
|
|
|
|
|
|
|
/* Only one release key event is fired when both shift keys are pressed together
|
|
|
|
|
and then released. In order to send the missing event, press events for shift
|
|
|
|
|
keys are recorded and sent together when the release event occurs.
|
|
|
|
|
Other modifiers (e.g. ctrl, alt) don't have this problem. */
|
|
|
|
|
if (msg->message == WM_KEYDOWN && msg->wParam == VK_SHIFT)
|
|
|
|
|
{
|
|
|
|
|
int pressed_shift = msg->lParam & 0xffffff; /* mask shift modifier */
|
|
|
|
|
if (win32_display->event_record->both_shift_pressed[0] == 0)
|
|
|
|
|
win32_display->event_record->both_shift_pressed[0] = pressed_shift;
|
|
|
|
|
else if (win32_display->event_record->both_shift_pressed[0] != pressed_shift)
|
|
|
|
|
win32_display->event_record->both_shift_pressed[1] = pressed_shift;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (msg->message == WM_KEYUP && msg->wParam == VK_SHIFT)
|
|
|
|
|
{
|
|
|
|
|
if (win32_display->event_record->both_shift_pressed[0] != 0 &&
|
|
|
|
|
win32_display->event_record->both_shift_pressed[1] != 0)
|
|
|
|
|
{
|
|
|
|
|
int tmp_retval;
|
|
|
|
|
MSG fake_release = *msg;
|
|
|
|
|
int pressed_shift = msg->lParam & 0xffffff;
|
|
|
|
|
|
|
|
|
|
if (win32_display->event_record->both_shift_pressed[0] == pressed_shift)
|
|
|
|
|
fake_release.lParam = win32_display->event_record->both_shift_pressed[1];
|
|
|
|
|
else
|
|
|
|
|
fake_release.lParam = win32_display->event_record->both_shift_pressed[0];
|
|
|
|
|
|
|
|
|
|
win32_display->event_record->both_shift_pressed[0] = win32_display->event_record->both_shift_pressed[1] = 0;
|
|
|
|
|
gdk_event_translate (&fake_release, &tmp_retval);
|
|
|
|
|
}
|
|
|
|
|
win32_display->event_record->both_shift_pressed[0] = win32_display->event_record->both_shift_pressed[1] = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Reset ALT_MASK if it is the Alt key itself */
|
|
|
|
|
if (msg->wParam == VK_MENU)
|
|
|
|
|
state &= ~GDK_ALT_MASK;
|
|
|
|
|
|
|
|
|
|
event = gdk_key_event_new ((msg->message == WM_KEYDOWN || msg->message == WM_SYSKEYDOWN)
|
|
|
|
|
? GDK_KEY_PRESS
|
|
|
|
|
: GDK_KEY_RELEASE,
|
|
|
|
|
surface,
|
|
|
|
|
win32_display->device_manager->core_keyboard,
|
|
|
|
|
_gdk_win32_get_next_tick (msg->time),
|
|
|
|
|
keycode,
|
|
|
|
|
state,
|
|
|
|
|
is_modifier,
|
|
|
|
|
&translated,
|
|
|
|
|
&no_lock,
|
|
|
|
|
composed);
|
|
|
|
|
|
|
|
|
|
_gdk_win32_append_event (event);
|
|
|
|
|
|
|
|
|
|
g_free (composed);
|
|
|
|
|
return_val = TRUE;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case WM_SYSCHAR:
|
|
|
|
|
if (msg->wParam != VK_SPACE)
|
|
|
|
|
{
|
|
|
|
|
/* To prevent beeps, don't let DefWindowProcW() be called */
|
|
|
|
|
return_val = TRUE;
|
|
|
|
|
goto done;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case WM_IME_STARTCOMPOSITION:
|
|
|
|
|
win32_display->event_record->in_ime_composition = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case WM_IME_ENDCOMPOSITION:
|
|
|
|
|
win32_display->event_record->in_ime_composition = FALSE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case WM_IME_COMPOSITION:
|
|
|
|
|
{
|
|
|
|
|
BYTE key_state[256];
|
|
|
|
|
wchar_t wbuf[100];
|
|
|
|
|
int ccount = 0;
|
|
|
|
|
|
|
|
|
|
/* On Win2k WM_IME_CHAR doesn't work correctly for non-Unicode
|
|
|
|
|
* applications. Thus, handle WM_IME_COMPOSITION with
|
|
|
|
|
* GCS_RESULTSTR instead, fetch the Unicode chars from the IME
|
|
|
|
|
* with ImmGetCompositionStringW().
|
|
|
|
|
*
|
|
|
|
|
* See for instance
|
|
|
|
|
* http://groups.google.com/groups?selm=natX5.57%24g77.19788%40nntp2.onemain.com
|
|
|
|
|
* and
|
|
|
|
|
* http://groups.google.com/groups?selm=u2XfrXw5BHA.1628%40tkmsftngp02
|
|
|
|
|
* for comments by other people that seems to have the same
|
|
|
|
|
* experience. WM_IME_CHAR just gives question marks, apparently
|
|
|
|
|
* because of going through some conversion to the current code
|
|
|
|
|
* page.
|
|
|
|
|
*
|
|
|
|
|
* WM_IME_CHAR might work on NT4 or Win9x with ActiveIMM, but
|
|
|
|
|
* use WM_IME_COMPOSITION there, too, to simplify the code.
|
|
|
|
|
*/
|
|
|
|
|
GDK_NOTE (EVENTS, g_print (" %#lx", (long) msg->lParam));
|
|
|
|
|
|
|
|
|
|
if (!(msg->lParam & GCS_RESULTSTR))
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
if (GDK_SURFACE_DESTROYED (surface))
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
himc = ImmGetContext (msg->hwnd);
|
|
|
|
|
ccount = ImmGetCompositionStringW (himc, GCS_RESULTSTR,
|
|
|
|
|
wbuf, sizeof (wbuf));
|
|
|
|
|
ImmReleaseContext (msg->hwnd, himc);
|
|
|
|
|
|
|
|
|
|
ccount /= 2;
|
|
|
|
|
|
|
|
|
|
API_CALL (GetKeyboardState, (key_state));
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < ccount; i++)
|
|
|
|
|
{
|
|
|
|
|
GdkTranslatedKey translated;
|
|
|
|
|
|
|
|
|
|
/* Build a key press event */
|
|
|
|
|
translated.keyval = gdk_unicode_to_keyval (wbuf[i]);
|
|
|
|
|
translated.consumed = 0;
|
|
|
|
|
translated.layout = get_active_group (display);
|
|
|
|
|
translated.level = 0;
|
|
|
|
|
event = gdk_key_event_new (GDK_KEY_PRESS,
|
|
|
|
|
surface,
|
|
|
|
|
win32_display->device_manager->core_keyboard,
|
|
|
|
|
_gdk_win32_get_next_tick (msg->time),
|
|
|
|
|
0,
|
|
|
|
|
build_key_event_state (display, key_state),
|
|
|
|
|
FALSE,
|
|
|
|
|
&translated,
|
|
|
|
|
&translated,
|
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
|
|
_gdk_win32_append_event (event);
|
|
|
|
|
|
|
|
|
|
/* Build a key release event. */
|
|
|
|
|
event = gdk_key_event_new (GDK_KEY_RELEASE,
|
|
|
|
|
surface,
|
|
|
|
|
win32_display->device_manager->core_keyboard,
|
|
|
|
|
_gdk_win32_get_next_tick (msg->time),
|
|
|
|
|
0,
|
|
|
|
|
build_key_event_state (display, key_state),
|
|
|
|
|
FALSE,
|
|
|
|
|
&translated,
|
|
|
|
|
&translated,
|
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
|
|
_gdk_win32_append_event (event);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return_val = TRUE;
|
|
|
|
|
}
|
|
|
|
|
return_val = handle_keyboard_event (display, surface, msg, ret_valp, &goto_done);
|
|
|
|
|
if (goto_done)
|
|
|
|
|
goto done;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case WM_LBUTTONDOWN:
|
|
|
|
|