PageRenderTime 26ms CodeModel.GetById 1ms app.highlight 21ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/llwindow/llkeyboardwin32.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 405 lines | 272 code | 47 blank | 86 comment | 49 complexity | fc663d60a73e7f85dcd9c85cdbc7080a MD5 | raw file
  1/** 
  2 * @file llkeyboardwin32.cpp
  3 * @brief Handler for assignable key bindings
  4 *
  5 * $LicenseInfo:firstyear=2001&license=viewerlgpl$
  6 * Second Life Viewer Source Code
  7 * Copyright (C) 2010, Linden Research, Inc.
  8 * 
  9 * This library is free software; you can redistribute it and/or
 10 * modify it under the terms of the GNU Lesser General Public
 11 * License as published by the Free Software Foundation;
 12 * version 2.1 of the License only.
 13 * 
 14 * This library is distributed in the hope that it will be useful,
 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 17 * Lesser General Public License for more details.
 18 * 
 19 * You should have received a copy of the GNU Lesser General Public
 20 * License along with this library; if not, write to the Free Software
 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 22 * 
 23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 24 * $/LicenseInfo$
 25 */
 26
 27#if LL_WINDOWS
 28
 29#include "linden_common.h"
 30
 31#define WIN32_LEAN_AND_MEAN
 32#include <winsock2.h>
 33#include <windows.h>
 34
 35#include "llkeyboardwin32.h"
 36
 37#include "llwindowcallbacks.h"
 38
 39
 40
 41LLKeyboardWin32::LLKeyboardWin32()
 42{
 43	// Set up key mapping for windows - eventually can read this from a file?
 44	// Anything not in the key map gets dropped
 45	// Add default A-Z
 46
 47	// Virtual key mappings from WinUser.h
 48
 49	KEY cur_char;
 50	for (cur_char = 'A'; cur_char <= 'Z'; cur_char++)
 51	{
 52		mTranslateKeyMap[cur_char] = (KEY)cur_char;
 53	}
 54
 55	for (cur_char = '0'; cur_char <= '9'; cur_char++)
 56	{
 57		mTranslateKeyMap[cur_char] = (KEY)cur_char;
 58	}
 59	// numpad number keys
 60	for (cur_char = 0x60; cur_char <= 0x69; cur_char++)
 61	{
 62		mTranslateKeyMap[cur_char] = (KEY)('0' + (cur_char - 0x60));
 63	}
 64
 65
 66	mTranslateKeyMap[VK_SPACE] = ' ';
 67	mTranslateKeyMap[VK_OEM_1] = ';';
 68	// When the user hits, for example, Ctrl-= as a keyboard shortcut,
 69	// Windows generates VK_OEM_PLUS.  This is true on both QWERTY and DVORAK
 70	// keyboards in the US.  Numeric keypad '+' generates VK_ADD below.
 71	// Thus we translate it as '='.
 72	// Potential bug: This may not be true on international keyboards. JC
 73	mTranslateKeyMap[VK_OEM_PLUS]   = '=';
 74	mTranslateKeyMap[VK_OEM_COMMA]  = ',';
 75	mTranslateKeyMap[VK_OEM_MINUS]  = '-';
 76	mTranslateKeyMap[VK_OEM_PERIOD] = '.';
 77	mTranslateKeyMap[VK_OEM_2] = '/';//This used to be KEY_PAD_DIVIDE, but that breaks typing into text fields in media prims
 78	mTranslateKeyMap[VK_OEM_3] = '`';
 79	mTranslateKeyMap[VK_OEM_4] = '[';
 80	mTranslateKeyMap[VK_OEM_5] = '\\';
 81	mTranslateKeyMap[VK_OEM_6] = ']';
 82	mTranslateKeyMap[VK_OEM_7] = '\'';
 83	mTranslateKeyMap[VK_ESCAPE] = KEY_ESCAPE;
 84	mTranslateKeyMap[VK_RETURN] = KEY_RETURN;
 85	mTranslateKeyMap[VK_LEFT] = KEY_LEFT;
 86	mTranslateKeyMap[VK_RIGHT] = KEY_RIGHT;
 87	mTranslateKeyMap[VK_UP] = KEY_UP;
 88	mTranslateKeyMap[VK_DOWN] = KEY_DOWN;
 89	mTranslateKeyMap[VK_BACK] = KEY_BACKSPACE;
 90	mTranslateKeyMap[VK_INSERT] = KEY_INSERT;
 91	mTranslateKeyMap[VK_DELETE] = KEY_DELETE;
 92	mTranslateKeyMap[VK_SHIFT] = KEY_SHIFT;
 93	mTranslateKeyMap[VK_CONTROL] = KEY_CONTROL;
 94	mTranslateKeyMap[VK_MENU] = KEY_ALT;
 95	mTranslateKeyMap[VK_CAPITAL] = KEY_CAPSLOCK;
 96	mTranslateKeyMap[VK_HOME] = KEY_HOME;
 97	mTranslateKeyMap[VK_END] = KEY_END;
 98	mTranslateKeyMap[VK_PRIOR] = KEY_PAGE_UP;
 99	mTranslateKeyMap[VK_NEXT] = KEY_PAGE_DOWN;
100	mTranslateKeyMap[VK_TAB] = KEY_TAB;
101	mTranslateKeyMap[VK_ADD] = KEY_ADD;
102	mTranslateKeyMap[VK_SUBTRACT] = KEY_SUBTRACT;
103	mTranslateKeyMap[VK_MULTIPLY] = KEY_MULTIPLY;
104	mTranslateKeyMap[VK_DIVIDE] = KEY_DIVIDE;
105	mTranslateKeyMap[VK_F1] = KEY_F1;
106	mTranslateKeyMap[VK_F2] = KEY_F2;
107	mTranslateKeyMap[VK_F3] = KEY_F3;
108	mTranslateKeyMap[VK_F4] = KEY_F4;
109	mTranslateKeyMap[VK_F5] = KEY_F5;
110	mTranslateKeyMap[VK_F6] = KEY_F6;
111	mTranslateKeyMap[VK_F7] = KEY_F7;
112	mTranslateKeyMap[VK_F8] = KEY_F8;
113	mTranslateKeyMap[VK_F9] = KEY_F9;
114	mTranslateKeyMap[VK_F10] = KEY_F10;
115	mTranslateKeyMap[VK_F11] = KEY_F11;
116	mTranslateKeyMap[VK_F12] = KEY_F12;
117	mTranslateKeyMap[VK_CLEAR] = KEY_PAD_CENTER;
118
119	// Build inverse map
120	std::map<U16, KEY>::iterator iter;
121	for (iter = mTranslateKeyMap.begin(); iter != mTranslateKeyMap.end(); iter++)
122	{
123		mInvTranslateKeyMap[iter->second] = iter->first;
124	}
125
126	// numpad map
127	mTranslateNumpadMap[0x60] = KEY_PAD_INS;	// keypad 0
128	mTranslateNumpadMap[0x61] = KEY_PAD_END;	// keypad 1
129	mTranslateNumpadMap[0x62] = KEY_PAD_DOWN;	// keypad 2
130	mTranslateNumpadMap[0x63] = KEY_PAD_PGDN;	// keypad 3
131	mTranslateNumpadMap[0x64] = KEY_PAD_LEFT;	// keypad 4
132	mTranslateNumpadMap[0x65] = KEY_PAD_CENTER;	// keypad 5
133	mTranslateNumpadMap[0x66] = KEY_PAD_RIGHT;	// keypad 6
134	mTranslateNumpadMap[0x67] = KEY_PAD_HOME;	// keypad 7
135	mTranslateNumpadMap[0x68] = KEY_PAD_UP;		// keypad 8
136	mTranslateNumpadMap[0x69] = KEY_PAD_PGUP;	// keypad 9
137	mTranslateNumpadMap[0x6A] = KEY_PAD_MULTIPLY;	// keypad *
138	mTranslateNumpadMap[0x6B] = KEY_PAD_ADD;	// keypad +
139	mTranslateNumpadMap[0x6D] = KEY_PAD_SUBTRACT;	// keypad -
140	mTranslateNumpadMap[0x6E] = KEY_PAD_DEL;	// keypad .
141	mTranslateNumpadMap[0x6F] = KEY_PAD_DIVIDE;	// keypad /
142
143	for (iter = mTranslateNumpadMap.begin(); iter != mTranslateNumpadMap.end(); iter++)
144	{
145		mInvTranslateNumpadMap[iter->second] = iter->first;
146	}
147}
148
149// Asynchronously poll the control, alt and shift keys and set the
150// appropriate states.
151// Note: this does not generate edges.
152void LLKeyboardWin32::resetMaskKeys()
153{
154	// GetAsyncKeyState returns a short and uses the most significant
155	// bit to indicate that the key is down.
156	if (GetAsyncKeyState(VK_SHIFT) & 0x8000)
157	{
158		mKeyLevel[KEY_SHIFT] = TRUE;
159	}
160
161	if (GetAsyncKeyState(VK_CONTROL) & 0x8000)
162	{
163		mKeyLevel[KEY_CONTROL] = TRUE;
164	}
165
166	if (GetAsyncKeyState(VK_MENU) & 0x8000)
167	{
168		mKeyLevel[KEY_ALT] = TRUE;
169	}
170}
171
172
173//void LLKeyboardWin32::setModifierKeyLevel( KEY key, BOOL new_state )
174//{
175//	if( mKeyLevel[key] != new_state )
176//	{
177//		mKeyLevelFrameCount[key] = 0;
178//
179//		if( new_state )
180//		{
181//			mKeyLevelTimer[key].reset();
182//		}
183//		mKeyLevel[key] = new_state;
184//	}
185//}
186
187
188MASK LLKeyboardWin32::updateModifiers()
189{
190	//RN: this seems redundant, as we should have already received the appropriate
191	// messages for the modifier keys
192
193	// Scan the modifier keys as of the last Windows key message
194	// (keydown encoded in high order bit of short)
195	mKeyLevel[KEY_CAPSLOCK] = (GetKeyState(VK_CAPITAL) & 0x0001) != 0; // Low order bit carries the toggle state.
196	// Get mask for keyboard events
197	MASK mask = currentMask(FALSE);
198	return mask;
199}
200
201
202// mask is ignored, except for extended flag -- we poll the modifier keys for the other flags
203BOOL LLKeyboardWin32::handleKeyDown(const U16 key, MASK mask)
204{
205	KEY		translated_key;
206	U32		translated_mask;
207	BOOL	handled = FALSE;
208
209	translated_mask = updateModifiers();
210
211	if (translateExtendedKey(key, mask, &translated_key))
212	{
213		handled = handleTranslatedKeyDown(translated_key, translated_mask);
214	}
215
216	return handled;
217}
218
219// mask is ignored, except for extended flag -- we poll the modifier keys for the other flags
220BOOL LLKeyboardWin32::handleKeyUp(const U16 key, MASK mask)
221{
222	KEY		translated_key;
223	U32		translated_mask;
224	BOOL	handled = FALSE;
225
226	translated_mask = updateModifiers();
227
228	if (translateExtendedKey(key, mask, &translated_key))
229	{
230		handled = handleTranslatedKeyUp(translated_key, translated_mask);
231	}
232
233	return handled;
234}
235
236
237MASK LLKeyboardWin32::currentMask(BOOL)
238{
239	MASK mask = MASK_NONE;
240
241	if (mKeyLevel[KEY_SHIFT])		mask |= MASK_SHIFT;
242	if (mKeyLevel[KEY_CONTROL])		mask |= MASK_CONTROL;
243	if (mKeyLevel[KEY_ALT])			mask |= MASK_ALT;
244
245	return mask;
246}
247
248
249void LLKeyboardWin32::scanKeyboard()
250{
251	S32 key;
252	MSG	msg;
253	BOOL pending_key_events = PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_NOREMOVE | PM_NOYIELD);
254	for (key = 0; key < KEY_COUNT; key++)
255	{
256		// On Windows, verify key down state. JC
257		// RN: only do this if we don't have further key events in the queue
258		// as otherwise there might be key repeat events still waiting for this key we are now dumping
259		if (!pending_key_events && mKeyLevel[key])
260		{
261			// *TODO: I KNOW there must be a better way of
262			// interrogating the key state than this, using async key
263			// state can cause ALL kinds of bugs - Doug
264			if (key < KEY_BUTTON0)
265			{
266				// ...under windows make sure the key actually still is down.
267				// ...translate back to windows key
268				U16 virtual_key = inverseTranslateExtendedKey(key);
269				// keydown in highest bit
270				if (!pending_key_events && !(GetAsyncKeyState(virtual_key) & 0x8000))
271				{
272 					//llinfos << "Key up event missed, resetting" << llendl;
273					mKeyLevel[key] = FALSE;
274				}
275			}
276		}
277
278		// Generate callback if any event has occurred on this key this frame.
279		// Can't just test mKeyLevel, because this could be a slow frame and
280		// key might have gone down then up. JC
281		if (mKeyLevel[key] || mKeyDown[key] || mKeyUp[key])
282		{
283			mCurScanKey = key;
284			mCallbacks->handleScanKey(key, mKeyDown[key], mKeyUp[key], mKeyLevel[key]);
285		}
286	}
287
288	// Reset edges for next frame
289	for (key = 0; key < KEY_COUNT; key++)
290	{
291		mKeyUp[key] = FALSE;
292		mKeyDown[key] = FALSE;
293		if (mKeyLevel[key])
294		{
295			mKeyLevelFrameCount[key]++;
296		}
297	}
298}
299
300BOOL LLKeyboardWin32::translateExtendedKey(const U16 os_key, const MASK mask, KEY *translated_key)
301{
302	if(mNumpadDistinct == ND_NUMLOCK_ON)
303	{
304		std::map<U16, KEY>::iterator iter = mTranslateNumpadMap.find(os_key);
305		if (iter != mTranslateNumpadMap.end())
306		{
307			*translated_key = iter->second;
308			return TRUE;
309		}
310	}
311
312	BOOL success = translateKey(os_key, translated_key);
313	if(mNumpadDistinct != ND_NEVER) {
314		if(!success) return success;
315		if(mask & MASK_EXTENDED) 
316		{
317			// this is where we'd create new keycodes for extended keys
318			// the set of extended keys includes the 'normal' arrow keys and 
319			// the pgup/dn/insert/home/end/delete cluster above the arrow keys
320			// see http://windowssdk.msdn.microsoft.com/en-us/library/ms646280.aspx
321
322			// only process the return key if numlock is off
323			if(((mNumpadDistinct == ND_NUMLOCK_OFF && 
324				 !(GetKeyState(VK_NUMLOCK) & 1)) 
325				 || mNumpadDistinct == ND_NUMLOCK_ON) &&
326					*translated_key == KEY_RETURN) {
327					*translated_key = KEY_PAD_RETURN;
328			}
329		}
330		else 
331		{
332			// the non-extended keys, those are in the numpad
333			switch (*translated_key) 
334			{
335				case KEY_LEFT:
336					*translated_key = KEY_PAD_LEFT; break;
337				case KEY_RIGHT: 
338					*translated_key = KEY_PAD_RIGHT; break;
339				case KEY_UP: 
340					*translated_key = KEY_PAD_UP; break;
341				case KEY_DOWN:
342					*translated_key = KEY_PAD_DOWN; break;
343				case KEY_HOME:
344					*translated_key = KEY_PAD_HOME; break;
345				case KEY_END:
346					*translated_key = KEY_PAD_END; break;
347				case KEY_PAGE_UP:
348					*translated_key = KEY_PAD_PGUP; break;
349				case KEY_PAGE_DOWN:
350					*translated_key = KEY_PAD_PGDN; break;
351				case KEY_INSERT:
352					*translated_key = KEY_PAD_INS; break;
353				case KEY_DELETE:
354					*translated_key = KEY_PAD_DEL; break;
355			}
356		}
357	}
358	return success;
359}
360
361U16  LLKeyboardWin32::inverseTranslateExtendedKey(const KEY translated_key)
362{
363	// if numlock is on, then we need to translate KEY_PAD_FOO to the corresponding number pad number
364	if((mNumpadDistinct == ND_NUMLOCK_ON) && (GetKeyState(VK_NUMLOCK) & 1))
365	{
366		std::map<KEY, U16>::iterator iter = mInvTranslateNumpadMap.find(translated_key);
367		if (iter != mInvTranslateNumpadMap.end())
368		{
369			return iter->second;
370		}
371	}
372
373	// if numlock is off or we're not converting numbers to arrows, we map our keypad arrows
374	// to regular arrows since Windows doesn't distinguish between them
375	KEY converted_key = translated_key;
376	switch (converted_key) 
377	{
378		case KEY_PAD_LEFT:
379			converted_key = KEY_LEFT; break;
380		case KEY_PAD_RIGHT: 
381			converted_key = KEY_RIGHT; break;
382		case KEY_PAD_UP: 
383			converted_key = KEY_UP; break;
384		case KEY_PAD_DOWN:
385			converted_key = KEY_DOWN; break;
386		case KEY_PAD_HOME:
387			converted_key = KEY_HOME; break;
388		case KEY_PAD_END:
389			converted_key = KEY_END; break;
390		case KEY_PAD_PGUP:
391			converted_key = KEY_PAGE_UP; break;
392		case KEY_PAD_PGDN:
393			converted_key = KEY_PAGE_DOWN; break;
394		case KEY_PAD_INS:
395			converted_key = KEY_INSERT; break;
396		case KEY_PAD_DEL:
397			converted_key = KEY_DELETE; break;
398		case KEY_PAD_RETURN:
399			converted_key = KEY_RETURN; break;
400	}
401	// convert our virtual keys to OS keys
402	return inverseTranslateKey(converted_key);
403}
404
405#endif