[操作疑難] Keyboard 問題

我用 VB Express 2010,想按 Keyboard 上不同鍵去執行不同的工作,但發覺兩個鍵有問題:NumPadEnter、F10。

初步測試,我用個 Textbox1 去收 Keyboard 的 KeyDown event,再用個 Label1 去顯示所按的鍵:
  1. Private Sub TextBox1_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles TextBox1.KeyDown        
  2.     Label1.Text = e.KeyCode.ToString & "," & e.KeyData.ToString & "," & e.KeyValue.ToString
  3. End Sub
複製代碼
不過,無論我按主 Keyboard 的 Enter 掣(Right shift 上面)或者 NumPad 的 Enter,Label1 都係出:
Return,Return,13
但係根據以下網址,NumPad 個 Enter 的 KeyValue 應該係 108。
可否分返開兩個 Enter 掣?
https://msdn.microsoft.com/en-us/library/aa243025%28v=vs.60%29.aspx

另一個有問題的鍵係 F10,按完後 Label1 會出:
F10,F10,121
但係之後再按其它掣會無反應,要按多一下 F10 或者 Esc 後才會正常顯示下一個按鍵的資料。為何會出現這問題?

原來 F10 係 Windows 預設用來開關 Menu bar。

TOP

本帖最後由 Charcoal99 於 2016-9-8 23:00 編輯

有關F10的問題, 你可以在離開 TextBox1_KeyDown 時加一句 e.Handled = Ture
通知系統不要再處理這鍵。 若有其他 HotKey 要系統處理, 也可先檢查是 F10 才加這一句。
https://msdn.microsoft.com/en-us/library/system.windows.forms.keypresseventargs.handled(v=vs.110).aspx

至於要分判 main Return 跟 numPad Return 會稍麻煩點,
這不同行為跟 DotNET 版本有關, 你所看的是 Visual Studio 6.0 的行為。
後來的 Windows Form Framework 是特意要把它們看成是一樣的,
要從更底層去攔截及處理 Windows Message.

如要截取 TextBox 的Key, 方法是 subclass TextBox class 然後 override 裡面的 WndProc() ,
截取 WM_KEYDOWN 及 WParam = 13 的 Message, 然後檢查
bit 24 的 Extended-Key Flag,
https://msdn.microsoft.com/en-us/library/windows/desktop/ms646267(v=vs.85).aspx

Form 裡面的 TextBox 要由新的 subclass 手動產生。 C# 的Code 大致如此 :
  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Data;
  5. using System.Drawing;
  6. using System.Linq;
  7. using System.Text;
  8. using System.Threading.Tasks;
  9. using System.Windows.Forms;

  10. namespace TestKey {

  11.     class MyTextBox : TextBox {
  12.         protected override void WndProc(ref Message m) {
  13.             // WM_KEYDOWN == 256, Enter == 13
  14.             if (m.Msg == 256 && m.WParam.ToInt32() == 13) {
  15.                 Console.WriteLine("{0:X}", m.LParam.ToInt32());
  16.                 if ((m.LParam.ToInt32() & 0x01000000) == 0) {
  17.                     Console.WriteLine("main Enter");
  18.                 } else {
  19.                     Console.WriteLine("numpad Enter");
  20.                 }
  21.             } else {
  22.                 base.WndProc(ref m);
  23.             }
  24.         }
  25.     }


  26.     public partial class Form1 : Form {

  27.         public Form1() {
  28.             InitializeComponent();
  29.             // 程式產生的 textBox
  30.             MyTextBox tb1 = new MyTextBox();
  31.             tb1.Name = "Test";
  32.             tb1.Text = "MyTextBox";
  33.             tb1.Location = new Point(40, 120);
  34.             tb1.Visible = true;
  35.             this.Controls.Add(tb1);
  36.         }

  37.         // Form Design 的 textBox
  38.         private void textBox1_KeyDown(object sender, KeyEventArgs e) {
  39.             label1.Text = e.KeyCode + "," + e.KeyData + "," + e.KeyValue;
  40.             e.Handled = true;
  41.         }
  42.     }
  43. }
