• 欢迎访问我爱CSharp学习网,这里有最新最全的C#书籍,C#视频。
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏我爱C#学习网吧
  • 推荐使用最新版Chrome浏览器和火狐浏览器访问本网站

C# 编写输入法强势来袭

C#杂烩 52csharp 214次浏览 0个评论 扫描二维码

(点击上方蓝字,可快速关注我们)


来源:YSWALLE

cnblogs.com/yswenli/p/6528447.html


虽说输入法不是什么新事物,各种语言版本都有,不过在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.停止钩子


public void Stop()

{

    bool retKeyboard = true;

    if (hKeyboardHook != 0)

    {

        retKeyboard = UnhookWindowsHookEx(hKeyboardHook);

        hKeyboardHook = 0;

    }

    if (!(retKeyboard))

        throw new Exception(“卸载钩子失败!”);

}


4.注册事件


private void WordBoard_Load(object sender, EventArgs e)

{

    Program.keyBordHook.KeyUpEvent += KeyBordHook_KeyUpEvent;

    Program.keyBordHook.OnSpaced += KeyBordHook_OnSpaced;

    Program.keyBordHook.OnBacked += KeyBordHook_OnBacked;

}


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


private void ShowCharatar()

{

    this.listView1.BeginInvoke(new Action(() =>

    {

        label1.Text = keys;


        try

        {

            this.listView1.Items.Clear();

            var arr = CacheHelper.Get(keys);

            if (arr != null)

                for (int i = 0; i < (arr.Length > 10 ? 9 : arr.Length); i++)

                {

                    this.listView1.Items.Add((i + 1) + “、” + arr[i]);

                }

        }

        catch

        {

            label1.Text = keys = “”;

        }

    }));

}


6.显示输入


private void KeyBordHook_KeyUpEvent(object sender, KeyEventArgs e)

{

    keys += e.KeyCode.ToString().ToLower();

    this.ShowCharatar();

}


7.空格上屏


private void KeyBordHook_OnSpaced(int choose)

{

    try

    {

        if (CacheHelper.ContainsKey(keys))

        {

            if (choose > 0)

            {

                choose = choose – 1;

            }


            Program.keyBordHook.Send(CacheHelper.Get(keys)[choose]);

            label1.Text = “”;

            this.listView1.Clear();

        }

    }

    catch

    {

    }

    keys = “”;

}


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


public void Send(string msg)

{

    if (!string.IsNullOrEmpty(msg))

    {

        Stop();

        SendKeys.Send(“{RIGHT}” + msg);

        Start();

    }

}


9.back键回退


private void KeyBordHook_OnBacked()

{

    if (!string.IsNullOrEmpty(keys))

    {

        keys = keys.Substring(0, keys.Length – 1);

    }

    this.ShowCharatar();

}


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


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


10.键词转换


/*****************************************************************************************************

 * 本代码版权归@wenli所有,All Rights Reserved (C) 2015-2017

 *****************************************************************************************************

 * CLR版本:4.0.30319.42000

 * 唯一标识:8ebc884b-ee5f-45de-8638-c054b832e0ce

 * 机器名称:WENLI-PC

 * 联系人邮箱:wenguoli_520@qq.com

 *****************************************************************************************************

 * 项目名称:$projectname$

 * 命名空间:Wenli.IEM

 * 类名称:CacheHelper

 * 创建时间:2017/3/3 16:18:14

 * 创建人:wenli

 * 创建说明:

 *****************************************************************************************************/

using System;

using System.Collections.Generic;

using System.IO;

using System.Linq;

using System.Runtime.Caching;

using System.Text;

using System.Windows.Forms;


namespace Wenli.IEM.Helper

{

    public static class CacheHelper

    {

        static MemoryCache _wubiCache = new MemoryCache(“wubi”);

        static MemoryCache _pinyinCache = new MemoryCache(“pinyin”);

        static CacheHelper()

        {

            var path = Application.StartupPath + “\Win32\world.dll”;

            var arr = File.ReadAllLines(path);

            foreach (string item in arr)

            {

                var key = item.Substring(0, item.IndexOf(” “));

                var value = item.Substring(item.IndexOf(” “) + 1);

                _wubiCache.Add(key, (object)value, DateTimeOffset.MaxValue);

            }

            //

            path = Application.StartupPath + “\Win32\pinyin.dll”;

            arr = File.ReadAllLines(path);

            foreach (string item in arr)

            {

                var key = item.Substring(0, item.IndexOf(” “));

                var value = item.Substring(item.IndexOf(” “) + 1);

                _pinyinCache.Add(key, (object)value, DateTimeOffset.MaxValue);

            }

        }


        public static string[] Get(string key)

        {

            if (!string.IsNullOrEmpty(key))

            {

                var str = string.Empty;

                try

                {

                    if (_wubiCache.Contains(key))

                        str = _wubiCache[key].ToString();

                }

                catch { }

                try

                {

                    if (_pinyinCache.Contains(key))

                        str += ” ” + _pinyinCache[key].ToString();

                }

                catch { }

                if (!string.IsNullOrEmpty(str))

                {

                    var arr = str.Split(new string[] { ” ” }, StringSplitOptions.RemoveEmptyEntries);

                    for (int i = 0; i < arr.Length; i++)

                    {

                        if (arr[i].IndexOf(“*”) > -1)

                        {

                            arr[i] = arr[i].Substring(0, arr[i].IndexOf(“*”));

                        }

                    }

                    return arr;

                }

            }

            return null;

        }

        public static bool ContainsKey(string key)

        {

            if (_wubiCache.Contains(key))

                return true;

            if (_pinyinCache.Contains(key))

                return true;

            return false;

        }

        public static void Clear()

        {

            _wubiCache.Dispose();

            GC.Collect(-1);

        }

    }

}


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


C# 编写输入法强势来袭

 

C# 编写输入法强势来袭


看完本文有收获?请转发分享给更多人

,提升.Net技能 

C# 编写输入法强势来袭


我爱CSharp学习网 , 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权 , 转载请注明C# 编写输入法强势来袭
喜欢 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址