summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDon Kjer <don@lindenlab.com>2011-03-23 01:34:26 +0000
committerDon Kjer <don@lindenlab.com>2011-03-23 01:34:26 +0000
commitbdaaa6de1384a39de5a452729bebea49d8242a67 (patch)
tree052550a07fdda090c05ebbbdb9ecc8936563161a
parent1e0608ff51efc69a14010f2ce5dba3acabe16e49 (diff)
parentfa4359e571fb67aca651efc3403274cdf0bb2616 (diff)
Merge with https://hg.lindenlab.com/nat/viewer-eventapi2
-rw-r--r--indra/llwindow/llwindow.cpp7
-rw-r--r--indra/llwindow/llwindowlistener.cpp279
-rw-r--r--indra/llwindow/llwindowlistener.h6
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 59f4c89e34..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->handleTranslatedKeyUp(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;
};