6 3 字元訊息

2021-07-16 19:15:56 字數 4729 閱讀 5727

摘錄於《windows程式(第5版,珍藏版).charles.petzold 著》p176

在本章前面講過,通過轉義狀態資訊可把擊鍵訊息轉換為字元訊息。並且提到,僅僅利用轉義狀態資訊是不夠的:還必須知道與國家/地區相關的鍵盤配置。由於這個原因,你不應該自己完成從擊鍵訊息到字元訊息的轉換。windows 將為你完成這一任務。在前面你已經看到過下面的**:

[cpp]view plain

copy

while

(getmessage (&msg, null, 0, 0))    

這是 winmain 函式中典型的訊息迴圈。getmessage 函式從訊息佇列中取出下一條訊息,填入 msg 結構的字段。dispatchmessage 函式呼叫此訊息的視窗過程。

在這兩個函式之間是 transaltemessage 函式,它負責把擊鍵訊息轉換為字元訊息。如果擊鍵訊息是 wm_keydown 或 wm_syskeydown,且擊鍵和轉義狀態組合產生了乙個字元,則 translatemessage 函式把字元訊息放入應用程式的訊息佇列。這個字元訊息將被放在擊鍵訊息之後,getmessage 函式可從訊息佇列中獲取此字元訊息。

字元訊息可分為四類。

字元死字元

非系統字元

wm_char

wm_deadchar

系統字元

wm_syschar

wm_sysdeadchar

wm_char 訊息和 wm_deadchar 訊息來自於 wm_keydown 訊息。而 wm_syschar 訊息和 wm_sysdeadchar 訊息來自於 wm_syskeydown 訊息。

有乙個好訊息:大多數情況下,windows 程式會忽略其他三種字元訊息,僅處理 wm_char 訊息。四類字元訊息中的 lparam 引數和產生此字元碼訊息的擊鍵訊息中的 lparam 引數是一樣的。但是,wparam 引數不是虛擬鍵**。實際上,它是 ansi 或 unicode 字元碼。

這些字元訊息是我們遇到的將文字傳遞給視窗過程的第乙個訊息。但它們絕不是唯一的乙個。其他字元訊息是將以零結束的文字串傳遞給視窗過程的訊息。視窗過程怎麼知道哪些字元資料是 8 位的 ansi 字元編碼,哪些是 16 位的 unicode 字元編碼呢?很簡單,任何視窗過程,只要包含用 registerclassa(registerclass 的 ansi 版本)註冊的視窗類,就得到包含 ansi 字元編碼的訊息。若包含用 registerclassw(registerclass 的寬字元版本)註冊的視窗類,則得到 unicode 字元編碼的訊息。如果你的程式用 registerclass 註冊視窗類,且 unicode 識別符號被定義,則你使用的實際是 registerclassw;否則為 registerclassa。

除非你明確地對視窗過程做了 ansi 和 unicode 函式的混合編碼,否則 wm_char 訊息(以及其他三個字元訊息)所傳遞的字元碼是:

[cpp]view plain

copy

(tchar

) wparam  

同乙個視窗過程可能會用到兩個視窗類,乙個用 registerclassa 註冊,另乙個用 registerclassw 註冊。這意味著視窗過程會接收到用 ansi 字元編碼的訊息和用 unicode 字元編碼的訊息。如果你的視窗過程需要確認是哪種字元編碼,它能呼叫:

[cpp]view plain

copy

funicode = iswindowunicode(hwnd);  

如果 hwnd 的視窗過程獲得 unicode 訊息,則 funicode 變數為 true。這意味著此視窗基於用 registerclassw 註冊的視窗類。

因為 translatemessage 函式從 wm_keydown 和 wm_syskeydown 訊息產生字元訊息,所以字元訊息夾在擊鍵訊息中傳給視窗過程。例如,如果 caps lock 鍵沒有鎖定,則在你按下再釋放 a 鍵時,相應的視窗過程會接收以下三個訊息:

訊息擊鍵或**

wm_keydown

『a』的虛擬鍵** (0x41)

wm_char

『a』的字元編碼 (0x61)

wm_keyup

『a』的虛擬鍵** (0x41)

如果你通過以下幾步輸入大寫字母 a:按下 shift 鍵,再按下 a 鍵,釋放 a 鍵,再釋放 shift 鍵,則視窗過程接收五個訊息:

訊息擊鍵或**

wm_keydown

虛擬鍵** vk_shift (0x10)

wm_keydown

『a』的虛擬鍵** (0x41)

wm_char

『a』的字元編碼 (0x41)

wm_keyup

『a』的虛擬鍵** (0x41)

wm_keyup

虛擬鍵** vk_shift (0x10)

shift 鍵本身不會產生字元訊息。

如果你持續按住 a 鍵,使連續擊鍵行為產生了擊鍵訊息,則對於每一條 wm_keydown 訊息,可以得到乙個字元訊息:

訊息擊鍵或**

wm_keydown

『a』的虛擬鍵** (0x41)

wm_char

『a'的字元編碼 (0x61)

wm_keydown

『a』的虛擬鍵** (0x41)

wm_char

