Dot Net中InputLanguage对象的使用限制

https://ask.csdn.net/questions/764368?utm_medium=distribute.pc_relevant_bbs_down.none-task--2~all~first_rank_v2~rank_v29-2.nonecase&depth_1-utm_source=distribute.pc_relevant_bbs_down.none-task--2~all~first_rank_v2~rank_v29-2.nonecase

c# winform 如何在 win10系统中设置输入法切换

当前网络上提供的解决方案,都是使用InputLanguage类提供的方法,但是这种方法在win10操作系统中是**获取不到**输入法列表的,请问有什么别的方式可以获取设置输入法?
经过我实际测试,在WIN10下,**InputLanguage**只能取到中文、英文输入,不能检测到具体的输入法;另外,网上提供的读**取注册表的**方式,在WIN10下也行不通,注册表中根本没有相关的项。如下:
for (int i=0 ; i< TotalKbLayout ; i++)
{
string RegKey=String.Format("System//CurrentControlSet//Control//Keyboard Layouts//{0:X8}",KbList[i]);
RegistryKey rk=Registry.LocalMachine.OpenSubKey(RegKey);
if (rk==null)
continue;
string ImeName=(string)rk.GetValue("layout text");
if (ImeName==null)
continue;
FImes.Add(ImeName, KbList[i]);
}

 

在Dot Net中,InputLanguage对象是“提供方法和字段以管理输入语言。无法继承此类。”

  InputLanguage对象中InstalledInputLanguages方法获得系统已经安装的输入法;CurrentInputLanguage方法是获取或设置当前输入法;DefaultInputLanguage方法是获取系统的默认输入法。通过InputLanguage对象的这三个方法,可以设置指定的输入法。

  而在笔者将程序给他人使用时,却意外的在其中一台机器上报错。由于是已经编译好的程序,而且又不在笔者的身边,故只知道是InputLanguage对象出了问题,而具体的错误编号不知道。

  通过QQ远程观看了错误的提示后,第一感觉就是他没有装中文输入法。可是,他明明装了输入法,有搜狗、QQ拼音等。输入法使用也正常。

  出于直觉,查看他的“文字服务和输入语言”窗口。正常的应该象下面一样。

Dot Net中InputLanguage对象的使用限制

  可是意外的现象出现了,在他的电脑上这个是一片空白,下面提示一行字“检测到不兼容的键盘驱动程序该对话框已经被禁用”。

  在网上搜了搜解决方法。发现由于种种原因,系统注册表中HKEY_LOCAL_MACHINE\SYSTEMCurrentControlSet\Control\Keyboard Layouts的键值下的内容全被删除了。

  详情参看“文字服务和输入语言的选项显示空白”。

  按照上文的方法,将缺失的注册表部分导入到他的系统中。OK!解决了。不再报错。

  由此可以知道,InputLanguage对象是通过访问注册表来控制输入法的。一旦注册表的内容有误。也就导致了错误的产生。

  不过,难以理解的是为何注册表出错,而输入法却能正常使用。

 

开始正文

1、先介绍本文会用到的windows的API,网上有很详细的资料,我这里就只简要说明一下

  ImmGetContext(IntPtr hwnd):获取当前正在输入的窗口的输入法句柄

  ImmSetOpenStatus(IntPtr himc, bool b):设置输入法的状态

  InputLanguage类:提供方法和字段以管理输入语言;这是winform里面自带的输入法管理类,msdn上有详细资料

2、比如本系统安装有两个输入法:搜狗拼音 和 智能 ABC(注意:智能 ABC中间有个空格,用下划线就是要明确对比出来)。

3、使用InputLanguage类来显示指定的输入法。

  思路很简单:先获取到操作系统中安装的所有输入法列表,然后循环列表,比对指定的输入法名称(名称可以设置在配置文件中,安装的时候,根据不同人的需要配置成不同的输入法),然后把找到的输入法设为当前输入法,代码如下:

  1. //设置“搜狗拼音”为当前输入法
  2. foreach (InputLanguage item in InputLanguage.InstalledInputLanguages)
  3. {
  4. if (item.LayoutName.Contains("搜狗拼音"))
  5. {
  6. InputLanguage.CurrentInputLanguage = item;
  7. break;
  8. }
  9. }
  10. //设置“智能 ABC”为当前输入法
  11. foreach (InputLanguage item in InputLanguage.InstalledInputLanguages)
  12. {
  13. if (item.LayoutName.Contains("智能 ABC"))
  14. {
  15. InputLanguage.CurrentInputLanguage = item;
  16. break;
  17. }
  18. }
  19. //设置系统默认输入法为当前输入法
  20. InputLanguage.CurrentInputLanguage = InputLanguage.DefaultInputLanguage;

