使用 C# 在通用 windows 应用程序中未检测到键盘布局更改
Keyboard layout change not detected in universal windows apps with C#
我想用 C# 检测每一个键盘布局变化。无论是通过 win + space 还是 alt + shift 或鼠标切换都没关系...
我编写的代码对于桌面应用程序非常有效(见下文)。但它不适用于 UWP 应用程序。如果我在 UWP 应用程序中切换布局,则不会检测到它,如果我切换到桌面应用程序,则会立即检测到更改......我怎样才能检测到布局中的任何更改?有没有其他方法可以找出在任何给定时刻处于活动状态的布局,而不管 window 处于活动状态?
我的代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Microsoft.Win32;
using System.Runtime.InteropServices;
using System.Globalization;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string lastLang = "";
while (true)
{
string langSuffix = GetKeyboardLayoutIdAtTime();
if (!langSuffix.Equals(lastLang))
{
// do something
Console.WriteLine(getCurrentTimeStamp() + ": Changing '" + lastLang + "' to '" + langSuffix + "'.");
lastLang = langSuffix;
}
System.Threading.Thread.Sleep(1000);
}
}
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
private static extern int GetWindowThreadProcessId(IntPtr handleWindow, out int lpdwProcessID);
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
private static extern IntPtr GetKeyboardLayout(int WindowsThreadProcessID);
public static string GetKeyboardLayoutIdAtTime()
{
IntPtr hWnd = GetForegroundWindow();
int lpdwProcessId;
InputLanguageCollection installedInputLanguages = InputLanguage.InstalledInputLanguages;
CultureInfo currentInputLanguage = null;
int WinThreadProcId = GetWindowThreadProcessId(hWnd, out lpdwProcessId);
IntPtr KeybLayout = GetKeyboardLayout(WinThreadProcId);
// this remain unchanged when I switch layouts in UWP
Console.WriteLine("KL IntPtr: " + KeybLayout);
for (int i = 0; i < installedInputLanguages.Count; i++)
{
if (KeybLayout == installedInputLanguages[i].Handle) currentInputLanguage = installedInputLanguages[i].Culture;
}
if(currentInputLanguage == null)
{
Console.WriteLine(getCurrentTimeStamp() + "current input language is null...");
}
return currentInputLanguage.TwoLetterISOLanguageName;
}
private static string getCurrentTimeStamp()
{
return DateTime.Now.ToString("yyyyMMddHHmmssffff");
}
}
}
在桌面中,我们使用 Input Method Manager to communicate with an input method editor (IME), which runs as a service. In UWP, we should be able to use the Text Services Framework. There is a document about Alternatives to Windows APIs in Universal Windows Platform (UWP) apps。
所以我们应该可以使用Windows.UI.Text.Core
名称space,它提供了访问Windows核心文本API和文本输入服务器的类型。 Windows 核心文本是一个客户端-服务器系统,它将键盘输入的处理集中到单个服务器中。
我们可以找到InputLanguageChanged
event in the CoreTextServicesManager
class。当当前输入语言发生变化时发生。当我们通过 win + space 或 alt + shift 或鼠标切换输入法时, InputLanguageChanged
将被触发。
例如:
public MainPage()
{
this.InitializeComponent();
CoreTextServicesManager textServiceManager = CoreTextServicesManager.GetForCurrentView();
textServiceManager.InputLanguageChanged += TextServiceManager_InputLanguageChanged;
}
private void TextServiceManager_InputLanguageChanged(CoreTextServicesManager sender, object args)
{
Debug.WriteLine("Keyboard layout is changed!");
}
我想用 C# 检测每一个键盘布局变化。无论是通过 win + space 还是 alt + shift 或鼠标切换都没关系... 我编写的代码对于桌面应用程序非常有效(见下文)。但它不适用于 UWP 应用程序。如果我在 UWP 应用程序中切换布局,则不会检测到它,如果我切换到桌面应用程序,则会立即检测到更改......我怎样才能检测到布局中的任何更改?有没有其他方法可以找出在任何给定时刻处于活动状态的布局,而不管 window 处于活动状态? 我的代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Microsoft.Win32;
using System.Runtime.InteropServices;
using System.Globalization;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string lastLang = "";
while (true)
{
string langSuffix = GetKeyboardLayoutIdAtTime();
if (!langSuffix.Equals(lastLang))
{
// do something
Console.WriteLine(getCurrentTimeStamp() + ": Changing '" + lastLang + "' to '" + langSuffix + "'.");
lastLang = langSuffix;
}
System.Threading.Thread.Sleep(1000);
}
}
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
private static extern int GetWindowThreadProcessId(IntPtr handleWindow, out int lpdwProcessID);
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
private static extern IntPtr GetKeyboardLayout(int WindowsThreadProcessID);
public static string GetKeyboardLayoutIdAtTime()
{
IntPtr hWnd = GetForegroundWindow();
int lpdwProcessId;
InputLanguageCollection installedInputLanguages = InputLanguage.InstalledInputLanguages;
CultureInfo currentInputLanguage = null;
int WinThreadProcId = GetWindowThreadProcessId(hWnd, out lpdwProcessId);
IntPtr KeybLayout = GetKeyboardLayout(WinThreadProcId);
// this remain unchanged when I switch layouts in UWP
Console.WriteLine("KL IntPtr: " + KeybLayout);
for (int i = 0; i < installedInputLanguages.Count; i++)
{
if (KeybLayout == installedInputLanguages[i].Handle) currentInputLanguage = installedInputLanguages[i].Culture;
}
if(currentInputLanguage == null)
{
Console.WriteLine(getCurrentTimeStamp() + "current input language is null...");
}
return currentInputLanguage.TwoLetterISOLanguageName;
}
private static string getCurrentTimeStamp()
{
return DateTime.Now.ToString("yyyyMMddHHmmssffff");
}
}
}
在桌面中,我们使用 Input Method Manager to communicate with an input method editor (IME), which runs as a service. In UWP, we should be able to use the Text Services Framework. There is a document about Alternatives to Windows APIs in Universal Windows Platform (UWP) apps。
所以我们应该可以使用Windows.UI.Text.Core
名称space,它提供了访问Windows核心文本API和文本输入服务器的类型。 Windows 核心文本是一个客户端-服务器系统,它将键盘输入的处理集中到单个服务器中。
我们可以找到InputLanguageChanged
event in the CoreTextServicesManager
class。当当前输入语言发生变化时发生。当我们通过 win + space 或 alt + shift 或鼠标切换输入法时, InputLanguageChanged
将被触发。
例如:
public MainPage()
{
this.InitializeComponent();
CoreTextServicesManager textServiceManager = CoreTextServicesManager.GetForCurrentView();
textServiceManager.InputLanguageChanged += TextServiceManager_InputLanguageChanged;
}
private void TextServiceManager_InputLanguageChanged(CoreTextServicesManager sender, object args)
{
Debug.WriteLine("Keyboard layout is changed!");
}