diff --git a/gdk/win32/gdkdisplay-win32.c b/gdk/win32/gdkdisplay-win32.c index 4a7182758f..bbfda32729 100644 --- a/gdk/win32/gdkdisplay-win32.c +++ b/gdk/win32/gdkdisplay-win32.c @@ -38,6 +38,8 @@ #include +#include "gdkwin32langnotification.h" + static int debug_indent = 0; /** @@ -536,6 +538,7 @@ _gdk_win32_display_open (const gchar *display_name) NULL); _gdk_device_manager->display = _gdk_display; + _gdk_win32_lang_notification_init (); _gdk_drag_init (); _gdk_drop_init (); @@ -701,6 +704,7 @@ gdk_win32_display_finalize (GObject *object) _gdk_win32_display_finalize_cursors (display_win32); _gdk_win32_dnd_exit (); + _gdk_win32_lang_notification_exit (); g_ptr_array_free (display_win32->monitors, TRUE); diff --git a/gdk/win32/gdkevents-win32.c b/gdk/win32/gdkevents-win32.c index 712115072a..2ad57e0568 100644 --- a/gdk/win32/gdkevents-win32.c +++ b/gdk/win32/gdkevents-win32.c @@ -2113,7 +2113,6 @@ gdk_event_translate (MSG *msg, case WM_INPUTLANGCHANGE: _gdk_input_locale = (HKL) msg->lParam; _gdk_win32_keymap_set_active_layout (GDK_WIN32_KEYMAP (_gdk_win32_display_get_keymap (_gdk_display)), _gdk_input_locale); - _gdk_input_locale_is_ime = ImmIsIME (_gdk_input_locale); GetLocaleInfo (MAKELCID (LOWORD (_gdk_input_locale), SORT_DEFAULT), LOCALE_IDEFAULTANSICODEPAGE, buf, sizeof (buf)); @@ -2125,6 +2124,20 @@ gdk_event_translate (MSG *msg, (gpointer) msg->lParam, _gdk_input_locale_is_ime ? " (IME)" : "", _gdk_input_codepage)); gdk_display_setting_changed (display, "gtk-im-module"); + + /* Generate a dummy key event to "nudge" IMContext */ + event = gdk_event_new (GDK_KEY_PRESS); + event->any.surface = window; + event->key.time = _gdk_win32_get_next_tick (msg->time); + event->key.keyval = GDK_KEY_VoidSymbol; + event->key.hardware_keycode = 0; + event->key.group = 0; + gdk_event_set_scancode (event, 0); + gdk_event_set_device (event, device_manager_win32->core_keyboard); + gdk_event_set_source_device (event, device_manager_win32->system_keyboard); + event->key.is_modifier = FALSE; + event->key.state = 0; + _gdk_win32_append_event (event); break; case WM_SYSKEYUP: diff --git a/gdk/win32/gdkglobals-win32.c b/gdk/win32/gdkglobals-win32.c index 523e7c3a3b..12e228be2c 100644 --- a/gdk/win32/gdkglobals-win32.c +++ b/gdk/win32/gdkglobals-win32.c @@ -39,7 +39,7 @@ HINSTANCE _gdk_app_hmodule; gint _gdk_input_ignore_core; HKL _gdk_input_locale; -gboolean _gdk_input_locale_is_ime; +gboolean _gdk_input_locale_is_ime = FALSE; UINT _gdk_input_codepage; gint _gdk_input_ignore_wintab = FALSE; diff --git a/gdk/win32/gdkmain-win32.c b/gdk/win32/gdkmain-win32.c index dc878fa522..2506d53f11 100644 --- a/gdk/win32/gdkmain-win32.c +++ b/gdk/win32/gdkmain-win32.c @@ -83,7 +83,6 @@ _gdk_win32_surfaceing_init (void) _gdk_display_hdc = CreateDC ("DISPLAY", NULL, NULL, NULL); _gdk_input_locale = GetKeyboardLayout (0); _gdk_win32_keymap_set_active_layout (GDK_WIN32_KEYMAP (_gdk_win32_display_get_keymap (_gdk_display)), _gdk_input_locale); - _gdk_input_locale_is_ime = ImmIsIME (_gdk_input_locale); GetLocaleInfo (MAKELCID (LOWORD (_gdk_input_locale), SORT_DEFAULT), LOCALE_IDEFAULTANSICODEPAGE, buf, sizeof (buf)); diff --git a/gdk/win32/gdkproperty-win32.c b/gdk/win32/gdkproperty-win32.c index 630d6ec356..d0bc65ff59 100644 --- a/gdk/win32/gdkproperty-win32.c +++ b/gdk/win32/gdkproperty-win32.c @@ -215,9 +215,9 @@ _gdk_win32_get_setting (const gchar *name, else if (strcmp ("gtk-im-module", name) == 0) { if (_gdk_input_locale_is_ime) - g_value_set_string (value, "ime"); + g_value_set_static_string (value, "ime"); else - g_value_set_string (value, ""); + g_value_set_static_string (value, ""); return TRUE; } diff --git a/gdk/win32/gdkwin32langnotification.c b/gdk/win32/gdkwin32langnotification.c new file mode 100644 index 0000000000..94814ecd6a --- /dev/null +++ b/gdk/win32/gdkwin32langnotification.c @@ -0,0 +1,172 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 2019 Руслан Ижбулатов + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#include "config.h" + +#define COBJMACROS +#include + +#include + +#include "gdkprivate-win32.h" + +struct _GdkWin32ALPNSink +{ + ITfActiveLanguageProfileNotifySink itf_alpn_sink; + + gint ref_count; +}; + +typedef struct _GdkWin32ALPNSink GdkWin32ALPNSink; + +static GdkWin32ALPNSink *actlangchangenotify = NULL; +static ITfSource *itf_source = NULL; +static DWORD actlangchangenotify_id = 0; + +static ULONG STDMETHODCALLTYPE +alpn_sink_addref (ITfActiveLanguageProfileNotifySink *This) +{ + GdkWin32ALPNSink *alpn_sink = (GdkWin32ALPNSink *) This; + int ref_count = ++alpn_sink->ref_count; + + return ref_count; +} + +static HRESULT STDMETHODCALLTYPE +alpn_sink_queryinterface (ITfActiveLanguageProfileNotifySink *This, + REFIID riid, + LPVOID *ppvObject) +{ + *ppvObject = NULL; + + if (IsEqualGUID (riid, &IID_IUnknown)) + { + ITfActiveLanguageProfileNotifySink_AddRef (This); + *ppvObject = This; + return S_OK; + } + + if (IsEqualGUID (riid, &IID_ITfActiveLanguageProfileNotifySink)) + { + ITfActiveLanguageProfileNotifySink_AddRef (This); + *ppvObject = This; + return S_OK; + } + + return E_NOINTERFACE; +} + +static ULONG STDMETHODCALLTYPE +alpn_sink_release (ITfActiveLanguageProfileNotifySink *This) +{ + GdkWin32ALPNSink *alpn_sink = (GdkWin32ALPNSink *) This; + int ref_count = --alpn_sink->ref_count; + + if (ref_count == 0) + { + g_free (This); + } + + return ref_count; +} + +static HRESULT STDMETHODCALLTYPE +alpn_sink_on_activated (ITfActiveLanguageProfileNotifySink *This, + REFCLSID clsid, + REFGUID guidProfile, + BOOL fActivated) +{ + _gdk_input_locale_is_ime = fActivated; + return S_OK; +} + +static ITfActiveLanguageProfileNotifySinkVtbl alpn_sink_vtbl = { + alpn_sink_queryinterface, + alpn_sink_addref, + alpn_sink_release, + alpn_sink_on_activated, +}; + +static GdkWin32ALPNSink * +alpn_sink_new () +{ + GdkWin32ALPNSink *result; + + result = g_new0 (GdkWin32ALPNSink, 1); + result->itf_alpn_sink.lpVtbl = &alpn_sink_vtbl; + result->ref_count = 0; + + ITfActiveLanguageProfileNotifySink_AddRef (&result->itf_alpn_sink); + + return result; +} + + +void +_gdk_win32_lang_notification_init () +{ + HRESULT hr; + ITfThreadMgr *itf_threadmgr; + + CoInitializeEx (NULL, COINIT_APARTMENTTHREADED); + + if (actlangchangenotify != NULL) + return; + + hr = CoCreateInstance (&CLSID_TF_ThreadMgr, + NULL, + CLSCTX_INPROC_SERVER, + &IID_ITfThreadMgr, + (LPVOID *) &itf_threadmgr); + + if (!SUCCEEDED (hr)) + return; + + hr = ITfThreadMgr_QueryInterface (itf_threadmgr, &IID_ITfSource, (VOID **) &itf_source); + ITfThreadMgr_Release (itf_threadmgr); + + if (!SUCCEEDED (hr)) + return; + + actlangchangenotify = alpn_sink_new (); + + hr = ITfSource_AdviseSink (itf_source, + &IID_ITfActiveLanguageProfileNotifySink, + (IUnknown *) actlangchangenotify, + &actlangchangenotify_id); + + if (!SUCCEEDED (hr)) + { + ITfActiveLanguageProfileNotifySink_Release (&actlangchangenotify->itf_alpn_sink); + actlangchangenotify = NULL; + ITfSource_Release (itf_source); + itf_source = NULL; + } +} + +void +_gdk_win32_lang_notification_exit () +{ + if (actlangchangenotify != NULL && itf_source != NULL) + { + ITfSource_UnadviseSink (itf_source, actlangchangenotify_id); + ITfSource_Release (itf_source); + ITfActiveLanguageProfileNotifySink_Release (&actlangchangenotify->itf_alpn_sink); + } + + CoUninitialize (); +} diff --git a/gdk/win32/gdkwin32langnotification.h b/gdk/win32/gdkwin32langnotification.h new file mode 100644 index 0000000000..c67e18fc0e --- /dev/null +++ b/gdk/win32/gdkwin32langnotification.h @@ -0,0 +1,26 @@ +/* + * gdkwin32langnotification.h + * + * Copyright 2019 Руслан Ижбулатов + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library. If not, see . + */ + +#ifndef __GDK_WIN32_LANGNOTIFICATION_H__ +#define __GDK_WIN32_LANGNOTIFICATION_H__ + +void _gdk_win32_lang_notification_init (void); +void _gdk_win32_lang_notification_exit (void); + +#endif \ No newline at end of file diff --git a/gdk/win32/meson.build b/gdk/win32/meson.build index f96fc6b394..45915f2a8f 100644 --- a/gdk/win32/meson.build +++ b/gdk/win32/meson.build @@ -17,6 +17,7 @@ gdk_win32_sources = files([ 'gdkglobals-win32.c', 'gdkhdataoutputstream-win32.c', 'gdkkeys-win32.c', + 'gdkwin32langnotification.c', 'gdkmain-win32.c', 'gdkmonitor-win32.c', 'gdkproperty-win32.c',