3、解决输入法被禁用的假象。

  思路也很简单,只需要重新激活输入法就行了,这里就用到上面的API方法了。

  首先声明一个委托:

  1. private delegate void fixImeDele();
  2. private fixImeDele _fixime;

  然后定义委托要实现的事情。

  1. fixime = delegate
  2. {
  3. IntPtr HIme = ImmGetContext(this.Handle);
  4. ImmSetOpenStatus(HIme, true);
  5. };

  最后执行委托就行了哦。

  1. this.BeginInvoke(fixime);

最后完整代码如下:

  1. public partial class Form1 : Form
  2. {
  3. [DllImport("imm32.dll")]
  4. public static extern IntPtr ImmGetContext(IntPtr hwnd);//获取当前正在输入的窗口的输入法句柄
  5. [DllImport("imm32.dll")]
  6. public static extern bool ImmSetOpenStatus(IntPtr himc, bool b);//设置输入法的状态
  7. private delegate void fixImeDele();
  8. private fixImeDele fixime;
  9. public Form1()
  10. {
  11. InitializeComponent();
  12. }
  13. private void txt搜狗拼音_Enter(object sender, EventArgs e)
  14. {
  15. //int index = InputLanguage.InstalledInputLanguages.IndexOf(InputLanguage.CurrentInputLanguage);
  16. //设置“搜狗拼音”为当前输入法
  17. foreach (InputLanguage item in InputLanguage.InstalledInputLanguages)
  18. {
  19. if (item.LayoutName.Contains("搜狗拼音"))
  20. {
  21. InputLanguage.CurrentInputLanguage = item;
  22. break;
  23. }
  24. }
  25. }
  26. private void textBox3_Enter(object sender, EventArgs e)
  27. {
  28. //设置“智能 ABC”为当前输入法
  29. foreach (InputLanguage item in InputLanguage.InstalledInputLanguages)
  30. {
  31. if (item.LayoutName.Contains("智能 ABC"))
  32. {
  33. InputLanguage.CurrentInputLanguage = item;
  34. break;
  35. }
  36. }
  37. }
  38. private void txt系统默认_Enter(object sender, EventArgs e)
  39. {
  40. //设置系统默认输入法为当前输入法
  41. InputLanguage.CurrentInputLanguage = InputLanguage.DefaultInputLanguage;
  42. }
  43. private void txtTrue_Enter(object sender, EventArgs e)
  44. {
  45. fixime = delegate
  46. {
  47. IntPtr HIme = ImmGetContext(this.Handle);
  48. ImmSetOpenStatus(HIme, true);
  49. };
  50. this.BeginInvoke(fixime);
  51. }
  52. private void txtFalse_Enter(object sender, EventArgs e)
  53. {
  54. fixime = delegate
  55. {
  56. IntPtr HIme = ImmGetContext(this.Handle);
  57. ImmSetOpenStatus(HIme, false);
  58. };
  59. this.BeginInvoke(fixime);
  60. }
  61. }

再给大家分享一个小问题的解决方法

wihform 默认的 ImeMode 值是NoControl

这不适合中文输入.

因为例如: 你每到一个控件都要切换一下输入法.

我们应该把父窗口 及所有子窗口 的 ImeMode 值 设置为 On

可是这样有个问题就是 它总是全角状态.

解决办法是:
在每个窗休的 Desinger.cs文件里找到

  1. this.ImeMode = System.Windows.Forms.ImeMode.On;

替换为

  1. this.ImeMode = System.Windows.Forms.ImeMode.OnHalf;

这样就ok了.

Dot Net中InputLanguage对象的使用限制

上一篇:flexible.js如何实现rem自适应


下一篇:WAF绕过-漏洞利用之注入上传跨站等绕过