C# 入力メソッドの概要

Apr 24, 2017 am 11:46 AM

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);
ログイン後にコピー

停止使用钩子

publicstatic extern bool UnhookWindowsHookEx(intidHook);
ログイン後にコピー

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

publicstatic extern int CallNextHookEx(intidHook, int nCode, Int32 wParam, IntPtr lParam);
ログイン後にコピー

线程钩子需要用到

static extern int GetCurrentThreadId();
ログイン後にコピー

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

publicstatic extern IntPtr GetModuleHandle(stringname);
ログイン後にコピー

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

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                 catch18                 {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             catch18             {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就轻松高效搞定

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#版外挂输入法就成功完成了

以上がC# 入力メソッドの概要の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

C# を使用した Active Directory C# を使用した Active Directory Sep 03, 2024 pm 03:33 PM

C# を使用した Active Directory のガイド。ここでは、Active Directory の概要と、C# での動作方法について、構文と例とともに説明します。

C# の乱数ジェネレーター C# の乱数ジェネレーター Sep 03, 2024 pm 03:34 PM

C# の乱数ジェネレーターのガイド。ここでは、乱数ジェネレーターの仕組み、擬似乱数の概念、安全な数値について説明します。

C# シリアル化 C# シリアル化 Sep 03, 2024 pm 03:30 PM

C# シリアル化のガイド。ここでは、C# シリアル化オブジェクトの導入、手順、作業、例についてそれぞれ説明します。

C# データ グリッド ビュー C# データ グリッド ビュー Sep 03, 2024 pm 03:32 PM

C# データ グリッド ビューのガイド。ここでは、SQL データベースまたは Excel ファイルからデータ グリッド ビューをロードおよびエクスポートする方法の例について説明します。

C# のパターン C# のパターン Sep 03, 2024 pm 03:33 PM

C# のパターンのガイド。ここでは、C# のパターンの概要と上位 3 種類について、その例とコード実装とともに説明します。

C# の素数 C# の素数 Sep 03, 2024 pm 03:35 PM

C# の素数ガイド。ここでは、C# における素数の導入と例を、コードの実装とともに説明します。

C# の階乗 C# の階乗 Sep 03, 2024 pm 03:34 PM

C# の Factorial のガイド。ここでは、C# での階乗の概要について、さまざまな例とコード実装とともに説明します。

マルチスレッドと非同期C#の違い マルチスレッドと非同期C#の違い Apr 03, 2025 pm 02:57 PM

マルチスレッドと非同期の違いは、マルチスレッドが複数のスレッドを同時に実行し、現在のスレッドをブロックせずに非同期に操作を実行することです。マルチスレッドは計算集約型タスクに使用されますが、非同期はユーザーインタラクションに使用されます。マルチスレッドの利点は、コンピューティングのパフォーマンスを改善することですが、非同期の利点はUIスレッドをブロックしないことです。マルチスレッドまたは非同期を選択することは、タスクの性質に依存します。計算集約型タスクマルチスレッド、外部リソースと相互作用し、UIの応答性を非同期に使用する必要があるタスクを使用します。

See all articles