TSF Ime Helper 與 Silverlight

Silverlight 4的OOB+Elevated Trust模式,可以讓我們直接呼叫COM物件,這讓我有了把TSF Helper搬到Silverlight 4
上執行的想法,首先把TSF Helper改寫回COM物件,並註冊到電腦中,這並不難。

 

TSF Ime Helper Silverlight
 
 
/黃忠成
 
 
關於TSF Ime Helper
 
   2007年,我在MSDN上發表了如何在Vista下透過TSF來切換中文輸入法,至今已經過了2年多了,原文已找不到,
所以我重新整理一份放在我的Blog上,順便修正了CoFreeTaskMem會引發的問題。
 
 
可以用在Silverlight上嗎?
 
   Silverlight 4OOB+Elevated Trust模式,可以讓我們直接呼叫COM物件,這讓我有了把TSF Helper搬到Silverlight 4
上執行的想法,首先把TSF Helper改寫回COM物件,並註冊到電腦中,這並不難。

TSFWrapper.cs
////////////////////////////////////////////////////////////////////////////////////
//                             TSF Wrapper
//                                                       write by code6421
////////////////////////////////////////////////////////////////////////////////////
using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
 
namespace TSF
{
    [Guid("95C45D1B-5965-44AB-98E3-836ADDA10EB0")]
    public interface ITSFHelper
    {
        short[] GetLangIDS();
        bool ActiveInputMethodWithDesc(short langID, string desc);
        string[] GetInputMethodList(short langID);
        string GetCurrentInputMethodDesc(short langID);
        bool DeActiveInputMethod(short langID);
    }
 
 
    [Guid("F2D6D1CD-A287-445C-A279-285E1E683DA1"),
        ClassInterface(ClassInterfaceType.None),
    ProgId("TSF.TSFHelper10")
    ]
    public class TSFHelper : ITSFHelper
    {
        public short[] GetLangIDS()
        {
            return TSFWrapper.GetLangIDs();
        }
 
        public bool ActiveInputMethodWithDesc(short langID, string desc)
        {
            return TSFWrapper.ActiveInputMethodWithDesc(langID, desc);
        }
 
        public string[] GetInputMethodList(short langID)
        {
            return TSFWrapper.GetInputMethodList(langID);
        }
 
        public string GetCurrentInputMethodDesc(short langID)
        {
            return TSFWrapper.GetCurrentInputMethodDesc(langID);
        }
 
        public bool DeActiveInputMethod(short langID)
        {
            return TSFWrapper.DeActiveInputMethod(langID);
        }
    }
 
 
    public static class TSFWrapper
    {
        public static short[] GetLangIDs()
        {
            List<short> langIDs = new List<short>();
            ITfInputProcessorProfiles profiles;
            if (TSF_NativeAPI.TF_CreateInputProcessorProfiles(out profiles) == 0)
            {
                IntPtr langPtrs;
                int fetchCount = 0;
                if (profiles.GetLanguageList(out langPtrs, out fetchCount) == 0)
                {
                    for (int i = 0; i < fetchCount; i++)
                    {
                        short id = Marshal.ReadInt16(langPtrs, sizeof(short) * i);
                        langIDs.Add(id);
                    }
                }
                Marshal.ReleaseComObject(profiles);
            }
            return langIDs.ToArray();
        }
 
