PageRenderTime 216ms CodeModel.GetById 2ms app.highlight 178ms RepoModel.GetById 16ms app.codeStats 1ms

/indra/newview/llviewerkeyboard.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 978 lines | 765 code | 129 blank | 84 comment | 195 complexity | be892abf29f35a37cb161c53dff39fd8 MD5 | raw file
  1/** 
  2 * @file llviewerkeyboard.cpp
  3 * @brief LLViewerKeyboard class implementation
  4 *
  5 * $LicenseInfo:firstyear=2005&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#include "llviewerprecompiledheaders.h"
 28
 29#include "llappviewer.h"
 30#include "llviewerkeyboard.h"
 31#include "llmath.h"
 32#include "llagent.h"
 33#include "llagentcamera.h"
 34#include "llnearbychatbar.h"
 35#include "llviewercontrol.h"
 36#include "llfocusmgr.h"
 37#include "llmorphview.h"
 38#include "llmoveview.h"
 39#include "lltoolfocus.h"
 40#include "llviewerwindow.h"
 41#include "llvoavatarself.h"
 42#include "llfloatercamera.h"
 43#include "llinitparam.h"
 44
 45//
 46// Constants
 47//
 48
 49const F32 FLY_TIME = 0.5f;
 50const F32 FLY_FRAMES = 4;
 51
 52const F32 NUDGE_TIME = 0.25f;  // in seconds
 53const S32 NUDGE_FRAMES = 2;
 54const F32 ORBIT_NUDGE_RATE = 0.05f;  // fraction of normal speed
 55const F32 YAW_NUDGE_RATE = 0.05f;  // fraction of normal speed
 56
 57struct LLKeyboardActionRegistry 
 58:	public LLRegistrySingleton<std::string, boost::function<void (EKeystate keystate)>, LLKeyboardActionRegistry>
 59{
 60};
 61
 62LLViewerKeyboard gViewerKeyboard;
 63
 64void agent_jump( EKeystate s )
 65{
 66	if( KEYSTATE_UP == s  ) return;
 67	F32 time = gKeyboard->getCurKeyElapsedTime();
 68	S32 frame_count = llround(gKeyboard->getCurKeyElapsedFrameCount());
 69
 70	if( time < FLY_TIME 
 71		|| frame_count <= FLY_FRAMES 
 72		|| gAgent.upGrabbed()
 73		|| !gSavedSettings.getBOOL("AutomaticFly"))
 74	{
 75		gAgent.moveUp(1);
 76	}
 77	else
 78	{
 79		gAgent.setFlying(TRUE);
 80		gAgent.moveUp(1);
 81	}
 82}
 83
 84void agent_push_down( EKeystate s )
 85{
 86	if( KEYSTATE_UP == s  ) return;
 87	gAgent.moveUp(-1);
 88}
 89
 90static void agent_handle_doubletap_run(EKeystate s, LLAgent::EDoubleTapRunMode mode)
 91{
 92	if (KEYSTATE_UP == s)
 93	{
 94		if (gAgent.mDoubleTapRunMode == mode &&
 95		    gAgent.getRunning() &&
 96		    !gAgent.getAlwaysRun())
 97		{
 98			// Turn off temporary running.
 99			gAgent.clearRunning();
100			gAgent.sendWalkRun(gAgent.getRunning());
101		}
102	}
103	else if (gSavedSettings.getBOOL("AllowTapTapHoldRun") &&
104		 KEYSTATE_DOWN == s &&
105		 !gAgent.getRunning())
106	{
107		if (gAgent.mDoubleTapRunMode == mode &&
108		    gAgent.mDoubleTapRunTimer.getElapsedTimeF32() < NUDGE_TIME)
109		{
110			// Same walk-key was pushed again quickly; this is a
111			// double-tap so engage temporary running.
112			gAgent.setRunning();
113			gAgent.sendWalkRun(gAgent.getRunning());
114		}
115
116		// Pressing any walk-key resets the double-tap timer
117		gAgent.mDoubleTapRunTimer.reset();
118		gAgent.mDoubleTapRunMode = mode;
119	}
120}
121
122static void agent_push_forwardbackward( EKeystate s, S32 direction, LLAgent::EDoubleTapRunMode mode )
123{
124	agent_handle_doubletap_run(s, mode);
125	if (KEYSTATE_UP == s) return;
126
127	F32 time = gKeyboard->getCurKeyElapsedTime();
128	S32 frame_count = llround(gKeyboard->getCurKeyElapsedFrameCount());
129
130	if( time < NUDGE_TIME || frame_count <= NUDGE_FRAMES)
131	{
132		gAgent.moveAtNudge(direction);
133	}
134	else
135	{
136		gAgent.moveAt(direction);
137	}
138}
139
140void camera_move_forward( EKeystate s );
141
142void agent_push_forward( EKeystate s )
143{
144	//in free camera control mode we need to intercept keyboard events for avatar movements
145	if (LLFloaterCamera::inFreeCameraMode())
146	{
147		camera_move_forward(s);
148		return;
149	}
150	agent_push_forwardbackward(s, 1, LLAgent::DOUBLETAP_FORWARD);
151}
152
153void camera_move_backward( EKeystate s );
154
155void agent_push_backward( EKeystate s )
156{
157	//in free camera control mode we need to intercept keyboard events for avatar movements
158	if (LLFloaterCamera::inFreeCameraMode())
159	{
160		camera_move_backward(s);
161		return;
162	}
163	agent_push_forwardbackward(s, -1, LLAgent::DOUBLETAP_BACKWARD);
164}
165
166static void agent_slide_leftright( EKeystate s, S32 direction, LLAgent::EDoubleTapRunMode mode )
167{
168	agent_handle_doubletap_run(s, mode);
169	if( KEYSTATE_UP == s ) return;
170	F32 time = gKeyboard->getCurKeyElapsedTime();
171	S32 frame_count = llround(gKeyboard->getCurKeyElapsedFrameCount());
172
173	if( time < NUDGE_TIME || frame_count <= NUDGE_FRAMES)
174	{
175		gAgent.moveLeftNudge(direction);
176	}
177	else
178	{
179		gAgent.moveLeft(direction);
180	}
181}
182
183
184void agent_slide_left( EKeystate s )
185{
186	agent_slide_leftright(s, 1, LLAgent::DOUBLETAP_SLIDELEFT);
187}
188
189
190void agent_slide_right( EKeystate s )
191{
192	agent_slide_leftright(s, -1, LLAgent::DOUBLETAP_SLIDERIGHT);
193}
194
195void camera_spin_around_cw( EKeystate s );
196
197void agent_turn_left( EKeystate s )
198{
199	//in free camera control mode we need to intercept keyboard events for avatar movements
200	if (LLFloaterCamera::inFreeCameraMode())
201	{
202		camera_spin_around_cw(s);
203		return;
204	}
205
206	if (LLToolCamera::getInstance()->mouseSteerMode())
207	{
208		agent_slide_left(s);
209	}
210	else
211	{
212		if (KEYSTATE_UP == s) return;
213		F32 time = gKeyboard->getCurKeyElapsedTime();
214		gAgent.moveYaw( LLFloaterMove::getYawRate( time ) );
215	}
216}
217
218void camera_spin_around_ccw( EKeystate s );
219
220void agent_turn_right( EKeystate s )
221{
222	//in free camera control mode we need to intercept keyboard events for avatar movements
223	if (LLFloaterCamera::inFreeCameraMode())
224	{
225		camera_spin_around_ccw(s);
226		return;
227	}
228
229	if (LLToolCamera::getInstance()->mouseSteerMode())
230	{
231		agent_slide_right(s);
232	}
233	else
234	{
235		if (KEYSTATE_UP == s) return;
236		F32 time = gKeyboard->getCurKeyElapsedTime();
237		gAgent.moveYaw( -LLFloaterMove::getYawRate( time ) );
238	}
239}
240
241void agent_look_up( EKeystate s )
242{
243	if( KEYSTATE_UP == s  ) return;
244	gAgent.movePitch(-1);
245	//gAgent.rotate(-2.f * DEG_TO_RAD, gAgent.getFrame().getLeftAxis() );
246}
247
248
249void agent_look_down( EKeystate s )
250{
251	if( KEYSTATE_UP == s  ) return;
252	gAgent.movePitch(1);
253	//gAgent.rotate(2.f * DEG_TO_RAD, gAgent.getFrame().getLeftAxis() );
254}
255
256void agent_toggle_fly( EKeystate s )
257{
258	// Only catch the edge
259	if (KEYSTATE_DOWN == s )
260	{
261		LLAgent::toggleFlying();
262	}
263}
264
265F32 get_orbit_rate()
266{
267	F32 time = gKeyboard->getCurKeyElapsedTime();
268	if( time < NUDGE_TIME )
269	{
270		F32 rate = ORBIT_NUDGE_RATE + time * (1 - ORBIT_NUDGE_RATE)/ NUDGE_TIME;
271		//llinfos << rate << llendl;
272		return rate;
273	}
274	else
275	{
276		return 1;
277	}
278}
279
280void camera_spin_around_ccw( EKeystate s )
281{
282	if( KEYSTATE_UP == s  ) return;
283	gAgentCamera.unlockView();
284	gAgentCamera.setOrbitLeftKey( get_orbit_rate() );
285}
286
287
288void camera_spin_around_cw( EKeystate s )
289{
290	if( KEYSTATE_UP == s  ) return;
291	gAgentCamera.unlockView();
292	gAgentCamera.setOrbitRightKey( get_orbit_rate() );
293}
294
295void camera_spin_around_ccw_sitting( EKeystate s )
296{
297	if( KEYSTATE_UP == s ) return;
298	if (gAgent.rotateGrabbed() || gAgentCamera.sitCameraEnabled())
299	{
300		//send keystrokes, but do not change camera
301		agent_turn_right(s);
302	}
303	else
304	{
305		//change camera but do not send keystrokes
306		gAgentCamera.setOrbitLeftKey( get_orbit_rate() );
307	}
308}
309
310
311void camera_spin_around_cw_sitting( EKeystate s )
312{
313	if( KEYSTATE_UP == s  ) return;
314	if (gAgent.rotateGrabbed() || gAgentCamera.sitCameraEnabled())
315	{
316		//send keystrokes, but do not change camera
317		agent_turn_left(s);
318	}
319	else
320	{
321		//change camera but do not send keystrokes
322		gAgentCamera.setOrbitRightKey( get_orbit_rate() );
323	}
324}
325
326
327void camera_spin_over( EKeystate s )
328{
329	if( KEYSTATE_UP == s  ) return;
330	gAgentCamera.unlockView();
331	gAgentCamera.setOrbitUpKey( get_orbit_rate() );
332}
333
334
335void camera_spin_under( EKeystate s )
336{
337	if( KEYSTATE_UP == s  ) return;
338	gAgentCamera.unlockView();
339	gAgentCamera.setOrbitDownKey( get_orbit_rate() );
340}
341
342void camera_spin_over_sitting( EKeystate s )
343{
344	if( KEYSTATE_UP == s  ) return;
345	if (gAgent.upGrabbed() || gAgentCamera.sitCameraEnabled())
346	{
347		//send keystrokes, but do not change camera
348		agent_jump(s);
349	}
350	else
351	{
352		//change camera but do not send keystrokes
353		gAgentCamera.setOrbitUpKey( get_orbit_rate() );
354	}
355}
356
357
358void camera_spin_under_sitting( EKeystate s )
359{
360	if( KEYSTATE_UP == s  ) return;
361	if (gAgent.downGrabbed() || gAgentCamera.sitCameraEnabled())
362	{
363		//send keystrokes, but do not change camera
364		agent_push_down(s);
365	}
366	else
367	{
368		//change camera but do not send keystrokes
369		gAgentCamera.setOrbitDownKey( get_orbit_rate() );
370	}
371}
372
373void camera_move_forward( EKeystate s )
374{
375	if( KEYSTATE_UP == s  ) return;
376	gAgentCamera.unlockView();
377	gAgentCamera.setOrbitInKey( get_orbit_rate() );
378}
379
380
381void camera_move_backward( EKeystate s )
382{
383	if( KEYSTATE_UP == s  ) return;
384	gAgentCamera.unlockView();
385	gAgentCamera.setOrbitOutKey( get_orbit_rate() );
386}
387
388void camera_move_forward_sitting( EKeystate s )
389{
390	if( KEYSTATE_UP == s  ) return;
391	if (gAgent.forwardGrabbed() || gAgentCamera.sitCameraEnabled())
392	{
393		agent_push_forward(s);
394	}
395	else
396	{
397		gAgentCamera.setOrbitInKey( get_orbit_rate() );
398	}
399}
400
401
402void camera_move_backward_sitting( EKeystate s )
403{
404	if( KEYSTATE_UP == s  ) return;
405
406	if (gAgent.backwardGrabbed() || gAgentCamera.sitCameraEnabled())
407	{
408		agent_push_backward(s);
409	}
410	else
411	{
412		gAgentCamera.setOrbitOutKey( get_orbit_rate() );
413	}
414}
415
416void camera_pan_up( EKeystate s )
417{
418	if( KEYSTATE_UP == s  ) return;
419	gAgentCamera.unlockView();
420	gAgentCamera.setPanUpKey( get_orbit_rate() );
421}
422
423void camera_pan_down( EKeystate s )
424{
425	if( KEYSTATE_UP == s  ) return;
426	gAgentCamera.unlockView();
427	gAgentCamera.setPanDownKey( get_orbit_rate() );
428}
429
430void camera_pan_left( EKeystate s )
431{
432	if( KEYSTATE_UP == s  ) return;
433	gAgentCamera.unlockView();
434	gAgentCamera.setPanLeftKey( get_orbit_rate() );
435}
436
437void camera_pan_right( EKeystate s )
438{
439	if( KEYSTATE_UP == s  ) return;
440	gAgentCamera.unlockView();
441	gAgentCamera.setPanRightKey( get_orbit_rate() );
442}
443
444void camera_pan_in( EKeystate s )
445{
446	if( KEYSTATE_UP == s  ) return;
447	gAgentCamera.unlockView();
448	gAgentCamera.setPanInKey( get_orbit_rate() );
449}
450
451void camera_pan_out( EKeystate s )
452{
453	if( KEYSTATE_UP == s  ) return;
454	gAgentCamera.unlockView();
455	gAgentCamera.setPanOutKey( get_orbit_rate() );
456}
457
458void camera_move_forward_fast( EKeystate s )
459{
460	if( KEYSTATE_UP == s  ) return;
461	gAgentCamera.unlockView();
462	gAgentCamera.setOrbitInKey(2.5f);
463}
464
465void camera_move_backward_fast( EKeystate s )
466{
467	if( KEYSTATE_UP == s  ) return;
468	gAgentCamera.unlockView();
469	gAgentCamera.setOrbitOutKey(2.5f);
470}
471
472
473void edit_avatar_spin_ccw( EKeystate s )
474{
475	if( KEYSTATE_UP == s  ) return;
476	gMorphView->setCameraDrivenByKeys( TRUE );
477	gAgentCamera.setOrbitLeftKey( get_orbit_rate() );
478	//gMorphView->orbitLeft( get_orbit_rate() );
479}
480
481
482void edit_avatar_spin_cw( EKeystate s )
483{
484	if( KEYSTATE_UP == s  ) return;
485	gMorphView->setCameraDrivenByKeys( TRUE );
486	gAgentCamera.setOrbitRightKey( get_orbit_rate() );
487	//gMorphView->orbitRight( get_orbit_rate() );
488}
489
490void edit_avatar_spin_over( EKeystate s )
491{
492	if( KEYSTATE_UP == s  ) return;
493	gMorphView->setCameraDrivenByKeys( TRUE );
494	gAgentCamera.setOrbitUpKey( get_orbit_rate() );
495	//gMorphView->orbitUp( get_orbit_rate() );
496}
497
498
499void edit_avatar_spin_under( EKeystate s )
500{
501	if( KEYSTATE_UP == s  ) return;
502	gMorphView->setCameraDrivenByKeys( TRUE );
503	gAgentCamera.setOrbitDownKey( get_orbit_rate() );
504	//gMorphView->orbitDown( get_orbit_rate() );
505}
506
507void edit_avatar_move_forward( EKeystate s )
508{
509	if( KEYSTATE_UP == s  ) return;
510	gMorphView->setCameraDrivenByKeys( TRUE );
511	gAgentCamera.setOrbitInKey( get_orbit_rate() );
512	//gMorphView->orbitIn();
513}
514
515
516void edit_avatar_move_backward( EKeystate s )
517{
518	if( KEYSTATE_UP == s  ) return;
519	gMorphView->setCameraDrivenByKeys( TRUE );
520	gAgentCamera.setOrbitOutKey( get_orbit_rate() );
521	//gMorphView->orbitOut();
522}
523
524void stop_moving( EKeystate s )
525{
526	if( KEYSTATE_UP == s  ) return;
527	// stop agent
528	gAgent.setControlFlags(AGENT_CONTROL_STOP);
529
530	// cancel autopilot
531	gAgent.stopAutoPilot();
532}
533
534void start_chat( EKeystate s )
535{
536	// start chat
537	LLNearbyChatBar::startChat(NULL);
538}
539
540void start_gesture( EKeystate s )
541{
542	LLUICtrl* focus_ctrlp = dynamic_cast<LLUICtrl*>(gFocusMgr.getKeyboardFocus());
543	if (KEYSTATE_UP == s &&
544		! (focus_ctrlp && focus_ctrlp->acceptsTextInput()))
545	{
546 		if (LLNearbyChatBar::getInstance()->getCurrentChat().empty())
547 		{
548 			// No existing chat in chat editor, insert '/'
549 			LLNearbyChatBar::startChat("/");
550 		}
551 		else
552 		{
553 			// Don't overwrite existing text in chat editor
554 			LLNearbyChatBar::startChat(NULL);
555 		}
556	}
557}
558
559#define REGISTER_KEYBOARD_ACTION(KEY, ACTION) LLREGISTER_STATIC(LLKeyboardActionRegistry, KEY, ACTION);
560REGISTER_KEYBOARD_ACTION("jump", agent_jump);
561REGISTER_KEYBOARD_ACTION("push_down", agent_push_down);
562REGISTER_KEYBOARD_ACTION("push_forward", agent_push_forward);
563REGISTER_KEYBOARD_ACTION("push_backward", agent_push_backward);
564REGISTER_KEYBOARD_ACTION("look_up", agent_look_up);
565REGISTER_KEYBOARD_ACTION("look_down", agent_look_down);
566REGISTER_KEYBOARD_ACTION("toggle_fly", agent_toggle_fly);
567REGISTER_KEYBOARD_ACTION("turn_left", agent_turn_left);
568REGISTER_KEYBOARD_ACTION("turn_right", agent_turn_right);
569REGISTER_KEYBOARD_ACTION("slide_left", agent_slide_left);
570REGISTER_KEYBOARD_ACTION("slide_right", agent_slide_right);
571REGISTER_KEYBOARD_ACTION("spin_around_ccw", camera_spin_around_ccw);
572REGISTER_KEYBOARD_ACTION("spin_around_cw", camera_spin_around_cw);
573REGISTER_KEYBOARD_ACTION("spin_around_ccw_sitting", camera_spin_around_ccw_sitting);
574REGISTER_KEYBOARD_ACTION("spin_around_cw_sitting", camera_spin_around_cw_sitting);
575REGISTER_KEYBOARD_ACTION("spin_over", camera_spin_over);
576REGISTER_KEYBOARD_ACTION("spin_under", camera_spin_under);
577REGISTER_KEYBOARD_ACTION("spin_over_sitting", camera_spin_over_sitting);
578REGISTER_KEYBOARD_ACTION("spin_under_sitting", camera_spin_under_sitting);
579REGISTER_KEYBOARD_ACTION("move_forward", camera_move_forward);
580REGISTER_KEYBOARD_ACTION("move_backward", camera_move_backward);
581REGISTER_KEYBOARD_ACTION("move_forward_sitting", camera_move_forward_sitting);
582REGISTER_KEYBOARD_ACTION("move_backward_sitting", camera_move_backward_sitting);
583REGISTER_KEYBOARD_ACTION("pan_up", camera_pan_up);
584REGISTER_KEYBOARD_ACTION("pan_down", camera_pan_down);
585REGISTER_KEYBOARD_ACTION("pan_left", camera_pan_left);
586REGISTER_KEYBOARD_ACTION("pan_right", camera_pan_right);
587REGISTER_KEYBOARD_ACTION("pan_in", camera_pan_in);
588REGISTER_KEYBOARD_ACTION("pan_out", camera_pan_out);
589REGISTER_KEYBOARD_ACTION("move_forward_fast", camera_move_forward_fast);
590REGISTER_KEYBOARD_ACTION("move_backward_fast", camera_move_backward_fast);
591REGISTER_KEYBOARD_ACTION("edit_avatar_spin_ccw", edit_avatar_spin_ccw);
592REGISTER_KEYBOARD_ACTION("edit_avatar_spin_cw", edit_avatar_spin_cw);
593REGISTER_KEYBOARD_ACTION("edit_avatar_spin_over", edit_avatar_spin_over);
594REGISTER_KEYBOARD_ACTION("edit_avatar_spin_under", edit_avatar_spin_under);
595REGISTER_KEYBOARD_ACTION("edit_avatar_move_forward", edit_avatar_move_forward);
596REGISTER_KEYBOARD_ACTION("edit_avatar_move_backward", edit_avatar_move_backward);
597REGISTER_KEYBOARD_ACTION("stop_moving", stop_moving);
598REGISTER_KEYBOARD_ACTION("start_chat", start_chat);
599REGISTER_KEYBOARD_ACTION("start_gesture", start_gesture);
600#undef REGISTER_KEYBOARD_ACTION
601
602LLViewerKeyboard::LLViewerKeyboard()
603{
604	for (S32 i = 0; i < MODE_COUNT; i++)
605	{
606		mBindingCount[i] = 0;
607	}
608
609	for (S32 i = 0; i < KEY_COUNT; i++)
610	{
611		mKeyHandledByUI[i] = FALSE;
612	}
613	// we want the UI to never see these keys so that they can always control the avatar/camera
614	for(KEY k = KEY_PAD_UP; k <= KEY_PAD_DIVIDE; k++) 
615	{
616		mKeysSkippedByUI.insert(k);	
617	}
618}
619
620BOOL LLViewerKeyboard::modeFromString(const std::string& string, S32 *mode)
621{
622	if (string == "FIRST_PERSON")
623	{
624		*mode = MODE_FIRST_PERSON;
625		return TRUE;
626	}
627	else if (string == "THIRD_PERSON")
628	{
629		*mode = MODE_THIRD_PERSON;
630		return TRUE;
631	}
632	else if (string == "EDIT")
633	{
634		*mode = MODE_EDIT;
635		return TRUE;
636	}
637	else if (string == "EDIT_AVATAR")
638	{
639		*mode = MODE_EDIT_AVATAR;
640		return TRUE;
641	}
642	else if (string == "SITTING")
643	{
644		*mode = MODE_SITTING;
645		return TRUE;
646	}
647	else
648	{
649		*mode = MODE_THIRD_PERSON;
650		return FALSE;
651	}
652}
653
654BOOL LLViewerKeyboard::handleKey(KEY translated_key,  MASK translated_mask, BOOL repeated)
655{
656	// check for re-map
657	EKeyboardMode mode = gViewerKeyboard.getMode();
658	U32 keyidx = (translated_mask<<16) | translated_key;
659	key_remap_t::iterator iter = mRemapKeys[mode].find(keyidx);
660	if (iter != mRemapKeys[mode].end())
661	{
662		translated_key = (iter->second) & 0xff;
663		translated_mask = (iter->second)>>16;
664	}
665
666	// No repeats of F-keys
667	BOOL repeatable_key = (translated_key < KEY_F1 || translated_key > KEY_F12);
668	if (!repeatable_key && repeated)
669	{
670		return FALSE;
671	}
672
673	lldebugst(LLERR_USER_INPUT) << "keydown -" << translated_key << "-" << llendl;
674	// skip skipped keys
675	if(mKeysSkippedByUI.find(translated_key) != mKeysSkippedByUI.end()) 
676	{
677		mKeyHandledByUI[translated_key] = FALSE;
678	}
679	else
680	{
681		// it is sufficient to set this value once per call to handlekey
682		// without clearing it, as it is only used in the subsequent call to scanKey
683		mKeyHandledByUI[translated_key] = gViewerWindow->handleKey(translated_key, translated_mask);
684	}
685	return mKeyHandledByUI[translated_key];
686}
687
688
689
690BOOL LLViewerKeyboard::bindKey(const S32 mode, const KEY key, const MASK mask, const std::string& function_name)
691{
692	S32 index;
693	typedef boost::function<void(EKeystate)> function_t;
694	function_t function = NULL;
695	std::string name;
696
697	// Allow remapping of F2-F12
698	if (function_name[0] == 'F')
699	{
700		int c1 = function_name[1] - '0';
701		int c2 = function_name[2] ? function_name[2] - '0' : -1;
702		if (c1 >= 0 && c1 <= 9 && c2 >= -1 && c2 <= 9)
703		{
704			int idx = c1;
705			if (c2 >= 0)
706				idx = idx*10 + c2;
707			if (idx >=2 && idx <= 12)
708			{
709				U32 keyidx = ((mask<<16)|key);
710				(mRemapKeys[mode])[keyidx] = ((0<<16)|(KEY_F1+(idx-1)));
711				return TRUE;
712			}
713		}
714	}
715
716	// Not remapped, look for a function
717	
718	function_t* result = LLKeyboardActionRegistry::getValue(function_name);
719	if (result)
720	{
721		function = *result;
722	}
723
724	if (!function)
725	{
726		llerrs << "Can't bind key to function " << function_name << ", no function with this name found" << llendl;
727		return FALSE;
728	}
729
730	// check for duplicate first and overwrite
731	for (index = 0; index < mBindingCount[mode]; index++)
732	{
733		if (key == mBindings[mode][index].mKey && mask == mBindings[mode][index].mMask)
734			break;
735	}
736
737	if (index >= MAX_KEY_BINDINGS)
738	{
739		llerrs << "LLKeyboard::bindKey() - too many keys for mode " << mode << llendl;
740		return FALSE;
741	}
742
743	if (mode >= MODE_COUNT)
744	{
745		llerror("LLKeyboard::bindKey() - unknown mode passed", mode);
746		return FALSE;
747	}
748
749	mBindings[mode][index].mKey = key;
750	mBindings[mode][index].mMask = mask;
751	mBindings[mode][index].mFunction = function;
752
753	if (index == mBindingCount[mode])
754		mBindingCount[mode]++;
755
756	return TRUE;
757}
758
759LLViewerKeyboard::KeyBinding::KeyBinding()
760:	key("key"),
761	mask("mask"),
762	command("command")
763{}
764
765LLViewerKeyboard::KeyMode::KeyMode(EKeyboardMode _mode)
766:	bindings("binding"),
767	mode(_mode)
768{}
769
770LLViewerKeyboard::Keys::Keys()
771:	first_person("first_person", KeyMode(MODE_FIRST_PERSON)),
772	third_person("third_person", KeyMode(MODE_THIRD_PERSON)),
773	edit("edit", KeyMode(MODE_EDIT)),
774	sitting("sitting", KeyMode(MODE_SITTING)),
775	edit_avatar("edit_avatar", KeyMode(MODE_EDIT_AVATAR))
776{}
777
778S32 LLViewerKeyboard::loadBindingsXML(const std::string& filename)
779{
780	S32 binding_count = 0;
781	Keys keys;
782	LLSimpleXUIParser parser;
783
784	if (parser.readXUI(filename, keys) 
785		&& keys.validateBlock())
786	{
787		binding_count += loadBindingMode(keys.first_person);
788		binding_count += loadBindingMode(keys.third_person);
789		binding_count += loadBindingMode(keys.edit);
790		binding_count += loadBindingMode(keys.sitting);
791		binding_count += loadBindingMode(keys.edit_avatar);
792	}
793	return binding_count;
794}
795
796S32 LLViewerKeyboard::loadBindingMode(const LLViewerKeyboard::KeyMode& keymode)
797{
798	S32 binding_count = 0;
799	for (LLInitParam::ParamIterator<KeyBinding>::const_iterator it = keymode.bindings.begin(), 
800			end_it = keymode.bindings.end();
801		it != end_it;
802		++it)
803	{
804		KEY key;
805		MASK mask;
806		LLKeyboard::keyFromString(it->key, &key);
807		LLKeyboard::maskFromString(it->mask, &mask);
808		bindKey(keymode.mode, key, mask, it->command);
809		binding_count++;
810	}
811
812	return binding_count;
813}
814
815S32 LLViewerKeyboard::loadBindings(const std::string& filename)
816{
817	LLFILE *fp;
818	const S32 BUFFER_SIZE = 2048;
819	char buffer[BUFFER_SIZE];	/* Flawfinder: ignore */
820	// *NOTE: This buffer size is hard coded into scanf() below.
821	char mode_string[MAX_STRING] = "";	/* Flawfinder: ignore */
822	char key_string[MAX_STRING] = "";	/* Flawfinder: ignore */
823	char mask_string[MAX_STRING] = "";	/* Flawfinder: ignore */
824	char function_string[MAX_STRING] = "";	/* Flawfinder: ignore */
825	S32 mode = MODE_THIRD_PERSON;
826	KEY key = 0;
827	MASK mask = 0;
828	S32 tokens_read;
829	S32 binding_count = 0;
830	S32 line_count = 0;
831
832	if(filename.empty())
833	{
834		llerrs << " No filename specified" << llendl;
835		return 0;
836	}
837
838	fp = LLFile::fopen(filename, "r");
839
840	if (!fp)
841	{
842		return 0;
843	}
844
845
846	while (!feof(fp))
847	{
848		line_count++;
849		if (!fgets(buffer, BUFFER_SIZE, fp))
850			break;
851
852		// skip over comments, blank lines
853		if (buffer[0] == '#' || buffer[0] == '\n') continue;
854
855		// grab the binding strings
856		tokens_read = sscanf(	/* Flawfinder: ignore */
857			buffer,
858			"%254s %254s %254s %254s",
859			mode_string,
860			key_string,
861			mask_string,
862			function_string);
863
864		if (tokens_read == EOF)
865		{
866			llinfos << "Unexpected end-of-file at line " << line_count << " of key binding file " << filename << llendl;
867			fclose(fp);
868			return 0;
869		}
870		else if (tokens_read < 4)
871		{
872			llinfos << "Can't read line " << line_count << " of key binding file " << filename << llendl;
873			continue;
874		}
875
876		// convert mode
877		if (!modeFromString(mode_string, &mode))
878		{
879			llinfos << "Unknown mode on line " << line_count << " of key binding file " << filename << llendl;
880			llinfos << "Mode must be one of FIRST_PERSON, THIRD_PERSON, EDIT, EDIT_AVATAR" << llendl;
881			continue;
882		}
883
884		// convert key
885		if (!LLKeyboard::keyFromString(key_string, &key))
886		{
887			llinfos << "Can't interpret key on line " << line_count << " of key binding file " << filename << llendl;
888			continue;
889		}
890
891		// convert mask
892		if (!LLKeyboard::maskFromString(mask_string, &mask))
893		{
894			llinfos << "Can't interpret mask on line " << line_count << " of key binding file " << filename << llendl;
895			continue;
896		}
897
898		// bind key
899		if (bindKey(mode, key, mask, function_string))
900		{
901			binding_count++;
902		}
903	}
904
905	fclose(fp);
906
907	return binding_count;
908}
909
910
911EKeyboardMode LLViewerKeyboard::getMode()
912{
913	if ( gAgentCamera.cameraMouselook() )
914	{
915		return MODE_FIRST_PERSON;
916	}
917	else if ( gMorphView && gMorphView->getVisible())
918	{
919		return MODE_EDIT_AVATAR;
920	}
921	else if (isAgentAvatarValid() && gAgentAvatarp->isSitting())
922	{
923		return MODE_SITTING;
924	}
925	else
926	{
927		return MODE_THIRD_PERSON;
928	}
929}
930
931
932// Called from scanKeyboard.
933void LLViewerKeyboard::scanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level)
934{
935	S32 mode = getMode();
936	// Consider keyboard scanning as NOT mouse event. JC
937	MASK mask = gKeyboard->currentMask(FALSE);
938
939	LLKeyBinding* binding = mBindings[mode];
940	S32 binding_count = mBindingCount[mode];
941
942
943	if (mKeyHandledByUI[key])
944	{
945		return;
946	}
947
948	// don't process key down on repeated keys
949	BOOL repeat = gKeyboard->getKeyRepeated(key);
950
951	for (S32 i = 0; i < binding_count; i++)
952	{
953		//for (S32 key = 0; key < KEY_COUNT; key++)
954		if (binding[i].mKey == key)
955		{
956			//if (binding[i].mKey == key && binding[i].mMask == mask)
957			if (binding[i].mMask == mask)
958			{
959				if (key_down && !repeat)
960				{
961					// ...key went down this frame, call function
962					binding[i].mFunction( KEYSTATE_DOWN );
963				}
964				else if (key_up)
965				{
966					// ...key went down this frame, call function
967					binding[i].mFunction( KEYSTATE_UP );
968				}
969				else if (key_level)
970				{
971					// ...key held down from previous frame
972					// Not windows, just call the function.
973					binding[i].mFunction( KEYSTATE_LEVEL );
974				}//if
975			}//if
976		}//for
977	}//for
978}