以文本方式查看主题 - 中文XML论坛 - 专业的XML技术讨论区 (http://bbs.xml.org.cn/index.asp) -- 『 C/C++编程思想 』 (http://bbs.xml.org.cn/list.asp?boardid=61) ---- Getting Input from the Keyboard (http://bbs.xml.org.cn/dispbbs.asp?boardid=61&rootid=&id=70390) |
-- 作者:卷积内核 -- 发布时间:12/12/2008 10:12:00 AM -- Getting Input from the Keyboard 一篇针对键盘技术非常不错的文章,由于时间关系没有翻译,看不懂的地方大家共同讨论。 A windows application learns of keyboard events the same way it learns about mouse events: through messages. a program receives a message whenever a key is pressed or released. if you want to know when the page up or page down key is pressed so that your application can react accordingly, you process wm_keydown messages and check for key codes identifying the page up or page down key. if you'd rather know when a key is released, you process wm_keyup messages instead. for keys that produce printable characters, you can ignore key-down and key-up messages and process wm_char messages that denote characters typed at the keyboard. relying on wm_char messages instead of wm_keyup/down messages simplifies character processing by enabling windows to factor in events and circumstances surrounding the keystroke, such as whether the shift key is pressed, whether caps lock is on or off, and differences in keyboard layouts. the input focus windows notifies a window that it is about to receive or lose the input focus with wm_setfocus and wm_killfocus messages, which mfc programs process as shown here: // in cmainwindow's message map void cmainwindow::onkillfocus (cwnd* pnewwnd) an application can shift the input focus to another window with cwnd::setfocus: pwnd->setfocus (); or it can use the static cwnd::getfocus function to find out who currently has the input focus: cwnd* pfocuswnd = cwnd::getfocus (); |
-- 作者:卷积内核 -- 发布时间:12/12/2008 10:15:00 AM -- in the win32 environment, getfocus returns null if the window that owns the focus was not created by the calling thread. you can't use getfocus to get a pointer to a window created by another application, but you can use it to identify windows that belong to your application. keystroke messages all keys but two generate wm_keydown and wm_keyup messages. the two exceptions are alt and f10, which are "system" keys that have a special meaning to windows. when either of these keys is pressed and released, a window receives a wm_syskeydown message followed by a wm_syskeyup message. if other keys are pressed while the alt key is held down, they, too, generate wm_syskeydown and wm_syskeyup messages instead of wm_keydown and wm_keyup messages. pressing f10 puts windows in a special modal state that treats the next keypress as a menu shortcut. pressing f10 followed by the f key, for example, pulls down the file menu in most applications. an application processes keystroke messages by providing message-map entries and message handling functions for the messages it is interested in. wm_keydown, wm_keyup, wm_syskeydown, and wm_syskeyup messages are processed by a class's onkeydown, onkeyup, onsyskeydown, and onsyskeyup member functions, respectively. the corresponding message-map macros are on_wm_keydown, on_wm_keyup, on_wm_syskeydown, and on_wm_syskeyup. when activated, a keystroke handler receives a wealth of information about the keystroke, including a code identifying the key that was pressed or released. keystroke message handlers are prototyped as follows: afx_msg void onmsgname (uint nchar, uint nrepcnt, uint nflags) nchar is the virtual key code of the key that was pressed or released. nrepcnt is the repeat count—the number of keystrokes encoded in the message. nrepcnt is usually equal to 1 for wm_keydown or wm_syskeydown messages and is always 1 for wm_keyup or wm_syskeyup messages. if key-down messages arrive so fast that your application can't keep up, windows combines two or more wm_keydown or wm_syskeydown messages into one and increases the repeat count accordingly. most programs ignore the repeat count and treat combinatorial key-down messages (messages in which nrepcnt is greater than 1) as a single keystroke to prevent overruns—situations in which a program continues to scroll or otherwise respond to keystroke messages after the user's finger has released the key. in contrast to the pc's keyboard bios, which buffers incoming keystrokes and reports each one individually, the windows method of reporting consecutive presses of the same key to your application provides a built-in hedge against keyboard overruns. the nflags parameter contains the key's scan code and zero or more of the bit flags described here: bit(s) meaning description
|
-- 作者:卷积内核 -- 发布时间:12/12/2008 10:15:00 AM -- the extended key flag allows an application to differentiate between the duplicate keys that appear on most keyboards. on the 101-key and 102-key keyboards used with the majority of ibm-compatible pcs, the extended key flag is set for the ctrl and alt keys on the right side of the keyboard; the home, end, insert, delete, page up, page down, and arrow keys that are clustered between the main part of the keyboard and the numeric keypad; and the keypad's enter and forward-slash (/) keys. for all other keys, the extended key flag is 0. the oem scan code is an 8-bit value that identifies the key to the keyboard bios. most windows applications ignore this field because it is inherently hardware dependent. (if needed, scan codes can be translated into virtual key codes with the ::mapvirtualkey api function.) the transition state, previous key state, and context code are generally disregarded too, but they are occasionally useful. a previous key state value equal to 1 identifies typematic keystrokes—keystrokes generated when a key is pressed and held down for some length of time. holding down the shift key for a second or so, for instance, generates the following sequence of messages: message virtual key code previous key state in general, applications shouldn't process wm_syskeydown and wm_syskeyup messages; they should let windows process them instead. if these messages don't eventually find their way to ::defwindowproc, system keyboard commands such as alt-tab and alt-esc will stop working. windows puts a tremendous amount of power in your hands by routing all mouse and keyboard messages through your application first, even though many of these messages are meaningful first and foremost to the operating system. as with nonclient-area mouse messages, the improper handling of system keystroke messages—in particular, the failure to pass these messages on to the operating system—can result in all sorts of quirky behavior. virtual key codes conspicuously missing from this table are virtual key codes for the letters a through z and a through z and for the numerals 0 through 9. the virtual key codes for these keys are the same as the corresponding characters' ansi codes: 0x41 through 0x5a for a through z, 0x61 through 0x7a for a through z, and 0x30 through 0x39 for 0 through 9.
|
-- 作者:卷积内核 -- 发布时间:12/12/2008 10:31:00 AM -- if you look inside winuser.h, where the virtual key codes are defined, you'll find a few key codes that aren't listed in the following table, including vk_select, vk_execute, and vk_f13 through vk_f24. these codes are provided for use on other platforms and can't be generated on conventional ibm keyboards. nonletter and nonnumeric keys for which windows does not provide virtual key codes—for example, the semicolon (;) and square bracket ([]) keys—are best avoided when processing key-down and key-up messages because their ids can vary on international keyboards. this doesn't mean that your program can't process punctuation symbols and other characters for which no vk_ identifiers exist; it simply means that there's a better way to do it than relying on key-up and key-down messages. that "better way" is wm_char messages, which we'll discuss in a moment. virtual key codes virtual key code(s) corresponding key(s) ::getkeystate (vk_shift) |
-- 作者:卷积内核 -- 发布时间:12/12/2008 10:32:00 AM -- returns a negative value if the shift key is held down or a nonnegative value if it is not. similarly, the expression ::getkeystate (vk_control) returns a negative value if the ctrl key is held down. thus, the bracketed statements in the following code fragment taken from an onkeydown handler are executed only when ctrl-left (the left arrow key in combination with the ctrl key) is pressed: if ((nchar == vk_left) && (::getkeystate (vk_control) < 0)) { to inquire about the alt key, you can call ::getkeystate with a vk_menu parameter or simply check the context code bit in the nflags parameter. usually even that amount of effort isn't necessary because if the alt key is pressed, your window will receive a wm_syskeydown or wm_syskeyup message instead of a wm_keydown or wm_keyup message. in other words, the message id generally tells you all you need to know about the alt key. as a bonus, you can use the identifiers vk_lbutton, vk_mbutton, and vk_rbutton in conjunction with ::getkeystate to determine if any of the mouse buttons is held down. an application can also use ::getkeystate to determine whether num lock, caps lock, and scroll lock are on or off. while the high bit of the return code indicates whether a key is currently pressed (yielding a negative number when the high bit is 1), the low bit—bit 0—indicates the state of the toggle. the expression ::getkeystate (vk_numlock) & 0x01 evaluates to nonzero if num lock is on and evaluates to 0 if it is not. the same technique works for the vk_capital (caps lock) and vk_scroll (scroll lock) keys. it's important to mask off all but the lowest bit of the return code before testing because the high bit still indicates whether the key itself is up or down. in all cases, ::getkeystate reports the state of the key or the mouse button at the time the keyboard message was generated, not at the precise moment that the function is called. this is a feature, not a bug, because it means you don't have to worry about a key being released before your message handler gets around to inquiring about the key state. the ::getkeystate function should never be called outside a keyboard message handler because the information it returns is valid only after a keyboard message has been retrieved from the message queue. if you really need to know the current state of a key or a mouse button, or if you want to check a key or a mouse button outside a keyboard message handler, use ::getasynckeystate instead. character messages virtual key code vk_shift caps lock result
|
-- 作者:卷积内核 -- 发布时间:12/12/2008 10:32:00 AM -- while you might reasonably expect to overcome this problem by writing code to sense all the possible shift and toggle states, your work is complicated by the fact that the user might also have the ctrl key held down. and the problem is only compounded when your application is run outside the united states, where keyboard layouts typically differ from the u.s. keyboard layout. a u.s. user presses shift-0 to enter a right parenthesis symbol. but shift-0 produces an equal sign on most international keyboards and an apostrophe on dutch keyboards. users won't appreciate it much if the characters your program displays don't match the characters they type. that's why windows provides the ::translatemessage api function. ::translatemessage converts keystroke messages involving character keys into wm_char messages.the message loop provided by mfc calls ::translatemessage for you, so in an mfc application you don't have to do anything special to translate keystroke messages into wm_char messages. when you use wm_char messages for keyboard input, you needn't worry about virtual key codes and shift states because each wm_char message includes a character code that maps directly to a symbol in the ansi character set (windows 98) or unicode character set (windows 2000). assuming that caps lock is not turned on, pressing shift-a produces the following sequence of messages: message virtual key code character code message virtual key code character code figure 3-6 shows the characters in the ansi character set. since ansi codes are only 8 bits wide, there are only 256 possible characters. unicode uses 16-bit character codes, expanding the possible character count to 65,536. fortunately, the first 256 characters in the unicode character set and the 256 characters in the ansi character set are identical. thus, code like this: case _t (`a'): works fine with either character set.
figure 3-6. the ansi character set. an on_wm_char entry in a class's message map routes wm_char messages to the member function onchar, which is prototyped as follows: afx_msg void onchar (uint nchar, uint nrepcnt, uint nflags) nrepcnt and nflags have the same meanings that they have in keystroke messages. nchar holds an ansi or unicode character code. the following code fragment traps presses of the letter keys, the enter key, and the backspace key, all of which produce wm_char messages: // in cmainwindow's message map { if it's unclear to you whether a particular key produces a wm_char message, there's an easy way to find out. simply run the visualkb application that comes with this book and press the key. if the key produces a wm_char message, the message will appear in visualkb's window. dead-key messages you can process dead-key messages in an mfc application by including an on_wm_deadchar or on_wm_sysdeadchar entry in a message map and supplying handling functions named ondeadchar and onsysdeadchar. you'll find descriptions of these functions in the mfc documentation. the caret cwnd caret handling functions function description
|
-- 作者:卷积内核 -- 发布时间:12/12/2008 10:33:00 AM -- the caret, like the mouse cursor, is a shared resource. however, unlike the cursor, which is a global resource shared by everyone, the caret is a per-thread resource that's shared by all windows running on the same thread. to ensure proper handling, applications that use the caret should follow these simple rules: as you know, a window receives a wm_setfocus message when it receives the input focus and a wm_killfocus message when it loses the input focus. the following wm_setfocus handler creates a caret, positions it, and displays it when a window gains the input focus: void cmainwindow::onsetfocus (cwnd* pwnd) and this wm_killfocus handler saves the caret position and hides and destroys the caret when the input focus is lost: void cmainwindow::onkillfocus (cwnd* pwnd) in these examples, m_cychar holds the caret height and m_ptcaretpos holds the caret position. the caret position is saved when the focus is lost, and it is restored when the focus is regained. since only one window can have the input focus at a time and keyboard messages are directed to the window with the input focus, this approach to caret handling ensures that the window that "owns" the keyboard also owns the caret. the caret-create functions serve two purposes: defining the look of the caret and claiming ownership of the caret. the caret is actually a bitmap, so you can customize its appearance by supplying a bitmap to cwnd::createcaret. but more often than not you'll find that the easier-to-use createsolidcaret function (it's easier to use because it doesn't require a bitmap) does the job nicely. createsolidcaret creates a solid block caret that, depending on how you shape it, can look like a rectangle, a horizontal or vertical line, or something in between. in the onsetfocus example above, the statement createsolidcaret (2, m_cychar); creates a vertical-line caret 2 pixels wide whose height equals the character height of the current font (m_cychar). this is the traditional way of creating a caret for use with a proportional font, although some programs key the width of the caret to the width of a window border. you can obtain the border width by calling ::getsystemmetrics with the value sm_cxborder. for fixed-pitch fonts, you might prefer to use a block caret whose width and height equal the width and height of one character, as in createsolidcaret (m_cxchar, m_cychar); as mentioned above, it's your job to move the caret. cwnd::setcaretpos repositions the caret, accepting a cpoint object that contains the x and y client-area coordinates of the new cursor position. positioning the caret in a string of text is fairly straightforward if you're using a fixed-pitch font because you can calculate a new x offset into the string by multiplying the character position by the character width. if the font is proportionally spaced, you'll have to do a little more work. mfc's cdc::gettextextent and cdc::gettabbedtextextent functions enable an application to determine the width, in logical units, of a string of characters rendered in a proportional font. (use gettabbedtextextent if the string contains tab characters.) given a character position n, you can compute the corresponding caret position by calling gettextextent or gettabbedtextextent to find the cumulative width of the first n characters. if the string "hello, world" is displayed at the position specified by a cpoint object named point and dc is a device context object, the following statements position the caret between the "w" and "o" in "world": csize size = dc.gettextextent (_t ("hello, w"), 8); |
-- 作者:秋十三 -- 发布时间:1/2/2009 8:38:00 PM -- 我先收藏了 慢慢研究啊 |
W 3 C h i n a ( since 2003 ) 旗 下 站 点 苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》 |
125.000ms |