複製代碼

TOP

回覆 3# Charcoal99

Thanks~~~~
研究下先。

TOP

F10 問題可以在 KeyDown event 內用 e.handled 或者 e.SuppressKeyPress = true 去解決。

兩個 Enter 可以用以下方法去分辨:
https://support.microsoft.com/en-us/kb/188550
http://stackoverflow.com/questions/27378049/differentiate-between-enter-keys-in-keydown-event

不過又有新問題,就係 Shift+NumPadKey 無法正常顯示。以 Num8 鍵為例:
如果 NumLock 係 On,按 Num8 可以正常顯示我按 Num8,無 Modifier。
如果 NumLock 係 Off,會顯示 Up Arrow,無 Modifier。我都可以理解。
但係無論 NumLock 係 On 或 Off,按 Shift-Num8 都一律出 Up Arrow,無 Modifier。

但我希望顯示到我實際按的鍵,即係 Num8 鍵以及 Modifier=Shift。

NumPad 0~9 以及小數點都有這問題。連帶其它帶有 Shift 的組合鍵都出問題,例如 Alt-Shift-Num8 會被當作 Up Arrow,Modifier=Alt,而不是我想要的 Num8 及 Modifier=Alt+Shift。

TOP

本帖最後由 Charcoal99 於 2016-9-16 20:47 編輯

Perhaps you should know this 「The shift key overrides NumLock
這個要追溯到 PC-XT Keyboard 的年代,當時是沒有獨立的Arrow keys 的,
為了方便雙手操作簡易切換 數定鍵及方向鍵,當NumLock On 時, 按Shift 及 NumPad 數字鍵時
NumLock模式會暫時取消, 數字鍵會自動切換成方向鍵,但當同時又按Ctrl 及/或 Alt, override 並不生效。

當CapsLock On, 按Shift 時的CapsLock Modifier 也會如此。
這個相信是底層 Keyboard driver的行為, WndProc 跟 PeekMessage 所看到的已是修改了的Modifier。

Linux 的 Keyboard Layout Preference 設定裡面還特意有一個Compatibility選項
用來模擬 Windows 這個行為的。


如若仍想按你的想法去做, 便要自行讀取 RawInput 來做自己的 modifier 了。
https://msdn.microsoft.com/en-us ... 45543(v=vs.85).aspx

TOP

Perhaps you should know this 「」
這個要追溯到 PC-XT Keyboard 的年代,當時是沒有獨立的Arrow keys 的, ...
Charcoal99 發表於 2016/9/16 18:12


Thanks again!

其實我係想好似紅外線遙控器,用電腦控制一般家電。常見的家電遙控好多都有數字鍵、四個方向箭嘴、OK…等掣,好適合用 Keyboard 的 NumPad。

以前都做過一次:
http://www.hkepc.com/forum/viewthread.php?fid=146&tid=1925091

今次想加埋 Modifier 去控制不同電器,例如無 Modifier直接按係控制數碼電視機頂盒、Hold 住 Shift 就 DVD/BD 機、Ctrl 就有線電視、Ctrl-Shift 就係 Media Player Box……如此類推。如果無得用 Shift 就即係廢了一截武功!

TOP

本帖最後由 Charcoal99 於 2016-9-17 01:37 編輯

好奇之下花了點時間追查下去,發現 shift key overrides NumLock 是個 BIOS 層級的行為。
以下是 PC BIOS 的 Assembly code
http://maben.homeip.net/static/S ... er%20source.ASM.txt
處理KEYPAD 的 code 在 K48,它會先檢查當前是否 NUM_LOCK,是的話跳到 K52,
再檢查有否按下 L_SHIFT 或 R_SHIFT,有的話它會退回 沒有NUM_LOCK 的 BASE CASE K49
不是SHIFT 的情況才會是 REALLY_NUM_STATE 的 K53. 而帶 ALT 或/及 CTRL 的都會比 K48 優先處理。

所以應該沒有簡易方法可以改變這行為,只可自行追踨 所有 Shift key 的 up/down 狀態
以此修正系統的Modifier。

TOP