『a'的字元編碼 (0x61)

wm_keydown

『a』的虛擬鍵** (0x41)

wm_char

『a'的字元編碼 (0x61)

wm_keydown

『a』的虛擬鍵** (0x41)

wm_char

『a'的字元編碼 (0x61)

wm_keyup

『a』的虛擬鍵** (0x41)

如果某些 wm_keydown 訊息的重複計數大於 1,則相應的 wm_char 訊息將具有同樣的重複計數值。

ctrl 鍵和字母鍵的組合會產生 ascii 控制字元,範圍從 0x01(ctrl-a)到 0x1a(ctrl-z)。其中某些控制碼也可由下表中的擊鍵產生:

擊  鍵

字  符  碼

產生方法

ansi c 轉義碼

空格鍵0x08

ctrl-h

\btab 鍵

0x09

ctrl-i

\tctrl+回車

0x0a

ctrl-j

\n回車鍵

0x0d

ctrl-m

\resc 鍵

0x1b

ctrl-[

最後面一列顯示了在 ansi c 中定義的轉義碼,用來表明這些鍵的字元碼。

windows 程式有時採用 ctrl 鍵和字母鍵的組合作為選單快捷鍵。在這種情況下,字母鍵不能轉換為字元訊息。

我們按照以下的基本規則來處理擊鍵和字元訊息:如果你需要讀取輸入到視窗中的鍵盤字元,就處理 wm_char 訊息;如果你需要讀取游標鍵、功能鍵、delete 鍵、insert 鍵、shift 鍵、ctrl 鍵和 alt 鍵,則處理 wm_keydown 訊息。

但是 tab 鍵怎麼辦?回車鍵、空格鍵、esc 鍵呢?從傳統意義上講,這些鍵產生 ascii 控制字元,像上表所顯示的那樣。但是在 windows 中,它們也產生虛擬鍵**。這些鍵應該在處理 wm_char 訊息或者在處理 wm_keydown 訊息時被處理嗎?

經過十年的考慮(回顧我寫過的 windows 程式),我更偏向把 tab 鍵、回車鍵、空格鍵和 esc 鍵看作控制字元,而不是虛擬鍵。我通常這樣處理 wm_char 訊息:

[cpp]view plain

copy

case

wm_char:  

[other program lines]  

switch

(wparam)  

return

0;  

windows 程式通常忽略 wm_deadchar 和 wm_sysdeadchar 訊息,但是你應該明確地了解什麼是死字元和它們怎樣工作的。

在一些非美國英語的鍵盤上,某些鍵可以給字母加上音調。這些鍵稱為「死鍵」,因為它們自己不產生字元

。例如,當安裝了德語鍵盤時,對於美國式鍵盤上的+/=鍵,德語鍵盤上相應的位置為乙個死鍵:當按下 shift 鍵時,它為沉音符(ˋ);釋放 shift 鍵時,它為尖音符()。

當使用者按下此鍵時,相應的視窗過程會接收到 wparam 引數等於音調本身的 ascii 或 unicode 碼的 wm_deadchar 訊息。若接著按下可帶有音調的字母鍵時(例如 a 鍵),視窗過程接收到的將是 wparam 引數等於帶有音調的字母「a」的 ansi 碼的 wm_char 訊息。

因而,你的程式不必去處理 wm_deadchar 訊息,因為wm_char 訊息已經包含了程式所需要的所有資訊

。windows 邏輯甚至有內建的差錯處理:如果你按下死鍵,接著按下不能攜帶音調的字母鍵(如 『s』 鍵),那麼視窗過程會連續接收到兩個 wm_char 訊息——第乙個訊息的 wparam 引數等於音調本身的 ascii 碼(與傳遞給 wm_deadchar 訊息的 wparam 引數相同),第二個訊息的 wparam 引數等於字母「s」的 ascii 碼。

當然,理解它的最好方式就是實際操作。你需要載入使用死鍵的非英語鍵盤,比如我前面描述過的德國鍵盤。你可在控制面板中通過選擇【鍵盤】中的【語言】選項卡來設定。然後你需要乙個應用程式,它能顯示程式接收的每乙個鍵盤訊息的細節。

Ex6 3字串的連線

include 字串的連線 void main for i 0 c2 i 0 i c2元素的最大下標存在n2裡,即長度 1 for i 0 i n1 i c1裡的有效字元先給c3 for i 0 i n2 i c2接著上面的賦值給c3 int temp n1 i 1 c3 temp 0 不加這兩行,...

38 字元中的唯一字元

原題目 給定乙個字串,找到它的第乙個不重複的字元,並返回它的索引。如果不存在,則返回 1。示例 s leetcode 返回 0 s loveleetcode 返回 2 思路 用for迴圈遍歷每乙個元素,然後用find函式從前到後尋找這個元素並返回這個元素所在的位置,用rfind從後到錢尋找這個元素並...

021 字元陣列

021 字元陣列 以字元陣列為基礎做簡單的文版編輯器,該程式出入文字行直至遇到 乙個空行為止,而後每次乙個字元重新顯示各行。出語言精彩程式設計百例 第21 include define max 100 define len 80 void main char text max len registe...