diff --git a/gdk/win32/gdkevents-win32.c b/gdk/win32/gdkevents-win32.c index efa5e7c7d5..9c38663fd7 100644 --- a/gdk/win32/gdkevents-win32.c +++ b/gdk/win32/gdkevents-win32.c @@ -808,6 +808,8 @@ build_key_event_state (GdkEvent *event) if (GetKeyState (VK_MENU) < 0) event->key.state |= GDK_MOD1_MASK; } + else + event->key.group = 1; } static gint @@ -856,9 +858,11 @@ build_keypress_event (GdkWindowImplWin32 *impl, bytecount = ImmGetCompositionStringW (himc, GCS_RESULTSTR, wbuf, sizeof (wbuf)); ucount = bytecount / 2; + event->key.hardware_keycode = wbuf[0]; /* ??? */ } else { + event->key.hardware_keycode = msg->wParam; if (msg->message == WM_CHAR || msg->message == WM_SYSCHAR) { bytecount = MIN ((msg->lParam & 0xFFFF), sizeof (buf)); @@ -884,12 +888,11 @@ build_keypress_event (GdkWindowImplWin32 *impl, } } - /* Convert from the window's current code page + /* Convert from the thread's current code page * to Unicode. Then convert to UTF-8. * We don't handle the surrogate stuff. Should we? */ - GDK_NOTE (EVENTS, g_print ("ciACP=%d\n", impl->charset_info.ciACP)); - ucount = MultiByteToWideChar (impl->charset_info.ciACP, + ucount = MultiByteToWideChar (_gdk_input_codepage, 0, buf, bytecount, wbuf, G_N_ELEMENTS (wbuf)); } @@ -940,18 +943,24 @@ build_keyrelease_event (GdkWindowImplWin32 *impl, event->key.group = 0; /* ??? */ if (msg->message == WM_CHAR || msg->message == WM_SYSCHAR) - if (msg->wParam < ' ') - event->key.keyval = msg->wParam + '@'; - else - { - buf = msg->wParam; - MultiByteToWideChar (impl->charset_info.ciACP, - 0, &buf, 1, &wbuf, 1); - - event->key.keyval = gdk_unicode_to_keyval (wbuf); - } + { + event->key.hardware_keycode = msg->wParam; + if (msg->wParam < ' ') + event->key.keyval = msg->wParam + '@'; + else + { + buf = msg->wParam; + MultiByteToWideChar (_gdk_input_codepage, + 0, &buf, 1, &wbuf, 1); + + event->key.keyval = gdk_unicode_to_keyval (wbuf); + } + } else - event->key.keyval = GDK_VoidSymbol; + { + event->key.keyval = GDK_VoidSymbol; + event->key.hardware_keycode = 0; /* ??? */ + } build_key_event_state (event); event->key.string = NULL; event->key.length = 0; @@ -1061,7 +1070,8 @@ print_event (GdkEvent *event) else escaped = g_strescape (event->key.string, NULL); kvname = gdk_keyval_name (event->key.keyval); - g_print ("%s %d:\"%s\" ", + g_print ("%#.02x %d %s %d:\"%s\" ", + event->key.hardware_keycode, event->key.group, (kvname ? kvname : "??"), event->key.length, escaped); @@ -1796,6 +1806,7 @@ gdk_event_translate (GdkEvent *event, HWND hwnd; HCURSOR hcursor; HRGN hrgn; + CHARSETINFO charset_info; /* Invariant: * window_impl == GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (window)->impl) @@ -2014,13 +2025,16 @@ gdk_event_translate (GdkEvent *event, switch (msg->message) { case WM_INPUTLANGCHANGE: - GDK_NOTE (EVENTS, - g_print ("WM_INPUTLANGCHANGE: %p charset %lu locale %lx\n", - msg->hwnd, (gulong) msg->wParam, msg->lParam)); - window_impl->input_locale = (HKL) msg->lParam; + _gdk_input_locale = (HKL) msg->lParam; TranslateCharsetInfo ((DWORD FAR *) msg->wParam, - &window_impl->charset_info, + &charset_info, TCI_SRCCHARSET); + _gdk_input_codepage = charset_info.ciACP; + _gdk_keymap_serial++; + GDK_NOTE (EVENTS, + g_print ("WM_INPUTLANGCHANGE: %p charset %lu locale %lx cp%d\n", + msg->hwnd, (gulong) msg->wParam, msg->lParam, + _gdk_input_codepage)); break; case WM_SYSKEYUP: @@ -2068,7 +2082,6 @@ gdk_event_translate (GdkEvent *event, keyup_or_down: event->key.window = window; - event->key.hardware_keycode = msg->wParam; switch (msg->wParam) { @@ -2330,7 +2343,8 @@ gdk_event_translate (GdkEvent *event, event->key.state |= GDK_CONTROL_MASK; if (msg->wParam != VK_MENU && GetKeyState (VK_MENU) < 0) event->key.state |= GDK_MOD1_MASK; - event->key.group = 0; /* ??? */ + event->key.hardware_keycode = msg->wParam; + event->key.group = (event->key.state & GDK_MOD1_MASK) != 0; event->key.string = NULL; event->key.length = 0; return_val = !GDK_WINDOW_DESTROYED (window); diff --git a/gdk/win32/gdkglobals-win32.c b/gdk/win32/gdkglobals-win32.c index 6e86176251..b72f7cea51 100644 --- a/gdk/win32/gdkglobals-win32.c +++ b/gdk/win32/gdkglobals-win32.c @@ -33,6 +33,9 @@ HDC gdk_display_hdc; HINSTANCE gdk_dll_hinstance; HINSTANCE gdk_app_hmodule; +HKL _gdk_input_locale; +UINT _gdk_input_codepage; + WORD cf_rtf; WORD cf_utf8_string; diff --git a/gdk/win32/gdkkeys-win32.c b/gdk/win32/gdkkeys-win32.c index b28bd7b22b..2eebe11dc9 100644 --- a/gdk/win32/gdkkeys-win32.c +++ b/gdk/win32/gdkkeys-win32.c @@ -40,11 +40,246 @@ guint _gdk_keymap_serial = 0; -static gint min_keycode = 0; -static gint max_keycode = 0; - static GdkKeymap *default_keymap = NULL; +static guint *keysym_tab = NULL; + +static void +update_keymap (void) +{ + static guint current_serial = 0; + guchar key_state[256]; + guint scancode; + guint vk; + + if (keysym_tab != NULL && current_serial == _gdk_keymap_serial) + return; + + current_serial = _gdk_keymap_serial; + + if (keysym_tab == NULL) + keysym_tab = g_new (guint, 4*256); + + memset (key_state, 0, sizeof (key_state)); + + for (vk = 0; vk < 256; vk++) + { + if ((scancode = MapVirtualKey (vk, 0)) == 0) + keysym_tab[vk*4+0] = + keysym_tab[vk*4+1] = + keysym_tab[vk*4+2] = + keysym_tab[vk*4+3] = GDK_VoidSymbol; + else + { + gint i, k; + + key_state[vk] = 0x80; + for (i = 0; i < 4; i++) + { + guint *ksymp = keysym_tab + vk*4 + i; + guchar chars[2]; + + switch (i) + { + case 0: + key_state[VK_SHIFT] = 0; + key_state[VK_CONTROL] = key_state[VK_MENU] = 0; + break; + case 1: + key_state[VK_SHIFT] = 0x80; + key_state[VK_CONTROL] = key_state[VK_MENU] = 0; + break; + case 2: + key_state[VK_SHIFT] = 0; + key_state[VK_CONTROL] = key_state[VK_MENU] = 0x80; + break; + case 3: + key_state[VK_SHIFT] = 0x80; + key_state[VK_CONTROL] = key_state[VK_MENU] = 0x80; + break; + } + + *ksymp = 0; + + /* First, handle those virtual keys that we always want + * as special GDK_* keysyms, even if ToAsciiEx might + * turn some them into a ASCII character (like TAB and + * ESC). + */ + switch (vk) + { + case VK_CANCEL: + *ksymp = GDK_Cancel; break; + case VK_BACK: + *ksymp = GDK_BackSpace; break; + case VK_TAB: + *ksymp = GDK_Tab; break; + case VK_CLEAR: + *ksymp = GDK_Clear; break; + case VK_RETURN: + *ksymp = GDK_Return; break; + case VK_SHIFT: + case VK_LSHIFT: + *ksymp = GDK_Shift_L; break; + case VK_CONTROL: + case VK_LCONTROL: + *ksymp = GDK_Control_L; break; + case VK_MENU: + case VK_LMENU: + *ksymp = GDK_Alt_L; break; + case VK_PAUSE: + *ksymp = GDK_Pause; break; + case VK_ESCAPE: + *ksymp = GDK_Escape; break; + case VK_PRIOR: + *ksymp = GDK_Prior; break; + case VK_NEXT: + *ksymp = GDK_Next; break; + case VK_END: + *ksymp = GDK_End; break; + case VK_HOME: + *ksymp = GDK_Home; break; + case VK_LEFT: + *ksymp = GDK_Left; break; + case VK_UP: + *ksymp = GDK_Up; break; + case VK_RIGHT: + *ksymp = GDK_Right; break; + case VK_DOWN: + *ksymp = GDK_Down; break; + case VK_SELECT: + *ksymp = GDK_Select; break; + case VK_PRINT: + *ksymp = GDK_Print; break; + case VK_EXECUTE: + *ksymp = GDK_Execute; break; + case VK_INSERT: + *ksymp = GDK_Insert; break; + case VK_DELETE: + *ksymp = GDK_Delete; break; + case VK_HELP: + *ksymp = GDK_Help; break; + case VK_LWIN: + *ksymp = GDK_Meta_L; break; + case VK_RWIN: + *ksymp = GDK_Meta_R; break; + case VK_MULTIPLY: + *ksymp = GDK_KP_Multiply; break; + case VK_ADD: + *ksymp = GDK_KP_Add; break; + case VK_SEPARATOR: + *ksymp = GDK_KP_Separator; break; + case VK_SUBTRACT: + *ksymp = GDK_KP_Subtract; break; + case VK_DECIMAL: + *ksymp = GDK_KP_Decimal; break; + case VK_DIVIDE: + *ksymp = GDK_KP_Divide; break; + case VK_F1: + *ksymp = GDK_F1; break; + case VK_F2: + *ksymp = GDK_F2; break; + case VK_F3: + *ksymp = GDK_F3; break; + case VK_F4: + *ksymp = GDK_F4; break; + case VK_F5: + *ksymp = GDK_F5; break; + case VK_F6: + *ksymp = GDK_F6; break; + case VK_F7: + *ksymp = GDK_F7; break; + case VK_F8: + *ksymp = GDK_F8; break; + case VK_F9: + *ksymp = GDK_F9; break; + case VK_F10: + *ksymp = GDK_F10; break; + case VK_F11: + *ksymp = GDK_F11; break; + case VK_F12: + *ksymp = GDK_F12; break; + case VK_F13: + *ksymp = GDK_F13; break; + case VK_F14: + *ksymp = GDK_F14; break; + case VK_F15: + *ksymp = GDK_F15; break; + case VK_F16: + *ksymp = GDK_F16; break; + case VK_F17: + *ksymp = GDK_F17; break; + case VK_F18: + *ksymp = GDK_F18; break; + case VK_F19: + *ksymp = GDK_F19; break; + case VK_F20: + *ksymp = GDK_F20; break; + case VK_F21: + *ksymp = GDK_F21; break; + case VK_F22: + *ksymp = GDK_F22; break; + case VK_F23: + *ksymp = GDK_F23; break; + case VK_F24: + *ksymp = GDK_F24; break; + case VK_NUMLOCK: + *ksymp = GDK_Num_Lock; break; + case VK_SCROLL: + *ksymp = GDK_Scroll_Lock; break; + case VK_RSHIFT: + *ksymp = GDK_Shift_R; break; + case VK_RCONTROL: + *ksymp = GDK_Control_R; break; + case VK_RMENU: + *ksymp = GDK_Alt_R; break; + } + if (*ksymp == 0) + { + if ((k = ToAsciiEx (vk, scancode, key_state, + (LPWORD) chars, 0, + _gdk_input_locale)) == 1) + { + if (_gdk_input_codepage == 1252 && + chars[0] >= GDK_space && chars[0] <= GDK_asciitilde) + *ksymp = chars[0]; + else + { + wchar_t wcs[1]; + if (MultiByteToWideChar (_gdk_input_codepage, 0, + chars, 1, wcs, 1) > 0) + *ksymp = gdk_unicode_to_keyval (wcs[0]); + } + } + } + if (*ksymp == 0) + *ksymp = GDK_VoidSymbol; + } + key_state[vk] = 0; + } + } +#ifdef G_ENABLE_DEBUG + if (_gdk_debug_flags & GDK_DEBUG_EVENTS) + { + gint i, j; + + g_print ("keymap:\n"); + for (i = 0; i < 256; i++) + { + g_print ("%#.02x: ", i); + for (j = 0; j < 4; j++) + { + gchar *name = gdk_keyval_name (keysym_tab[i*4 + j]); + if (name == NULL) + name = "(none)"; + g_print ("%s ", name); + } + g_print ("\n"); + } + } +#endif +} + GdkKeymap* gdk_keymap_get_default (void) { @@ -57,31 +292,21 @@ gdk_keymap_get_default (void) PangoDirection gdk_keymap_get_direction (GdkKeymap *keymap) { - PangoDirection result; - char kln[KL_NAMELENGTH]; - UINT acp = GetACP (); + update_keymap (); - /* XXX : all this is untested, so if you are using a RTL language - * please provide patches/hints if your cursor blinks at - * the wrong place ... - */ - if (!GetKeyboardLayoutName(kln)) - strcpy (kln, "?"); + switch (PRIMARYLANGID (LOWORD ((DWORD) _gdk_input_locale))) + { + case LANG_HEBREW: + case LANG_ARABIC: + /* Not 100% sure about these */ + case LANG_URDU: + case LANG_FARSI: + /* Others? */ + return PANGO_DIRECTION_RTL; - switch (acp) { - case 1255 : /* Hebrew */ - case 1256 : /* Arabic */ - result = PANGO_DIRECTION_RTL; - break; - default : - result = PANGO_DIRECTION_LTR; - } - - GDK_NOTE (MISC, - g_print ("gdk_keymap_get_direction: selecting %s for '%s'\n", - result == PANGO_DIRECTION_LTR ? "LTR" : "RTL", kln)); - - return result; + default: + return PANGO_DIRECTION_LTR; + } } /** @@ -120,7 +345,34 @@ gdk_keymap_get_entries_for_keyval (GdkKeymap *keymap, retval = g_array_new (FALSE, FALSE, sizeof (GdkKeymapKey)); - /* FIXME: implement */ + /* Accept only the default keymap */ + if (keymap == NULL || keymap == gdk_keymap_get_default ()) + { + gint vk; + + update_keymap (); + + for (vk = 0; vk < 256; vk++) + { + gint i; + + for (i = 0; i < 4; i++) + { + if (keysym_tab[vk*4+i] == keyval) + { + GdkKeymapKey key; + + key.keycode = vk; + + /* 2 levels (normal, shift), two groups (normal, AltGr) */ + key.group = i / 2; + key.level = i % 2; + + g_array_append_val (retval, key); + } + } + } + } if (retval->len > 0) { @@ -168,8 +420,8 @@ gdk_keymap_get_entries_for_keycode (GdkKeymap *keymap, g_return_val_if_fail (keymap == NULL || GDK_IS_KEYMAP (keymap), FALSE); g_return_val_if_fail (n_entries != NULL, FALSE); - if (hardware_keycode < min_keycode || - hardware_keycode > max_keycode) + if (hardware_keycode <= 0 || + hardware_keycode >= 256) { if (keys) *keys = NULL; @@ -190,7 +442,31 @@ gdk_keymap_get_entries_for_keycode (GdkKeymap *keymap, else keyval_array = NULL; - /* FIXME: implement */ + /* Accept only the default keymap */ + if (keymap == NULL || keymap == gdk_keymap_get_default ()) + { + gint i; + + update_keymap (); + + for (i = 0; i < 4; i++) + { + if (key_array) + { + GdkKeymapKey key; + + key.keycode = hardware_keycode; + + key.group = i / 2; + key.level = i % 2; + + g_array_append_val (key_array, key); + } + + if (keyval_array) + g_array_append_val (keyval_array, keysym_tab[hardware_keycode*4+i]); + } + } if ((key_array && key_array->len > 0) || (keyval_array && keyval_array->len > 0)) @@ -243,13 +519,29 @@ guint gdk_keymap_lookup_key (GdkKeymap *keymap, const GdkKeymapKey *key) { + guint sym; + g_return_val_if_fail (keymap == NULL || GDK_IS_KEYMAP (keymap), 0); g_return_val_if_fail (key != NULL, 0); g_return_val_if_fail (key->group < 4, 0); - /* FIXME: implement */ + /* Accept only the default keymap */ + if (keymap != NULL && keymap != gdk_keymap_get_default ()) + return 0; - return 0; + update_keymap (); + + if (key->keycode >= 256 || + key->group < 0 || key->group >= 2 || + key->level < 0 || key->level >= 2) + return 0; + + sym = keysym_tab[key->keycode*4 + key->group*2 + key->level]; + + if (sym == GDK_VoidSymbol) + return 0; + else + return sym; } /** @@ -286,10 +578,63 @@ gdk_keymap_translate_keyboard_state (GdkKeymap *keymap, gint *level, GdkModifierType *consumed_modifiers) { + guint tmp_keyval; + gint shift_level; + g_return_val_if_fail (keymap == NULL || GDK_IS_KEYMAP (keymap), FALSE); g_return_val_if_fail (group < 4, FALSE); - /* FIXME: implement */ + if (keyval) + *keyval = 0; + if (effective_group) + *effective_group = 0; + if (level) + *level = 0; + if (consumed_modifiers) + *consumed_modifiers = 0; + + /* Accept only the default keymap */ + if (keymap != NULL && keymap != gdk_keymap_get_default ()) + return FALSE; + + if (hardware_keycode >= 256) + return FALSE; + + if (group < 0 || group >= 2) + return FALSE; + + if ((state & GDK_SHIFT_MASK) && (state & GDK_LOCK_MASK)) + shift_level = 0; /* shift disables shift lock */ + else if ((state & GDK_SHIFT_MASK) || (state & GDK_LOCK_MASK)) + shift_level = 1; + else + shift_level = 0; + + update_keymap (); + + tmp_keyval = keysym_tab[hardware_keycode*4 + group*2 + shift_level]; + + if (effective_group) + *effective_group = group; + + if (level) + *level = shift_level; + + /* GDK_ISO_Left_Tab, as usually configured through XKB, really messes + * up the whole idea of "consumed modifiers" because shift is consumed. + * However, Tab is not _consistently_ GDK_ISO_Left_Tab, so people + * can't bind to GDK_ISO_Left_Tab instead. So, we force consistency here. + */ + if (tmp_keyval == GDK_Tab && shift_level == 1) + { + tmp_keyval = GDK_ISO_Left_Tab; + } + + if (consumed_modifiers) + *consumed_modifiers = GDK_SHIFT_MASK | GDK_LOCK_MASK; + + if (keyval) + *keyval = tmp_keyval; return FALSE; } diff --git a/gdk/win32/gdkmain-win32.c b/gdk/win32/gdkmain-win32.c index 70137bf50c..b5503a5191 100644 --- a/gdk/win32/gdkmain-win32.c +++ b/gdk/win32/gdkmain-win32.c @@ -70,6 +70,8 @@ gboolean _gdk_windowing_init_check (int argc, char **argv) { + gchar buf[10]; + #ifdef HAVE_WINTAB if (getenv ("GDK_IGNORE_WINTAB") != NULL) gdk_input_ignore_wintab = TRUE; @@ -85,6 +87,14 @@ _gdk_windowing_init_check (int argc, gdk_root_window = GetDesktopWindow (); windows_version = GetVersion (); + _gdk_input_locale = GetKeyboardLayout (0); + GetLocaleInfo (MAKELCID (LOWORD (_gdk_input_locale), SORT_DEFAULT), + LOCALE_IDEFAULTANSICODEPAGE, + buf, sizeof (buf)); + _gdk_input_codepage = atoi (buf); + GDK_NOTE (MISC, g_print ("input_locale: %#lx, codepage:%d\n", + _gdk_input_locale, _gdk_input_codepage)); + CoInitialize (NULL); cf_rtf = RegisterClipboardFormat ("Rich Text Format"); diff --git a/gdk/win32/gdkprivate-win32.h b/gdk/win32/gdkprivate-win32.h index 1fafb86017..8b2d0c65a8 100644 --- a/gdk/win32/gdkprivate-win32.h +++ b/gdk/win32/gdkprivate-win32.h @@ -444,6 +444,14 @@ extern HDC gdk_display_hdc; extern HINSTANCE gdk_dll_hinstance; extern HINSTANCE gdk_app_hmodule; +/* These are thread specific, but GDK/win32 works OK only when invoked + * from a single thread anyway. + */ +extern HKL _gdk_input_locale; +extern UINT _gdk_input_codepage; + +extern guint _gdk_keymap_serial; + /* Registered clipboard formats */ extern WORD cf_rtf; extern WORD cf_utf8_string; diff --git a/gdk/win32/gdkwindow-win32.c b/gdk/win32/gdkwindow-win32.c index 9b051316db..a0d8d55826 100644 --- a/gdk/win32/gdkwindow-win32.c +++ b/gdk/win32/gdkwindow-win32.c @@ -95,9 +95,6 @@ gdk_window_impl_win32_init (GdkWindowImplWin32 *impl) impl->hcursor = NULL; impl->hint_flags = 0; impl->extension_events_selected = FALSE; - impl->input_locale = GetKeyboardLayout (0); - TranslateCharsetInfo ((DWORD FAR *) GetACP (), &impl->charset_info, - TCI_SRCCODEPAGE); } static void @@ -644,14 +641,11 @@ gdk_window_new (GdkWindow *parent, #endif GDK_NOTE (MISC, - g_print ("... \"%s\" %dx%d@+%d+%d %p = %p\n" - "... locale %#x codepage %d\n", + g_print ("... \"%s\" %dx%d@+%d+%d %p = %p\n", mbtitle, width, height, (x == CW_USEDEFAULT ? -9999 : x), y, hparent, - GDK_WINDOW_HWND (window), - (guint) impl->input_locale, - (guint) impl->charset_info.ciACP)); + GDK_WINDOW_HWND (window))); g_free (mbtitle); diff --git a/gdk/win32/gdkwindow-win32.h b/gdk/win32/gdkwindow-win32.h index e57b088dda..d084f72492 100644 --- a/gdk/win32/gdkwindow-win32.h +++ b/gdk/win32/gdkwindow-win32.h @@ -87,9 +87,6 @@ struct _GdkWindowImplWin32 gint hint_max_width, hint_max_height; gboolean extension_events_selected; - - HKL input_locale; - CHARSETINFO charset_info; }; struct _GdkWindowImplWin32Class