        public static bool ActiveInputMethodWithDesc(short langID, string desc)
        {
            ITfInputProcessorProfiles profiles;
            if (TSF_NativeAPI.TF_CreateInputProcessorProfiles(out profiles) == 0)
            {
                try
                {
                    IEnumTfLanguageProfiles enumerator = null;
                    if (profiles.EnumLanguageProfiles(langID, out enumerator) == 0)
                    {
                        if (enumerator != null)
                        {
                            TF_LANGUAGEPROFILE[] langProfile = new TF_LANGUAGEPROFILE[1];
                            int fetchCount = 0;
                            while (enumerator.Next(1, langProfile, out fetchCount) == 0)
                            {
                                IntPtr ptr;
                                if (profiles.GetLanguageProfileDescription(ref langProfile[0].clsid, langProfile[0].langid, ref langProfile[0].guidProfile, out ptr) == 0)
                                {
                                    bool enabled;
                                    if (profiles.IsEnabledLanguageProfile(ref langProfile[0].clsid, langProfile[0].langid, ref langProfile[0].guidProfile, out enabled) == 0)
                                    {
                                        if (enabled)
                                        {
                                            string s = Marshal.PtrToStringBSTR(ptr);
                                            if (s.Equals(desc))
                                                return profiles.ActivateLanguageProfile(ref langProfile[0].clsid, langProfile[0].langid, ref langProfile[0].guidProfile) == 0;
                                        }
                                    }
                                    Marshal.FreeBSTR(ptr);
                                    //Marshal.FreeCoTaskMem(ptr);
                                }
                            }
                        }
                    }
                }
                finally
                {
                    Marshal.ReleaseComObject(profiles);
                }
            }
            return false;
        }
 
        public static string[] GetInputMethodList(short langID)
        {
            List<string> imeList = new List<string>();
            ITfInputProcessorProfiles profiles;
            if (TSF_NativeAPI.TF_CreateInputProcessorProfiles(out profiles) == 0)
            {
                try
                {
                    IEnumTfLanguageProfiles enumerator = null;
                    if (profiles.EnumLanguageProfiles(langID, out enumerator) == 0)
                    {
                        if (enumerator != null)
                        {
                            TF_LANGUAGEPROFILE[] langProfile = new TF_LANGUAGEPROFILE[1];
                            int fetchCount = 0;
                            while (enumerator.Next(1, langProfile, out fetchCount) == 0)
                            {
                                IntPtr ptr;
                                if (profiles.GetLanguageProfileDescription(ref langProfile[0].clsid, langProfile[0].langid, ref langProfile[0].guidProfile, out ptr) == 0)
                                {
                                    bool enabled;
                                    if (profiles.IsEnabledLanguageProfile(ref langProfile[0].clsid, langProfile[0].langid, ref langProfile[0].guidProfile, out enabled) == 0)
                                    {
                                        if (enabled)
                                            imeList.Add(Marshal.PtrToStringBSTR(ptr));
                                    }
                                }
                                Marshal.FreeBSTR(ptr);
                                //in windows 2008, it will crash.
                                //Marshal.FreeCoTaskMem(ptr);
                            }
                        }
                    }
                }
                finally
                {
                    Marshal.ReleaseComObject(profiles);
                }
            }
            return imeList.ToArray();
        }
 
        public static string GetCurrentInputMethodDesc(short langID)
        {
            ITfInputProcessorProfiles profiles;
            if (TSF_NativeAPI.TF_CreateInputProcessorProfiles(out profiles) == 0)
            {
                try
                {
                    Guid clsid;
                    Guid profileid;
                    Guid catid = new Guid(TSF_NativeAPI.GUID_TFCAT_TIP_KEYBOARD.ToByteArray());
                    if (profiles.GetDefaultLanguageProfile(langID, ref catid, out clsid, out profileid) == 0)
                    {
                        if (profiles.GetActiveLanguageProfile(ref clsid, out langID, out profileid) == 0)
                        {
                            IntPtr ptr;
                            try
                            {
                                if (profiles.GetLanguageProfileDescription(ref clsid, langID, ref profileid, out ptr) == 0)
                                {
                                    string s = Marshal.PtrToStringBSTR(ptr);
                                    Marshal.FreeBSTR(ptr);
                                    //in windows 2008 , it will carsh.
                                    //Marshal.FreeCoTaskMem(ptr);
                                    return s;
                                }
                            }
                            catch (Exception ex)
                            {
                                int i = 0;
                            }
                        }
                    }
                }
                finally
                {
                    Marshal.ReleaseComObject(profiles);
                }
            }
            return string.Empty;
        }
 
 
        public static bool DeActiveInputMethod(short langID)
        {
            List<string> imeList = new List<string>();
            ITfInputProcessorProfiles profiles;
            if (TSF_NativeAPI.TF_CreateInputProcessorProfiles(out profiles) == 0)
            {
                try
                {
                    Guid clsid = Guid.Empty;
                    return profiles.ActivateLanguageProfile(ref clsid, langID, ref clsid) == 0;
                }
                finally
                {
                    Marshal.ReleaseComObject(profiles);
                }
            }
            return false;
        }
    }
}
透過RegAsm即可註冊到電腦中。

