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
  • 概述:在C#中,++i和i++都是自增運算符,其中++i先增加值再返回,而i++先返回值再增加。應用場景根據需求選擇,首碼適合先增後用,尾碼適合先用後增。詳細示例提供清晰的代碼演示這兩者的操作時機和實際應用。 在C#中,++i 和 i++ 都是自增運算符,但它們在操作上有細微的差異,主要體現在操作的 ...
  • 上次發佈了:Taurus.MVC 性能壓力測試(ap 壓測 和 linux 下wrk 壓測):.NET Core 版本,今天計劃準備壓測一下 .NET 版本,來測試並記錄一下 Taurus.MVC 框架在 .NET 版本的性能,以便後續持續優化改進。 為了方便對比,本文章的電腦環境和測試思路,儘量和... ...
  • .NET WebAPI作為一種構建RESTful服務的強大工具,為開發者提供了便捷的方式來定義、處理HTTP請求並返迴響應。在設計API介面時,正確地接收和解析客戶端發送的數據至關重要。.NET WebAPI提供了一系列特性,如[FromRoute]、[FromQuery]和[FromBody],用 ...
  • 原因:我之所以想做這個項目,是因為在之前查找關於C#/WPF相關資料時,我發現講解圖像濾鏡的資源非常稀缺。此外,我註意到許多現有的開源庫主要基於CPU進行圖像渲染。這種方式在處理大量圖像時,會導致CPU的渲染負擔過重。因此,我將在下文中介紹如何通過GPU渲染來有效實現圖像的各種濾鏡效果。 生成的效果 ...
  • 引言 上一章我們介紹了在xUnit單元測試中用xUnit.DependencyInject來使用依賴註入,上一章我們的Sample.Repository倉儲層有一個批量註入的介面沒有做單元測試,今天用這個示例來演示一下如何用Bogus創建模擬數據 ,和 EFCore 的種子數據生成 Bogus 的優 ...
  • 一、前言 在自己的項目中,涉及到實時心率曲線的繪製,項目上的曲線繪製,一般很難找到能直接用的第三方庫,而且有些還是定製化的功能,所以還是自己繪製比較方便。很多人一聽到自己畫就害怕,感覺很難,今天就分享一個完整的實時心率數據繪製心率曲線圖的例子;之前的博客也分享給DrawingVisual繪製曲線的方 ...
  • 如果你在自定義的 Main 方法中直接使用 App 類並啟動應用程式,但發現 App.xaml 中定義的資源沒有被正確載入,那麼問題可能在於如何正確配置 App.xaml 與你的 App 類的交互。 確保 App.xaml 文件中的 x:Class 屬性正確指向你的 App 類。這樣,當你創建 Ap ...
  • 一:背景 1. 講故事 上個月有個朋友在微信上找到我,說他們的軟體在客戶那邊隔幾天就要崩潰一次,一直都沒有找到原因,讓我幫忙看下怎麼回事,確實工控類的軟體環境複雜難搞,朋友手上有一個崩潰的dump,剛好丟給我來分析一下。 二:WinDbg分析 1. 程式為什麼會崩潰 windbg 有一個厲害之處在於 ...
  • 前言 .NET生態中有許多依賴註入容器。在大多數情況下,微軟提供的內置容器在易用性和性能方面都非常優秀。外加ASP.NET Core預設使用內置容器,使用很方便。 但是筆者在使用中一直有一個頭疼的問題:服務工廠無法提供請求的服務類型相關的信息。這在一般情況下並沒有影響,但是內置容器支持註冊開放泛型服 ...
  • 一、前言 在項目開發過程中,DataGrid是經常使用到的一個數據展示控制項,而通常表格的最後一列是作為操作列存在,比如會有編輯、刪除等功能按鈕。但WPF的原始DataGrid中,預設只支持固定左側列,這跟大家習慣性操作列放最後不符,今天就來介紹一種簡單的方式實現固定右側列。(這裡的實現方式參考的大佬 ...