diff options
Diffstat (limited to 'linden/indra/llwindow/llkeyboard.cpp')
-rw-r--r-- | linden/indra/llwindow/llkeyboard.cpp | 392 |
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 | |||
39 | LLKeyboard *gKeyboard = NULL; | ||
40 | |||
41 | //static | ||
42 | std::map<KEY,LLString> LLKeyboard::sKeysToNames; | ||
43 | std::map<LLString,KEY> LLKeyboard::sNamesToKeys; | ||
44 | |||
45 | // | ||
46 | // Class Implementation | ||
47 | // | ||
48 | |||
49 | LLKeyboard::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 | |||
136 | LLKeyboard::~LLKeyboard() | ||
137 | { | ||
138 | // nothing | ||
139 | } | ||
140 | |||
141 | void 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 | ||
151 | void 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 | |||
181 | BOOL 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 | |||
201 | U16 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 | |||
216 | BOOL 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 | |||
244 | BOOL 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 | |||
266 | void 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. | ||
280 | F32 LLKeyboard::getKeyElapsedTime(KEY key) | ||
281 | { | ||
282 | return mKeyLevelTimer[key].getElapsedTimeF32(); | ||
283 | } | ||
284 | |||
285 | // Returns time in frames since key was pressed. | ||
286 | S32 LLKeyboard::getKeyElapsedFrameCount(KEY key) | ||
287 | { | ||
288 | return mKeyLevelFrameCount[key]; | ||
289 | } | ||
290 | |||
291 | // static | ||
292 | BOOL 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 | ||
329 | LLString 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 | ||
345 | BOOL 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 | } | ||