Tastaturlayout ændres ikke i universelle Windows apps med C #

Indlæg af Hanne Mølgaard Plasc

Problem



Jeg vil opdage alle tastaturlayoutændringer med C #. Det er ligegyldigt, om det skiftes af win + space eller alt + shift eller med musen ...
Jeg skrev en kode, der virker betydeligt godt (se nedenfor) til desktop apps. Men det virker ikke for UWP apps. Hvis jeg skifter layout i UWP-appen, bliver den ikke opdaget, hvis jeg skifter til desktop app, ses ændringen med det samme ... Hvordan kan jeg gøre det for at registrere enhver ændring i layoutet? Er der nogen anden måde, hvordan man finder ud af, hvilket layout der er aktivt på et givet tidspunkt, uanset hvilket vindue der er aktivt?
Min kode:


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");
    }
}


}

Bedste reference


I Desktop bruger vi Input Method Manager til at kommunikere med en inputmetode editor (IME), som kører som en tjeneste. I UWP skal vi kunne bruge teksttjenester rammen. Der er et dokument om alternativer til Windows API'er i Universal Windows Platform (UWP) apps. [7] [8]


Så vi bør kunne bruge navneområdet Windows​.UI​.Text​.Core, det giver typer til at få adgang til API'erne til Windows-kernetekst og tekstindtastningsserveren. Windows-kernetekst er et klient-server-system, der centraliserer behandling af tastaturindgang til en enkelt server. [9]


Vi kan finde InputLanguageChanged hændelsen i klassen CoreTextServicesManager. Det sker, når det aktuelle indgangssprog er ændret. Når vi skiftede indtastningsmetoden ved at vinde + plads eller alt + skifte eller med musen, vil InputLanguageChanged blive fyret. [10] [11]


For eksempel:


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!");
}