Winform虛擬/模擬鍵盤

来源:https://www.cnblogs.com/lotusgu/archive/2023/05/23/17422796.html
-Advertisement-
Play Games

在使用 using 等新語法時,在 VisualStudio 2019 會自動判斷框架版本,如在 net 45 就不會自動使用最新版本的語法,需要修改項目文件 在使用 C# 8.0 之前,請在官網 下載最新的 VisualStudio 2019 版本 如果在編譯時提示 “Using 聲明”在 C# ...


項目需要在觸摸屏上增加一個虛擬鍵盤。記錄下過程中遇到的問題及解決方法。

1.模擬按鍵

網上找到如下3種方法

1)SendKeys.Send

測試單獨的shift不好用,所以最終未採納此方法

SendKeys.Send("^{E}");//shift+e
SendKeys.Send("{Enter}");

2)keybd_event

最終選擇了這個方法,簡單有效。

虛擬按鍵對照表:https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes

[DllImport("user32.dll", EntryPoint = "keybd_event", SetLastError = true)]
public static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, uint dwExtraInfo);
[DllImport("user32.dll", EntryPoint = "keybd_event", SetLastError = true)]
public static extern void keybd_event(Keys bVk, byte bScan, uint dwFlags, uint dwExtraInfo);
public static uint KEYEVENTF_KEYDOWN = 0;// 鍵按下 KEYEVENTF_KEYDOWN = 0
public static uint KEYEVENTF_KEYUP = 2;//鍵彈起 KEYEVENTF_KEYUP = 2
keybd_event(0x14, 0, KEYEVENTF_KEYDOWN, 0); //鍵按下 KEYEVENTF_KEYDOWN = 0
keybd_event(0x14, 0, KEYEVENTF_KEYUP, 0); //鍵彈起 KEYEVENTF_KEYUP = 2

3)PostMessage

這個方法也是簡單有效,但是據說有些其他問題,沒有仔細研究,有興趣的可以自己研究。

[DllImport("user32.dll", EntryPoint = "PostMessageA", SetLastError = true)]
public static extern int PostMessage(IntPtr hWnd, int Msg, Keys wParam, int lParam);

PostMessage(textBox2.Handle, 256, Keys.D, 2);//模擬按下2次 Keys.D

2.各種類型鍵的處理

微軟對鍵盤輸入有進行了分類,可以參考這個。

https://learn.microsoft.com/zh-cn/windows/win32/learnwin32/keyboard-input

1)CapsLock鍵/NumLock鍵

想要實現鍵盤按下抬起與界面效果相同,就需要捕獲鍵盤操作。我使用了Hook

以下這篇博客寫的很清晰明瞭,就不贅述了。

https://www.cnblogs.com/chorm590/p/14199978.html

在hook回調函數中做瞭如下處理

private int keyboardHookCallback(int code, IntPtr wParam, IntPtr lParam)
{
  if (code < 0)
    {
       return User32.CallNextHookEx(IntPtr.Zero, code, wParam, lParam);
    }
   else
   {
     Keyboard_LL_Hook_Data khd = (Keyboard_LL_Hook_Data)Marshal.PtrToStructure(lParam, typeof(Keyboard_LL_Hook_Data));
      System.Diagnostics.Debug.WriteLine($"key event:{wParam}, key code:{khd.vkCode}, event time:{khd.time}");
      if ((int)wParam == 256 && khd.vkCode == 0x14)
      {
        IsCapsLockDown = !IsCapsLockDown;
      }
      return User32.CallNextHookEx(IntPtr.Zero, code, wParam, lParam);
   }
}
private bool isCapsLockDown;
private bool IsCapsLockDown
{
  get { return isCapsLockDown; }
   set
    {
      isCapsLockDown = value;
       this.buttonCapsLock.BackColor = value ? Color.Gray : Control.DefaultBackColor;
    }
}
private void buttonCapsLock_Click(object sender, EventArgs e)
{
  User32.keybd_event(VirtualKeyCode.CAPS_LOCK, 0, 0, 0);   //鍵按下 KEYEVENTF_KEYDOWN = 0
   User32.keybd_event(VirtualKeyCode.CAPS_LOCK, 0, 2, 0);  //鍵彈起 KEYEVENTF_KEYUP = 2
}

初始化時同步鍵盤CapsLock/NumLock狀態,使用user32.GetKeyState.返回值等於1則按下狀態

