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 4的OOB+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