Visual Studio Command Prompt
regasm TSFIMEHelper.dll
 
 
結合Silverlight OOB+Elevated Trust
 
   最後是在Silverlight中使用它了,請注意,此法僅能用於Silverlight OOB+Elevated Trust模式。

MainPage.xaml
<UserControl x:Class="SilverlightApplication27.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">
 
    <Grid x:Name="LayoutRoot" Background="White">
        <TextBox Height="23" HorizontalAlignment="Left" Margin="52,46,0,0" Name="textBox1" VerticalAlignment="Top" Width="120" />
        <Button Content="Fetch Input List" Height="23" HorizontalAlignment="Left" Margin="275,35,0,0" Name="button1" VerticalAlignment="Top" Width="113" Click="button1_Click" />
        <ListBox Height="100" HorizontalAlignment="Left" Margin="21,150,0,0" Name="listBox1" VerticalAlignment="Top" Width="231" />
        <Button Content="Switch To" Height="23" HorizontalAlignment="Left" Margin="275,85,0,0" Name="button2" VerticalAlignment="Top" Width="113" Click="button2_Click" />
        <Button Content="Deactive" Height="23" HorizontalAlignment="Left" Margin="275,138,0,0" Name="button3" VerticalAlignment="Top" Width="113" Click="button3_Click" />
    </Grid>
</UserControl>
MainPage.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
 
namespace SilverlightApplication27
{
    public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();
        }
 
        private void button1_Click(object sender, RoutedEventArgs e)
        {
            if (System.Runtime.InteropServices.Automation.AutomationFactory.IsAvailable)
            {
                dynamic tsfHelper = System.Runtime.InteropServices.Automation.AutomationFactory.CreateObject("TSF.TSFHelper10");
                short[] result = (short[])tsfHelper.GetLangIDs();
                foreach (var lid in result)
                {
                    string[] inputs = (string[])tsfHelper.GetInputMethodList(lid);
                    foreach (var sname in inputs)
                        listBox1.Items.Add(sname + "," + lid.ToString());
                }
            }
        }
 
        private void button2_Click(object sender, RoutedEventArgs e)
        {
            if (System.Runtime.InteropServices.Automation.AutomationFactory.IsAvailable)
            {
                if (listBox1.SelectedIndex != -1)
                {
                    dynamic tsfHelper = System.Runtime.InteropServices.Automation.AutomationFactory.CreateObject("TSF.TSFHelper10");
                    string[] sels = ((string)listBox1.Items[listBox1.SelectedIndex]).Split(',');
                    tsfHelper.ActiveInputMethodWithDesc(short.Parse(sels[1]), sels[0]);
                }
            }
        }
 
        private void button3_Click(object sender, RoutedEventArgs e)
        {
            if (System.Runtime.InteropServices.Automation.AutomationFactory.IsAvailable)
            {
                dynamic tsfHelper = System.Runtime.InteropServices.Automation.AutomationFactory.CreateObject("TSF.TSFHelper10");
                string[] sels = ((string)listBox1.Items[listBox1.SelectedIndex]).Split(',');
                tsfHelper.DeActiveInputMethod(short.Parse(sels[1]));
            }
        }
    }
}
編譯並執行,按下Fetch Input List按鈕,可取得輸入法列表。
接著選取輸入法,按下Switch To即可切換,按下Deactive則切回英數。
 

範例下載:  http://code6421.sg1002.myweb.hinet.net/SL4/TSF/TSF_Silverlight.ZIP