[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern short GetKeyState(int keyCode);
public static bool GetState(byte VKeyCode)
{
   return (User32.GetKeyState(VKeyCode) == 1);
}

2)其他組合鍵處理

ctrl+shift切換輸入法,只響應這一種功能鍵+功能鍵。其他小伙伴有好的方法可以分享一下。

3)輸入鍵+組合鍵

如ctrl+c,ctrl+v,ctrl+a,ctrl+z等等。

此方法不是最優方式,可以改進功能鍵存放在Queue中,遍歷功能鍵,按順序響應。

private void HandleKeysCombin(byte VKCode)
{
  //設置焦點控制項
   this.ActiveControl = this.m_CustomActiveControl;
   lock (this)
   {
     if (IsCtrlDown)
      {
        keybd_event(VirtualKeyCode.CTRL, 0, KEYEVENTF_KEYDOWN, 0);                //鍵按下 KEYEVENTF_KEYDOWN = 0
      }
      if (IsShiftDown)
      {
        keybd_event(VirtualKeyCode.SHIFT, 0, KEYEVENTF_KEYDOWN, 0);                //鍵按下 KEYEVENTF_KEYDOWN = 0
      }
      if (IsAltDown)
      {
        keybd_event(VirtualKeyCode.ALT, 0, KEYEVENTF_KEYDOWN, 0);                //鍵按下 KEYEVENTF_KEYDOWN = 0
      }
      keybd_event(VKCode, VKCode, User32.KEYEVENTF_KEYDOWN, 0);                //鍵按下 KEYEVENTF_KEYDOWN = 0
      keybd_event(VKCode, VKCode, User32.KEYEVENTF_KEYUP, 0);           //鍵彈起 KEYEVENTF_KEYUP = 2
      if (IsCtrlDown)
      {
        keybd_event(VirtualKeyCode.CTRL, 0, KEYEVENTF_KEYUP, 0);                //鍵彈起 KEYEVENTF_KEYUP = 2
         IsCtrlDown = false;
      }
      if (IsShiftDown)
      {
        keybd_event(VirtualKeyCode.SHIFT, 0, KEYEVENTF_KEYUP, 0);              //鍵彈起 KEYEVENTF_KEYUP = 2
         IsShiftDown = false;
      }
      if (IsAltDown)
      {
         keybd_event(VirtualKeyCode.ALT, 0, KEYEVENTF_KEYUP, 0);                //鍵彈起 KEYEVENTF_KEYUP = 2
        IsAltDown = false;
     }
  }
}

3.窗體/UserControl焦點的處理

