zoukankan      html  css  js  c++  java
  • C# 输入法 z

    C# 输入法

        虽说输入法不是什么新事物,各种语言版本都有,不过在C#不常见;这就会给人一种误会:C#不能做!其实C#能不能做呢,答案是肯定的——三种方式都行:IMM、TSF以及外挂式。IMM这种就是调windows的一些底层api,不过在新版本的windows中基本上已经不能用了,属于一种过时的操作方式。TSF是微软推荐的一种新方式,不过相对C#资料太少;线上主要的一些都是针对C++的版本资料,当然可以作为借鉴来实现C#版的。我这里主要介绍一种外挂式的(天啦撸,C#可以写外挂?),对于高手来说肯定不值一提,不过也算是实现了外挂及输入法!题外话——C#可以做外挂么?答案是可以的,C#针对windows的api编程资料还是很多的,下面就简单的介绍一下面可能要使用到的api:

    安装了一个钩子,截取鼠标键盘等信号

    public static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);

    停止使用钩子

    public static extern bool UnhookWindowsHookEx(int idHook);

    通过信息钩子继续下一个钩子

    public static extern int CallNextHookEx(int idHook, int nCode, Int32 wParam, IntPtr lParam);

    线程钩子需要用到

    static extern int GetCurrentThreadId();

    使用WINDOWS API函数代替获取当前实例的函数,防止钩子失效

    public static extern IntPtr GetModuleHandle(string name);

    转换指定的虚拟键码和键盘状态的相应字符或字符

    public static extern int ToAscii(int uVirtKey, //[in] 指定虚拟关键代码进行翻译。
    int uScanCode, // [in] 指定的硬件扫描码的关键须翻译成英文。高阶位的这个值设定的关键,如果是(不压)
    byte[] lpbKeyState, // [in] 指针,以256字节数组,包含当前键盘的状态。每个元素(字节)的数组包含状态的一个关键。如果高阶位的字节是一套,关键是下跌(按下)。在低比特,如果设置表明,关键是对切换。在此功能,只有肘位的CAPS LOCK键是相关的。在切换状态的NUM个锁和滚动锁定键被忽略。
    byte[] lpwTransKey, // [out] 指针的缓冲区收到翻译字符或字符。
    int fuState);

    1.有了以上的这些api基本上就可能实现鼠标键盘的监控或者锁定等;那么首先要安装钩子:

    复制代码
       // 安装键盘钩子 
    public void Start()
            {
             
                if (hKeyboardHook == 0)
                {
                    KeyboardHookProcedure = new HookProc(KeyboardHookProc);
    
                    hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardHookProcedure, GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName), 0);
    
                    //如果SetWindowsHookEx失败
                    if (hKeyboardHook == 0)
                    {
                        Stop();
                        throw new Exception("安装键盘钩子失败");
                    }
                }
            }
    复制代码

    2.安装完后就要对获取到钩子进行处理:

    复制代码
    private int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam)
            {
                // 侦听键盘事件
                if (nCode >= 0 && wParam == 0x0100)
                {
                    KeyboardHookStruct MyKeyboardHookStruct = (KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct));
    
                    #region 开关
                    if (MyKeyboardHookStruct.vkCode == 20 || MyKeyboardHookStruct.vkCode == 160 || MyKeyboardHookStruct.vkCode == 161)
                    {
                        isLocked = isLocked ? false : true;
                    }
                    #endregion
    
                    #region
                    if (isLocked)
                    {
                        if (isStarted && MyKeyboardHookStruct.vkCode >= 48 && MyKeyboardHookStruct.vkCode <= 57)
                        {
                            var c = int.Parse(((char)MyKeyboardHookStruct.vkCode).ToString());
                            OnSpaced(c);
                            isStarted = false;
                            return 1;
                        }
                        if (isStarted && MyKeyboardHookStruct.vkCode == 8)
                        {
                            OnBacked();
                            return 1;
                        }
                        if ((MyKeyboardHookStruct.vkCode >= 65 && MyKeyboardHookStruct.vkCode <= 90) || MyKeyboardHookStruct.vkCode == 32)
                        {
                            if (MyKeyboardHookStruct.vkCode >= 65 && MyKeyboardHookStruct.vkCode <= 90)
                            {
                                Keys keyData = (Keys)MyKeyboardHookStruct.vkCode;
                                KeyEventArgs e = new KeyEventArgs(keyData);
                                KeyUpEvent(this, e);
                                isStarted = true;
                            }
                            if (MyKeyboardHookStruct.vkCode == 32)
                            {
                                OnSpaced(0);
                                isStarted = false;
                            }
                            return 1;
                        }
                        else
                            return 0;
                    }
                    #endregion
                }
                return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);
            }
    复制代码

    上面一些数字,对于刚入门的同学来说也不是什么问题,一看就明白是对哪些键做的操作。

    3.停止钩子

    复制代码
     1 public void Stop()
     2         {
     3             bool retKeyboard = true;
     4 
     5 
     6             if (hKeyboardHook != 0)
     7             {
     8                 retKeyboard = UnhookWindowsHookEx(hKeyboardHook);
     9                 hKeyboardHook = 0;
    10             }
    11 
    12             if (!(retKeyboard))
    13                 throw new Exception("卸载钩子失败!");
    14         }
    复制代码

    4.注册事件

    1 private void WordBoard_Load(object sender, EventArgs e)
    2         {
    3             Program.keyBordHook.KeyUpEvent += KeyBordHook_KeyUpEvent;
    4             Program.keyBordHook.OnSpaced += KeyBordHook_OnSpaced;
    5             Program.keyBordHook.OnBacked += KeyBordHook_OnBacked;
    6         }

    5.根据输入内容显示并进行转换

    复制代码
     1 private void ShowCharatar()
     2         {
     3             this.listView1.BeginInvoke(new Action(() =>
     4             {
     5                 label1.Text = keys;
     6 
     7                 try
     8                 {
     9                     this.listView1.Items.Clear();
    10                     var arr = CacheHelper.Get(keys);
    11                     if (arr != null)
    12                         for (int i = 0; i < (arr.Length > 10 ? 9 : arr.Length); i++)
    13                         {
    14                             this.listView1.Items.Add((i + 1) + "" + arr[i]);
    15                         }
    16                 }
    17                 catch
    18                 {
    19                     label1.Text = keys = "";
    20                 }
    21             }));
    22         }
    复制代码

    6.显示输入

    1 private void KeyBordHook_KeyUpEvent(object sender, KeyEventArgs e)
    2         {
    3             keys += e.KeyCode.ToString().ToLower();
    4             this.ShowCharatar();
    5         }

    7.空格上屏

    复制代码
     1 private void KeyBordHook_OnSpaced(int choose)
     2         {
     3             try
     4             {
     5                 if (CacheHelper.ContainsKey(keys))
     6                 {
     7                     if (choose > 0)
     8                     {
     9                         choose = choose - 1;
    10                     }
    11 
    12                     Program.keyBordHook.Send(CacheHelper.Get(keys)[choose]);
    13                     label1.Text = "";
    14                     this.listView1.Clear();
    15                 }
    16             }
    17             catch
    18             {
    19 
    20             }
    21             keys = "";
    22         }
    复制代码

    8.将数据发送到激活的输入框中

    复制代码
    1 public void Send(string msg)
    2         {
    3             if (!string.IsNullOrEmpty(msg))
    4             {
    5                 Stop();
    6                 SendKeys.Send("{RIGHT}" + msg);
    7                 Start();
    8             }
    9         }
    复制代码

    9.back键回退

    复制代码
    1 private void KeyBordHook_OnBacked()
    2         {
    3             if (!string.IsNullOrEmpty(keys))
    4             {
    5                 keys = keys.Substring(0, keys.Length - 1);
    6             }
    7             this.ShowCharatar();
    8         }
    复制代码

    当然这里还可以使其他键来完善更多的功能,例如拼音的分页处理等

    至于什么五笔、拼音就要使用词库来解决了;其中五笔比较简单,拼音就非常复杂了,各种分词、联想等...这里以五笔为主,拼音为单拼来实现基本的输入功能;所以不需要什么高深算法,简单使用MemoryCache就轻松高效搞定(有兴趣的可以来https://github.com/yswenli/Wenli.IEM 上完善)

    10.键词转换

    复制代码
      1 /*****************************************************************************************************
      2  * 本代码版权归@wenli所有,All Rights Reserved (C) 2015-2017
      3  *****************************************************************************************************
      4  * CLR版本:4.0.30319.42000
      5  * 唯一标识:8ebc884b-ee5f-45de-8638-c054b832e0ce
      6  * 机器名称:WENLI-PC
      7  * 联系人邮箱:wenguoli_520@qq.com
      8  *****************************************************************************************************
      9  * 项目名称:$projectname$
     10  * 命名空间:Wenli.IEM
     11  * 类名称:CacheHelper
     12  * 创建时间:2017/3/3 16:18:14
     13  * 创建人:wenli
     14  * 创建说明:
     15  *****************************************************************************************************/
     16 using System;
     17 using System.Collections.Generic;
     18 using System.IO;
     19 using System.Linq;
     20 using System.Runtime.Caching;
     21 using System.Text;
     22 using System.Windows.Forms;
     23 
     24 namespace Wenli.IEM.Helper
     25 {
     26     public static class CacheHelper
     27     {
     28         static MemoryCache _wubiCache = new MemoryCache("wubi");
     29 
     30         static MemoryCache _pinyinCache = new MemoryCache("pinyin");
     31 
     32         static CacheHelper()
     33         {
     34             var path = Application.StartupPath + "\Win32\world.dll";
     35             var arr = File.ReadAllLines(path);
     36             foreach (string item in arr)
     37             {
     38                 var key = item.Substring(0, item.IndexOf(" "));
     39                 var value = item.Substring(item.IndexOf(" ") + 1);
     40                 _wubiCache.Add(key, (object)value, DateTimeOffset.MaxValue);
     41             }
     42 
     43             //
     44 
     45             path = Application.StartupPath + "\Win32\pinyin.dll";
     46             arr = File.ReadAllLines(path);
     47             foreach (string item in arr)
     48             {
     49                 var key = item.Substring(0, item.IndexOf(" "));
     50                 var value = item.Substring(item.IndexOf(" ") + 1);
     51                 _pinyinCache.Add(key, (object)value, DateTimeOffset.MaxValue);
     52             }
     53         }
     54 
     55         public static string[] Get(string key)
     56         {
     57             if (!string.IsNullOrEmpty(key))
     58             {
     59                 var str = string.Empty;
     60 
     61                 try
     62                 {
     63                     if (_wubiCache.Contains(key))
     64                         str = _wubiCache[key].ToString();
     65                 }
     66                 catch { }
     67                 try
     68                 {
     69                     if (_pinyinCache.Contains(key))
     70                         str += " " + _pinyinCache[key].ToString();
     71                 }
     72                 catch { }
     73 
     74                 if (!string.IsNullOrEmpty(str))
     75                 {
     76                     var arr = str.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries);
     77                     for (int i = 0; i < arr.Length; i++)
     78                     {
     79                         if (arr[i].IndexOf("*") > -1)
     80                         {
     81                             arr[i] = arr[i].Substring(0, arr[i].IndexOf("*"));
     82                         }
     83                     }
     84                     return arr;
     85                 }
     86             }
     87 
     88             return null;
     89         }
     90 
     91 
     92         public static bool ContainsKey(string key)
     93         {
     94             if (_wubiCache.Contains(key))
     95                 return true;
     96             if (_pinyinCache.Contains(key))
     97                 return true;
     98             return false;
     99         }
    100 
    101         public static void Clear()
    102         {
    103             _wubiCache.Dispose();
    104             GC.Collect(-1);
    105         }
    106     }
    107 }
    复制代码

    到此一个基本型的C#版外挂输入法就成功完成了,源码地址:https://github.com/yswenli/Wenli.IEM 

     

     


    转载请标明本文来源:http://www.cnblogs.com/yswenli/p/6528447.html
    更多内容欢迎star作者的github:https://github.com/yswenli/RedisDrive
    如果发现本文有什么问题和任何建议,也随时欢迎交流~

  • 相关阅读:
    寄存器(内存访问)知识整理
    寄存器知识点
    汇编语言之实验一
    汇编语言基础知识的总结
    汇编语言之第五章至第八章知识汇总
    汇编实验之第八章数据处理的两个基本问题
    汇编语言之第七章更灵活的定位内存地址的方法
    汇编语言之实验九
    汇编语言之第六章包含多个段的程序
    汇编语言之第五章【BX】和loop指令
  • 原文地址:https://www.cnblogs.com/zeroone/p/6534135.html
Copyright © 2011-2022 走看看