aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llwindow/llkeyboard.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'linden/indra/llwindow/llkeyboard.cpp')
-rw-r--r--linden/indra/llwindow/llkeyboard.cpp392
1 files changed, 392 insertions, 0 deletions
diff --git a/linden/indra/llwindow/llkeyboard.cpp b/linden/indra/llwindow/llkeyboard.cpp
new file mode 100644
index 0000000..fd6fcdc
--- /dev/null
+++ b/linden/indra/llwindow/llkeyboard.cpp
@@ -0,0 +1,392 @@
1/**
2 * @file llkeyboard.cpp
3 * @brief Handler for assignable key bindings
4 *
5 * Copyright (c) 2001-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#include "linden_common.h"
29#include "indra_constants.h"
30#include "llkeyboard.h"
31
32#include "llwindow.h"
33
34
35//
36// Globals
37//
38
39LLKeyboard *gKeyboard = NULL;
40
41//static
42std::map<KEY,LLString> LLKeyboard::sKeysToNames;
43std::map<LLString,KEY> LLKeyboard::sNamesToKeys;
44
45//
46// Class Implementation
47//
48
49LLKeyboard::LLKeyboard() : mCallbacks(NULL), mNumpadDistinct(ND_NUMLOCK_OFF)
50{
51 S32 i;
52
53 // Constructor for LLTimer inits each timer. We want them to
54 // be constructed without being initialized, so we shut them down here.
55 for (i = 0; i < KEY_COUNT; i++)
56 {
57 mKeyLevelFrameCount[i] = 0;
58 mKeyLevel[i] = FALSE;
59 mKeyUp[i] = FALSE;
60 mKeyDown[i] = FALSE;
61 mKeyRepeated[i] = FALSE;
62 }
63
64 mInsertMode = LL_KIM_INSERT;
65 mCurTranslatedKey = KEY_NONE;
66
67 addKeyName(' ', "Space" );
68 addKeyName(KEY_RETURN, "Enter" );
69 addKeyName(KEY_LEFT, "Left" );
70 addKeyName(KEY_RIGHT, "Right" );
71 addKeyName(KEY_UP, "Up" );
72 addKeyName(KEY_DOWN, "Down" );
73 addKeyName(KEY_ESCAPE, "Esc" );
74 addKeyName(KEY_HOME, "Home" );
75 addKeyName(KEY_END, "End" );
76 addKeyName(KEY_PAGE_UP, "PgUp" );
77 addKeyName(KEY_PAGE_DOWN, "PgDn" );
78 addKeyName(KEY_F1, "F1" );
79 addKeyName(KEY_F2, "F2" );
80 addKeyName(KEY_F3, "F3" );
81 addKeyName(KEY_F4, "F4" );
82 addKeyName(KEY_F5, "F5" );
83 addKeyName(KEY_F6, "F6" );
84 addKeyName(KEY_F7, "F7" );
85 addKeyName(KEY_F8, "F8" );
86 addKeyName(KEY_F9, "F9" );
87 addKeyName(KEY_F10, "F10" );
88 addKeyName(KEY_F11, "F11" );
89 addKeyName(KEY_F12, "F12" );
90 addKeyName(KEY_TAB, "Tab" );
91 addKeyName(KEY_ADD, "Add" );
92 addKeyName(KEY_SUBTRACT, "Subtract" );
93 addKeyName(KEY_MULTIPLY, "Multiply" );
94 addKeyName(KEY_DIVIDE, "Divide" );
95 addKeyName(KEY_PAD_LEFT, "PAD_LEFT" );
96 addKeyName(KEY_PAD_RIGHT, "PAD_RIGHT" );
97 addKeyName(KEY_PAD_DOWN, "PAD_DOWN" );
98 addKeyName(KEY_PAD_UP, "PAD_UP" );
99 addKeyName(KEY_PAD_HOME, "PAD_HOME" );
100 addKeyName(KEY_PAD_END, "PAD_END" );
101 addKeyName(KEY_PAD_PGUP, "PAD_PGUP" );
102 addKeyName(KEY_PAD_PGDN, "PAD_PGDN" );
103 addKeyName(KEY_PAD_CENTER, "PAD_CENTER" );
104 addKeyName(KEY_PAD_INS, "PAD_INS" );
105 addKeyName(KEY_PAD_DEL, "PAD_DEL" );
106 addKeyName(KEY_PAD_RETURN, "PAD_Enter" );
107 addKeyName(KEY_BUTTON0, "PAD_BUTTON0" );
108 addKeyName(KEY_BUTTON1, "PAD_BUTTON1" );
109 addKeyName(KEY_BUTTON2, "PAD_BUTTON2" );
110 addKeyName(KEY_BUTTON3, "PAD_BUTTON3" );
111 addKeyName(KEY_BUTTON4, "PAD_BUTTON4" );
112 addKeyName(KEY_BUTTON5, "PAD_BUTTON5" );
113 addKeyName(KEY_BUTTON6, "PAD_BUTTON6" );
114 addKeyName(KEY_BUTTON7, "PAD_BUTTON7" );
115 addKeyName(KEY_BUTTON8, "PAD_BUTTON8" );
116 addKeyName(KEY_BUTTON9, "PAD_BUTTON9" );
117 addKeyName(KEY_BUTTON10, "PAD_BUTTON10" );
118 addKeyName(KEY_BUTTON11, "PAD_BUTTON11" );
119 addKeyName(KEY_BUTTON12, "PAD_BUTTON12" );
120 addKeyName(KEY_BUTTON13, "PAD_BUTTON13" );
121 addKeyName(KEY_BUTTON14, "PAD_BUTTON14" );
122 addKeyName(KEY_BUTTON15, "PAD_BUTTON15" );
123
124 addKeyName(KEY_BACKSPACE, "Backsp" );
125 addKeyName(KEY_DELETE, "Del" );
126 addKeyName(KEY_SHIFT, "Shift" );
127 addKeyName(KEY_CONTROL, "Ctrl" );
128 addKeyName(KEY_ALT, "Alt" );
129 addKeyName(KEY_HYPHEN, "-" );
130 addKeyName(KEY_EQUALS, "=" );
131 addKeyName(KEY_INSERT, "Ins" );
132 addKeyName(KEY_CAPSLOCK, "CapsLock" );
133}
134
135
136LLKeyboard::~LLKeyboard()
137{
138 // nothing
139}
140
141void LLKeyboard::addKeyName(KEY key, const LLString& name)
142{
143 sKeysToNames[key] = name;
144 LLString nameuc = name;
145 LLString::toUpper(nameuc);
146 sNamesToKeys[nameuc] = key;
147}
148
149// BUG this has to be called when an OS dialog is shown, otherwise modifier key state
150// is wrong because the keyup event is never received by the main window. JC
151void LLKeyboard::resetKeys()
152{
153 S32 i;
154
155 for (i = 0; i < KEY_COUNT; i++)
156 {
157 if( mKeyLevel[i] )
158 {
159 mKeyLevel[i] = FALSE;
160 mKeyLevelFrameCount[i] = 0;
161 }
162 }
163
164 for (i = 0; i < KEY_COUNT; i++)
165 {
166 mKeyUp[i] = FALSE;
167 }
168
169 for (i = 0; i < KEY_COUNT; i++)
170 {
171 mKeyDown[i] = FALSE;
172 }
173
174 for (i = 0; i < KEY_COUNT; i++)
175 {
176 mKeyRepeated[i] = FALSE;
177 }
178}
179
180
181BOOL LLKeyboard::translateKey(const U16 os_key, KEY *out_key)
182{
183 std::map<U16, KEY>::iterator iter;
184
185 // Only translate keys in the map, ignore all other keys for now
186 iter = mTranslateKeyMap.find(os_key);
187 if (iter == mTranslateKeyMap.end())
188 {
189 //llwarns << "Unknown virtual key " << os_key << llendl;
190 *out_key = 0;
191 return FALSE;
192 }
193 else
194 {
195 *out_key = iter->second;
196 return TRUE;
197 }
198}
199
200
201U16 LLKeyboard::inverseTranslateKey(const KEY translated_key)
202{
203 std::map<KEY, U16>::iterator iter;
204 iter = mInvTranslateKeyMap.find(translated_key);
205 if (iter == mInvTranslateKeyMap.end())
206 {
207 return 0;
208 }
209 else
210 {
211 return iter->second;
212 }
213}
214
215
216BOOL LLKeyboard::handleTranslatedKeyDown(KEY translated_key, U32 translated_mask)
217{
218 BOOL handled = FALSE;
219 BOOL repeated = FALSE;
220
221 // is this the first time the key went down?
222 // if so, generate "character" message
223 if( !mKeyLevel[translated_key] )
224 {
225 mKeyLevel[translated_key] = TRUE;
226 mKeyLevelTimer[translated_key].reset();
227 mKeyLevelFrameCount[translated_key] = 0;
228 mKeyRepeated[translated_key] = FALSE;
229 }
230 else
231 {
232 // Level is already down, assume it's repeated.
233 repeated = TRUE;
234 mKeyRepeated[translated_key] = TRUE;
235 }
236
237 mKeyDown[translated_key] = TRUE;
238 mCurTranslatedKey = (KEY)translated_key;
239 handled = mCallbacks->handleTranslatedKeyDown(translated_key, translated_mask, repeated);
240 return handled;
241}
242
243
244BOOL LLKeyboard::handleTranslatedKeyUp(KEY translated_key, U32 translated_mask)
245{
246 BOOL handled = FALSE;
247 if( mKeyLevel[translated_key] )
248 {
249 mKeyLevel[translated_key] = FALSE;
250
251 // Only generate key up events if the key is thought to
252 // be down. This allows you to call resetKeys() in the
253 // middle of a frame and ignore subsequent KEY_UP
254 // messages in the same frame. This was causing the
255 // sequence W<return> in chat to move agents forward. JC
256 mKeyUp[translated_key] = TRUE;
257 handled = mCallbacks->handleTranslatedKeyUp(translated_key, translated_mask);
258 }
259
260 lldebugst(LLERR_USER_INPUT) << "keyup -" << translated_key << "-" << llendl;
261
262 return handled;
263}
264
265
266void LLKeyboard::toggleInsertMode()
267{
268 if (LL_KIM_INSERT == mInsertMode)
269 {
270 mInsertMode = LL_KIM_OVERWRITE;
271 }
272 else
273 {
274 mInsertMode = LL_KIM_INSERT;
275 }
276}
277
278
279// Returns time in seconds since key was pressed.
280F32 LLKeyboard::getKeyElapsedTime(KEY key)
281{
282 return mKeyLevelTimer[key].getElapsedTimeF32();
283}
284
285// Returns time in frames since key was pressed.
286S32 LLKeyboard::getKeyElapsedFrameCount(KEY key)
287{
288 return mKeyLevelFrameCount[key];
289}
290
291// static
292BOOL LLKeyboard::keyFromString(const LLString& str, KEY *key)
293{
294 LLString instring(str);
295 size_t length = instring.size();
296
297 if (length < 1)
298 {
299 return FALSE;
300 }
301 if (length == 1)
302 {
303 char ch = toupper(instring[0]);
304 if (('0' <= ch && ch <= '9') ||
305 ('A' <= ch && ch <= 'Z') ||
306 ('!' <= ch && ch <= '/') || // !"#$%&'()*+,-./
307 (':' <= ch && ch <= '@') || // :;<=>?@
308 ('[' <= ch && ch <= '`') || // [\]^_`
309 ('{' <= ch && ch <= '~')) // {|}~
310 {
311 *key = ch;
312 return TRUE;
313 }
314 }
315
316 LLString::toUpper(instring);
317 KEY res = get_if_there(sNamesToKeys, instring, (KEY)0);
318 if (res != 0)
319 {
320 *key = res;
321 return TRUE;
322 }
323 llwarns << "keyFromString failed: " << str << llendl;
324 return FALSE;
325}
326
327
328// static
329LLString LLKeyboard::stringFromKey(KEY key)
330{
331 LLString res = get_if_there(sKeysToNames, key, LLString::null);
332 if (res.empty())
333 {
334 char buffer[2];
335 buffer[0] = key;
336 buffer[1] = '\0';
337 res = LLString(buffer);
338 }
339 return res;
340}
341
342
343
344//static
345BOOL LLKeyboard::maskFromString(const LLString& str, MASK *mask)
346{
347 LLString instring(str);
348 if (instring == "NONE")
349 {
350 *mask = MASK_NONE;
351 return TRUE;
352 }
353 else if (instring == "SHIFT")
354 {
355 *mask = MASK_SHIFT;
356 return TRUE;
357 }
358 else if (instring == "CTL")
359 {
360 *mask = MASK_CONTROL;
361 return TRUE;
362 }
363 else if (instring == "ALT")
364 {
365 *mask = MASK_ALT;
366 return TRUE;
367 }
368 else if (instring == "CTL_SHIFT")
369 {
370 *mask = MASK_CONTROL | MASK_SHIFT;
371 return TRUE;
372 }
373 else if (instring == "ALT_SHIFT")
374 {
375 *mask = MASK_ALT | MASK_SHIFT;
376 return TRUE;
377 }
378 else if (instring == "CTL_ALT")
379 {
380 *mask = MASK_CONTROL | MASK_ALT;
381 return TRUE;
382 }
383 else if (instring == "CTL_ALT_SHIFT")
384 {
385 *mask = MASK_CONTROL | MASK_ALT | MASK_SHIFT;
386 return TRUE;
387 }
388 else
389 {
390 return FALSE;
391 }
392}