這篇裡面方法簡單好用,不贅述

 https://blog.csdn.net/accomp/article/details/7209052


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 有時間,我們在搭建微服務時,總希望拿一個比較單純的,沒有污染其它代碼的項目來從頭開始做,今天我們來建設一個最簡單的,gateway項目,它被註冊到nacos里,路由配置也存到nacos里,動態實現更新配置功能。 # 依賴配置 > 版本:com.alibaba.cloud:spring-cloud-s ...
  • 摘要:常用於消除雜訊的圖像平滑方法包括三種線性濾波(均值濾波、方框濾波、高斯濾波)和兩種非線性濾波(中值濾波、雙邊濾波),本文將詳細講解三種線性濾波方法。 本文分享自華為雲社區《[Python從零到壹] 五十五.圖像增強及運算篇之圖像平滑(均值濾波、方框濾波、高斯濾波)》,作者:eastmount。 ...
  • 學習的文章 [小姐姐非要問我:spring編程式事務是啥? (qq.com)](https://mp.weixin.qq.com/s?__biz=MzA5MTkxMDQ4MQ==&mid=2648936779&idx=2&sn=a6255c7d436a62af380dfa6b326fd4e7&chk ...
  • Java applet 不知道有同學聽過嗎?我也只是聽過,並沒有使用過。我特意去瞭解了一下它,本文就對 Java applet 進行簡單介紹,說說它的輝煌與衰敗。僅此而已,現在已經沒人使用 Java applet 開發了。 ...
  • ## 1、概述 我們常說的JMM指的是Java記憶體模型(Java Memory Model,JMM),主要用於控制Java程式解決線程間如何通信和數據同步,JMM規範了多線程訪問共用記憶體時的 **可見性、有序性和原子性**。 - 所有的共用變數都存在**主記憶體**中; - **每個線程**都保存了一 ...
  • 以前就是一直使用 `Newtonsoft.Json` 用起來還是挺舒服的。由於 JSON 的應用越來越廣,現在. NET Core 都內置了 `System.Text.Json` 可以直接對 JSON 進行操作,不過兩個東西的體驗依然有點區別。 有時候我們會遇到的從第三方傳遞過來的 json str ...
  • C# 讀取網路上下行有多種方式,其中有一種是使用System.Net.NetworkInformation命名空間中的NetworkInterface類和PerformanceCounter類,該方式其實讀的是windows系統的性能計數器中的Network Interface類別的數據。 方式如下 ...
  • 遞歸演算法本質: 1、方法的自我調用 2、有明確的終止條件 3、每次調用時,問題規模在不斷減少。通過遞減,最終到達終止條件 ...
一周排行
    -Advertisement-
    Play Games
  • PasteSpider是什麼? 一款使用.net編寫的開源的Linux容器部署助手,支持一鍵發佈,平滑升級,自動伸縮, Key-Value配置,項目網關,環境隔離,運行報表,差量升級,私有倉庫,集群部署,版本管理等! 30分鐘上手,讓開發也可以很容易的學會在linux上部署你得項目! [從需求角度介 ...
  • SQLSugar是什麼 **1. 輕量級ORM框架,專為.NET CORE開發人員設計,它提供了簡單、高效的方式來處理資料庫操作,使開發人員能夠更輕鬆地與資料庫進行交互 2. 簡化資料庫操作和數據訪問,允許開發人員在C#代碼中直接操作資料庫,而不需要編寫複雜的SQL語句 3. 支持多種資料庫,包括但 ...
  • 在C#中,經常會有一些耗時較長的CPU密集型運算,因為如果直接在UI線程執行這樣的運算就會出現UI不響應的問題。解決這類問題的主要途徑是使用多線程,啟動一個後臺線程,把運算操作放在這個後臺線程中完成。但是原生介面的線程操作有一些難度,如果要更進一步的去完成線程間的通訊就會難上加難。 因此,.NET類 ...
  • 一:背景 1. 講故事 前些天有位朋友在微信上丟了一個崩潰的dump給我,讓我幫忙看下為什麼出現了崩潰,在 Windows 的事件查看器上顯示的是經典的 訪問違例 ,即 c0000005 錯誤碼,不管怎麼說有dump就可以上windbg開幹了。 二:WinDbg 分析 1. 程式為誰崩潰了 在 Wi ...
  • CSharpe中的IO+NPOI+序列化 文件文件夾操作 學習一下常見的文件、文件夾的操作。 什麼是IO流? I:就是input O:就是output,故稱:輸入輸出流 將數據讀入記憶體或者記憶體輸出的過程。 常見的IO流操作,一般說的是[記憶體]與[磁碟]之間的輸入輸出。 作用 持久化數據,保證數據不再 ...
  • C#.NET與JAVA互通之MD5哈希V2024 配套視頻: 要點: 1.計算MD5時,SDK自帶的計算哈希(ComputeHash)方法,輸入輸出參數都是byte數組。就涉及到字元串轉byte數組轉換時,編碼選擇的問題。 2.輸入參數,字元串轉byte數組時,編碼雙方要統一,一般為:UTF-8。 ...
  • CodeWF.EventBus,一款靈活的事件匯流排庫,實現模塊間解耦通信。支持多種.NET項目類型,如WPF、WinForms、ASP.NET Core等。採用簡潔設計,輕鬆實現事件的發佈與訂閱。通過有序的消息處理,確保事件得到妥善處理。簡化您的代碼,提升系統可維護性。 ...
  • 一、基本的.NET框架概念 .NET框架是一個由微軟開發的軟體開發平臺,它提供了一個運行時環境(CLR - Common Language Runtime)和一套豐富的類庫(FCL - Framework Class Library)。CLR負責管理代碼的執行,而FCL則提供了大量預先編寫好的代碼, ...
  • 本章將和大家分享在ASP.NET Core中如何使用高級客戶端NEST來操作我們的Elasticsearch。 NEST是一個高級別的Elasticsearch .NET客戶端,它仍然非常接近原始Elasticsearch API的映射。所有的請求和響應都是通過類型來暴露的,這使得它非常適合快速上手 ...
  • 參考delphi的代碼更改為C# Delphi 檢測密碼強度 規則(仿 google) 仿 google 評分規則 一、密碼長度: 5 分: 小於等於 4 個字元 10 分: 5 到 7 字元 25 分: 大於等於 8 個字元 二、字母: 0 分: 沒有字母 10 分: 全都是小(大)寫字母 20 ...