diff options
| -rw-r--r-- | indra/llwindow/llwindow.cpp | 7 | ||||
| -rw-r--r-- | indra/llwindow/llwindowlistener.cpp | 279 | ||||
| -rw-r--r-- | indra/llwindow/llwindowlistener.h | 6 | 
3 files changed, 216 insertions, 76 deletions
| diff --git a/indra/llwindow/llwindow.cpp b/indra/llwindow/llwindow.cpp index 2d00c37719..71a5df910d 100644 --- a/indra/llwindow/llwindow.cpp +++ b/indra/llwindow/llwindow.cpp @@ -42,6 +42,7 @@  #include "linked_lists.h"  #include "llwindowcallbacks.h"  #include "llwindowlistener.h" +#include <boost/lambda/core.hpp>  // @@ -117,7 +118,11 @@ LLWindow::LLWindow(LLWindowCallbacks* callbacks, BOOL fullscreen, U32 flags)  	  mFlags(flags),  	  mHighSurrogate(0)  { -	mListener = new LLWindowListener(callbacks, gKeyboard); +	// gKeyboard is still NULL, so it doesn't do LLWindowListener any good to +	// pass its value right now. Instead, pass it a nullary function that +	// will, when we later need it, return the value of gKeyboard. +	// boost::lambda::var() constructs such a functor on the fly. +	mListener = new LLWindowListener(callbacks, boost::lambda::var(gKeyboard));  }  LLWindow::~LLWindow() diff --git a/indra/llwindow/llwindowlistener.cpp b/indra/llwindow/llwindowlistener.cpp index 22cc12acee..91b99d83c6 100644 --- a/indra/llwindow/llwindowlistener.cpp +++ b/indra/llwindow/llwindowlistener.cpp @@ -31,138 +31,271 @@  #include "llcoord.h"  #include "llkeyboard.h"  #include "llwindowcallbacks.h" +#include <map> -LLWindowListener::LLWindowListener(LLWindowCallbacks *window, LLKeyboard * keyboard) +LLWindowListener::LLWindowListener(LLWindowCallbacks *window, const KeyboardGetter& kbgetter)  	: LLEventAPI("LLWindow", "Inject input events into the LLWindow instance"),  	  mWindow(window), -	  mKeyboard(keyboard) +	  mKbGetter(kbgetter)  { +	std::string keySomething = +		"Given [\"keysym\"], [\"keycode\"] or [\"char\"], inject the specified "; +	std::string keyExplain = +		"(integer keycode values, or keysym \"XXXX\" from any KEY_XXXX, in\n" +		"http://hg.secondlife.com/viewer-development/src/tip/indra/llcommon/indra_constants.h )"; +	std::string mask = +		"Specify optional [\"mask\"] as an array containing any of \"CONTROL\", \"ALT\",\n" +		"\"SHIFT\" or \"MAC_CONTROL\"; the corresponding modifier bits will be combined\n" +		"to form the mask used with the event."; + +	std::string mouseSomething = +		"Given [\"button\"], [\"x\"] and [\"y\"], inject the given mouse "; +	std::string mouseExplain = +		"(button values \"LEFT\", \"MIDDLE\", \"RIGHT\")"; +  	add("keyDown", -		"Given [\"keycode\"] or [\"char\"], will inject the given keypress event.", +		keySomething + "keypress event.\n" + keyExplain + '\n' + mask,  		&LLWindowListener::keyDown);  	add("keyUp", -		"Given [\"keycode\"] or [\"char\"], will inject the given key release event.", +		keySomething + "key release event.\n" + keyExplain + '\n' + mask,  		&LLWindowListener::keyUp);  	add("mouseDown", -		"Given [\"button\"], [\"x\"] and [\"y\"], will inject the given mouse click event.", +		mouseSomething + "click event.\n" + mouseExplain + '\n' + mask,  		&LLWindowListener::mouseDown);  	add("mouseUp", -		"Given [\"button\"], [\"x\"] and [\"y\"], will inject the given mouse release event.", +		mouseSomething + "release event.\n" + mouseExplain + '\n' + mask,  		&LLWindowListener::mouseUp);  	add("mouseMove", -		"Given [\"x\"] and [\"y\"], will inject the given mouse movement event.", +		std::string("Given [\"x\"] and [\"y\"], inject the given mouse movement event.\n") + +		mask,  		&LLWindowListener::mouseMove);  	add("mouseScroll", -		"Given a number of [\"clicks\"], will inject the given mouse scroll event.", +		"Given an integer number of [\"clicks\"], inject the given mouse scroll event.\n" +		"(positive clicks moves downward through typical content)",  		&LLWindowListener::mouseScroll);  } -void LLWindowListener::keyDown(LLSD const & evt) +template <typename MAPPED> +class StringLookup  { -	if(NULL == mKeyboard) -	{ -		// *HACK to handle the fact that LLWindow subclasses have to initialize -		// things in an inconvenient order -		mKeyboard = gKeyboard; -	} +private: +	std::string mDesc; +	typedef std::map<std::string, MAPPED> Map; +	Map mMap; + +public: +	StringLookup(const std::string& desc): mDesc(desc) {} -	KEY keycode = 0; -	if(evt.has("keycode")) +	MAPPED lookup(const typename Map::key_type& key) const  	{ -		keycode = KEY(evt["keycode"].asInteger()); +		typename Map::const_iterator found = mMap.find(key); +		if (found == mMap.end()) +		{ +			LL_WARNS("LLWindowListener") << "Unknown " << mDesc << " '" << key << "'" << LL_ENDL; +			return MAPPED(); +		} +		return found->second;  	} -	else + +protected: +	void add(const typename Map::key_type& key, const typename Map::mapped_type& value)  	{ -		keycode = KEY(evt["char"].asString()[0]); +		mMap.insert(typename Map::value_type(key, value));  	} +}; -	// *TODO - figure out how to handle the mask -	mKeyboard->handleTranslatedKeyDown(keycode, 0); -} +// for WhichKeysym. KeyProxy is like the typedef KEY, except that KeyProxy() +// (default-constructed) is guaranteed to have the value KEY_NONE. +class KeyProxy +{ +public: +	KeyProxy(KEY k): mKey(k) {} +	KeyProxy(): mKey(KEY_NONE) {} +	operator KEY() const { return mKey; } -void LLWindowListener::keyUp(LLSD const & evt) +private: +	KEY mKey; +}; + +struct WhichKeysym: public StringLookup<KeyProxy>  { -	if(NULL == mKeyboard) +	WhichKeysym(): StringLookup<KeyProxy>("keysym")  	{ -		// *HACK to handle the fact that LLWindow subclasses have to initialize -		// things in an inconvenient order -		mKeyboard = gKeyboard; +		add("RETURN",		KEY_RETURN); +		add("LEFT",			KEY_LEFT); +		add("RIGHT",		KEY_RIGHT); +		add("UP",			KEY_UP); +		add("DOWN",			KEY_DOWN); +		add("ESCAPE",		KEY_ESCAPE); +		add("BACKSPACE",	KEY_BACKSPACE); +		add("DELETE",		KEY_DELETE); +		add("SHIFT",		KEY_SHIFT); +		add("CONTROL",		KEY_CONTROL); +		add("ALT",			KEY_ALT); +		add("HOME",			KEY_HOME); +		add("END",			KEY_END); +		add("PAGE_UP",		KEY_PAGE_UP); +		add("PAGE_DOWN",	KEY_PAGE_DOWN); +		add("HYPHEN",		KEY_HYPHEN); +		add("EQUALS",		KEY_EQUALS); +		add("INSERT",		KEY_INSERT); +		add("CAPSLOCK",		KEY_CAPSLOCK); +		add("TAB",			KEY_TAB); +		add("ADD",			KEY_ADD); +		add("SUBTRACT",		KEY_SUBTRACT); +		add("MULTIPLY",		KEY_MULTIPLY); +		add("DIVIDE",		KEY_DIVIDE); +		add("F1",			KEY_F1); +		add("F2",			KEY_F2); +		add("F3",			KEY_F3); +		add("F4",			KEY_F4); +		add("F5",			KEY_F5); +		add("F6",			KEY_F6); +		add("F7",			KEY_F7); +		add("F8",			KEY_F8); +		add("F9",			KEY_F9); +		add("F10",			KEY_F10); +		add("F11",			KEY_F11); +		add("F12",			KEY_F12); + +		add("PAD_UP",		KEY_PAD_UP); +		add("PAD_DOWN",		KEY_PAD_DOWN); +		add("PAD_LEFT",		KEY_PAD_LEFT); +		add("PAD_RIGHT",	KEY_PAD_RIGHT); +		add("PAD_HOME",		KEY_PAD_HOME); +		add("PAD_END",		KEY_PAD_END); +		add("PAD_PGUP",		KEY_PAD_PGUP); +		add("PAD_PGDN",		KEY_PAD_PGDN); +		add("PAD_CENTER",	KEY_PAD_CENTER); // the 5 in the middle +		add("PAD_INS",		KEY_PAD_INS); +		add("PAD_DEL",		KEY_PAD_DEL); +		add("PAD_RETURN",	KEY_PAD_RETURN); +		add("PAD_ADD",		KEY_PAD_ADD); // not used +		add("PAD_SUBTRACT", KEY_PAD_SUBTRACT); // not used +		add("PAD_MULTIPLY", KEY_PAD_MULTIPLY); // not used +		add("PAD_DIVIDE",	KEY_PAD_DIVIDE); // not used + +		add("BUTTON0",		KEY_BUTTON0); +		add("BUTTON1",		KEY_BUTTON1); +		add("BUTTON2",		KEY_BUTTON2); +		add("BUTTON3",		KEY_BUTTON3); +		add("BUTTON4",		KEY_BUTTON4); +		add("BUTTON5",		KEY_BUTTON5); +		add("BUTTON6",		KEY_BUTTON6); +		add("BUTTON7",		KEY_BUTTON7); +		add("BUTTON8",		KEY_BUTTON8); +		add("BUTTON9",		KEY_BUTTON9); +		add("BUTTON10",		KEY_BUTTON10); +		add("BUTTON11",		KEY_BUTTON11); +		add("BUTTON12",		KEY_BUTTON12); +		add("BUTTON13",		KEY_BUTTON13); +		add("BUTTON14",		KEY_BUTTON14); +		add("BUTTON15",		KEY_BUTTON15);  	} +}; +static WhichKeysym keysyms; -	KEY keycode = 0; -	if(evt.has("keycode")) +struct WhichMask: public StringLookup<MASK> +{ +	WhichMask(): StringLookup<MASK>("shift mask")  	{ -		keycode = KEY(evt["keycode"].asInteger()); +		add("NONE",			MASK_NONE); +		add("CONTROL",		MASK_CONTROL); // Mapped to cmd on Macs +		add("ALT",			MASK_ALT); +		add("SHIFT",		MASK_SHIFT); +		add("MAC_CONTROL",	MASK_MAC_CONTROL); // Un-mapped Ctrl key on Macs, not used on Windows  	} -	else +}; +static WhichMask masks; + +static MASK getMask(const LLSD& event) +{ +	MASK mask(MASK_NONE); +	LLSD masknames(event["mask"]); +	for (LLSD::array_const_iterator ai(masknames.beginArray()), aend(masknames.endArray()); +		 ai != aend; ++ai)  	{ -		keycode = KEY(evt["char"].asString()[0]); +		mask |= masks.lookup(*ai);  	} - -	// *TODO - figure out how to handle the mask -	mKeyboard->handleTranslatedKeyDown(keycode, 0); +	return mask;  } -void LLWindowListener::mouseDown(LLSD const & evt) +static KEY getKEY(const LLSD& event)  { -	LLCoordGL pos(evt["x"].asInteger(), evt["y"].asInteger()); - -	std::string const & button = evt["button"].asString(); - -	if(button == "LEFT") -	{ -		// *TODO - figure out how to handle the mask -		mWindow->handleMouseDown(NULL, pos, 0); -	} -	else if (button == "RIGHT") +    if (event.has("keysym"))  	{ -		// *TODO - figure out how to handle the mask -		mWindow->handleRightMouseDown(NULL, pos, 0); +		return keysyms.lookup(event["keysym"]);  	} -	else if (button == "MIDDLE") +	else if (event.has("keycode"))  	{ -		// *TODO - figure out how to handle the mask -		mWindow->handleMiddleMouseDown(NULL, pos, 0); +		return KEY(event["keycode"].asInteger());  	}  	else  	{ -		llwarns << "ignoring unknown mous button \"" << button << '\"' << llendl; +		return KEY(event["char"].asString()[0]);  	}  } -void LLWindowListener::mouseUp(LLSD const & evt) +void LLWindowListener::keyDown(LLSD const & evt) +{ +	mKbGetter()->handleTranslatedKeyDown(getKEY(evt), getMask(evt)); +} + +void LLWindowListener::keyUp(LLSD const & evt)  { -	LLCoordGL pos(evt["x"].asInteger(), evt["y"].asInteger()); +	mKbGetter()->handleTranslatedKeyUp(getKEY(evt), getMask(evt)); +} -	std::string const & button = evt["button"].asString(); +// for WhichButton +typedef BOOL (LLWindowCallbacks::*MouseFunc)(LLWindow *, LLCoordGL, MASK); +struct Actions +{ +	Actions(const MouseFunc& d, const MouseFunc& u): down(d), up(u), valid(true) {} +	Actions(): valid(false) {} +	MouseFunc down, up; +	bool valid; +}; -	if(button == "LEFT") -	{ -		// *TODO - figure out how to handle the mask -		mWindow->handleMouseUp(NULL, pos, 0); -	} -	else if (button == "RIGHT") +struct WhichButton: public StringLookup<Actions> +{ +	WhichButton(): StringLookup<Actions>("mouse button")  	{ -		// *TODO - figure out how to handle the mask -		mWindow->handleRightMouseUp(NULL, pos, 0); +		add("LEFT",		Actions(&LLWindowCallbacks::handleMouseDown, +								&LLWindowCallbacks::handleMouseUp)); +		add("RIGHT",	Actions(&LLWindowCallbacks::handleRightMouseDown, +								&LLWindowCallbacks::handleRightMouseUp)); +		add("MIDDLE",	Actions(&LLWindowCallbacks::handleMiddleMouseDown, +								&LLWindowCallbacks::handleMiddleMouseUp));  	} -	else if (button == "MIDDLE") +}; +static WhichButton buttons; + +static LLCoordGL getPos(const LLSD& event) +{ +	return LLCoordGL(event["x"].asInteger(), event["y"].asInteger()); +} + +void LLWindowListener::mouseDown(LLSD const & evt) +{ +	Actions actions(buttons.lookup(evt["button"])); +	if (actions.valid)  	{ -		// *TODO - figure out how to handle the mask -		mWindow->handleMiddleMouseUp(NULL, pos, 0); +		(mWindow->*(actions.down))(NULL, getPos(evt), getMask(evt));  	} -	else +} + +void LLWindowListener::mouseUp(LLSD const & evt) +{ +	Actions actions(buttons.lookup(evt["button"])); +	if (actions.valid)  	{ -		llwarns << "ignoring unknown mous button \"" << button << '\"' << llendl; +		(mWindow->*(actions.up))(NULL, getPos(evt), getMask(evt));  	}  }  void LLWindowListener::mouseMove(LLSD const & evt)  { -	LLCoordGL pos(evt["x"].asInteger(), evt["y"].asInteger()); - -	// *TODO - figure out how to handle the mask -	mWindow->handleMouseMove(NULL, pos, 0); +	mWindow->handleMouseMove(NULL, getPos(evt), getMask(evt));  }  void LLWindowListener::mouseScroll(LLSD const & evt) diff --git a/indra/llwindow/llwindowlistener.h b/indra/llwindow/llwindowlistener.h index 5b234c5d1d..74e577ff93 100644 --- a/indra/llwindow/llwindowlistener.h +++ b/indra/llwindow/llwindowlistener.h @@ -28,6 +28,7 @@  #define LL_LLWINDOWLISTENER_H  #include "lleventapi.h" +#include <boost/function.hpp>  class LLKeyboard;  class LLWindowCallbacks; @@ -35,7 +36,8 @@ class LLWindowCallbacks;  class LLWindowListener : public LLEventAPI  {  public: -	LLWindowListener(LLWindowCallbacks * window, LLKeyboard * keyboard); +	typedef boost::function<LLKeyboard*()> KeyboardGetter; +	LLWindowListener(LLWindowCallbacks * window, const KeyboardGetter& kbgetter);  	void keyDown(LLSD const & evt);  	void keyUp(LLSD const & evt); @@ -46,7 +48,7 @@ public:  private:  	LLWindowCallbacks * mWindow; -	LLKeyboard * mKeyboard; +	KeyboardGetter mKbGetter;  }; | 
