summaryrefslogtreecommitdiff
path: root/indra/newview/llviewerinput.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llviewerinput.cpp')
-rw-r--r--indra/newview/llviewerinput.cpp364
1 files changed, 308 insertions, 56 deletions
diff --git a/indra/newview/llviewerinput.cpp b/indra/newview/llviewerinput.cpp
index c0eaa88f54..43b9cd90bd 100644
--- a/indra/newview/llviewerinput.cpp
+++ b/indra/newview/llviewerinput.cpp
@@ -38,6 +38,7 @@
#include "llkeybind.h" // LLKeyData
#include "llmorphview.h"
#include "llmoveview.h"
+#include "llsetkeybinddialog.h"
#include "lltoolfocus.h"
#include "lltoolpie.h"
#include "llviewercontrol.h"
@@ -60,8 +61,21 @@ const F32 ORBIT_NUDGE_RATE = 0.05f; // fraction of normal speed
const LLKeyData agent_control_lbutton(CLICK_LEFT, KEY_NONE, MASK_NONE, true);
+struct LLKeybindFunctionData
+{
+ LLKeybindFunctionData(boost::function<bool(EKeystate keystate)> function, bool global)
+ :
+ mFunction(function),
+ mIsGlobal(global)
+ {
+ }
+ boost::function<bool(EKeystate keystate)> mFunction;
+ // todo: might be good idea to make this into enum, like: global/inworld/menu
+ bool mIsGlobal;
+};
+
struct LLKeyboardActionRegistry
-: public LLRegistrySingleton<std::string, boost::function<bool (EKeystate keystate)>, LLKeyboardActionRegistry>
+: public LLRegistrySingleton<const std::string, LLKeybindFunctionData, LLKeyboardActionRegistry>
{
LLSINGLETON_EMPTY_CTOR(LLKeyboardActionRegistry);
};
@@ -802,13 +816,20 @@ bool toggle_enable_media(EKeystate s)
bool walk_to(EKeystate s)
{
- if (KEYSTATE_DOWN != s) return true;
+ if (KEYSTATE_DOWN != s)
+ {
+ // teleport/walk is usually on mouseclick, mouseclick needs
+ // to let AGENT_CONTROL_LBUTTON_UP happen if teleport didn't,
+ // so return false, but if it causes issues, do some kind of
+ // "return !has_teleported"
+ return false;
+ }
return LLToolPie::getInstance()->walkToClickedLocation();
}
bool teleport_to(EKeystate s)
{
- if (KEYSTATE_DOWN != s) return true;
+ if (KEYSTATE_DOWN != s) return false;
return LLToolPie::getInstance()->teleportToClickedLocation();
}
@@ -836,7 +857,47 @@ bool voice_follow_key(EKeystate s)
return false;
}
-bool agen_control_lbutton_handle(EKeystate s)
+bool script_trigger_lbutton(EKeystate s)
+{
+ // Check for script overriding/expecting left mouse button.
+ // Note that this does not pass event further and depends onto mouselook.
+ // Checks CONTROL_ML_LBUTTON_DOWN_INDEX for mouselook,
+ // CONTROL_LBUTTON_DOWN_INDEX for normal camera
+ if (gAgent.leftButtonGrabbed())
+ {
+ bool mouselook = gAgentCamera.cameraMouselook();
+ switch (s)
+ {
+ case KEYSTATE_DOWN:
+ if (mouselook)
+ {
+ gAgent.setControlFlags(AGENT_CONTROL_ML_LBUTTON_DOWN);
+ }
+ else
+ {
+ gAgent.setControlFlags(AGENT_CONTROL_LBUTTON_DOWN);
+ }
+ return true;
+ case KEYSTATE_UP:
+ if (mouselook)
+ {
+ gAgent.setControlFlags(AGENT_CONTROL_ML_LBUTTON_UP);
+ }
+ else
+ {
+ gAgent.setControlFlags(AGENT_CONTROL_LBUTTON_UP);
+ }
+ return true;
+ default:
+ break;
+ }
+ }
+ return false;
+}
+
+// Used by scripts, for overriding/handling left mouse button
+// see mControlsTakenCount
+bool agent_control_lbutton_handle(EKeystate s)
{
switch (s)
{
@@ -852,7 +913,10 @@ bool agen_control_lbutton_handle(EKeystate s)
return true;
}
-#define REGISTER_KEYBOARD_ACTION(KEY, ACTION) LLREGISTER_STATIC(LLKeyboardActionRegistry, KEY, ACTION);
+// In-world keybindings, like walking or camera
+#define REGISTER_KEYBOARD_ACTION(KEY, ACTION) LLREGISTER_STATIC(LLKeyboardActionRegistry, KEY, LLKeybindFunctionData(ACTION, false));
+// Global keybindings that should work even with floaters focused, like voice
+#define REGISTER_KEYBOARD_GLOBAL_ACTION(KEY, ACTION) LLREGISTER_STATIC(LLKeyboardActionRegistry, KEY, LLKeybindFunctionData(ACTION, true));
REGISTER_KEYBOARD_ACTION("jump", agent_jump);
REGISTER_KEYBOARD_ACTION("push_down", agent_push_down);
REGISTER_KEYBOARD_ACTION("push_forward", agent_push_forward);
@@ -903,8 +967,9 @@ REGISTER_KEYBOARD_ACTION("toggle_pause_media", toggle_pause_media);
REGISTER_KEYBOARD_ACTION("toggle_enable_media", toggle_enable_media);
REGISTER_KEYBOARD_ACTION("teleport_to", teleport_to);
REGISTER_KEYBOARD_ACTION("walk_to", walk_to);
-REGISTER_KEYBOARD_ACTION("toggle_voice", toggle_voice);
-REGISTER_KEYBOARD_ACTION("voice_follow_key", voice_follow_key);
+REGISTER_KEYBOARD_GLOBAL_ACTION("toggle_voice", toggle_voice);
+REGISTER_KEYBOARD_GLOBAL_ACTION("voice_follow_key", voice_follow_key);
+REGISTER_KEYBOARD_ACTION(script_mouse_handler_name, script_trigger_lbutton);
#undef REGISTER_KEYBOARD_ACTION
LLViewerInput::LLViewerInput()
@@ -1034,6 +1099,53 @@ BOOL LLViewerInput::handleKeyUp(KEY translated_key, MASK translated_mask)
return gViewerWindow->handleKeyUp(translated_key, translated_mask);
}
+bool LLViewerInput::handleGlobalBindsKeyDown(KEY key, MASK mask)
+{
+ if (LLSetKeyBindDialog::isRecording())
+ {
+ // handleGlobalBindsKeyDown happens before view handling, so can't
+ // be interupted by LLSetKeyBindDialog, check manually
+ return false;
+ }
+ S32 mode = getMode();
+ return scanKey(mGlobalKeyBindings[mode], mGlobalKeyBindings[mode].size(), key, mask, TRUE, FALSE, FALSE, FALSE);
+}
+
+bool LLViewerInput::handleGlobalBindsKeyUp(KEY key, MASK mask)
+{
+ if (LLSetKeyBindDialog::isRecording())
+ {
+ // handleGlobalBindsKeyUp happens before view handling, so can't
+ // be interupted by LLSetKeyBindDialog, check manually
+ return false;
+ }
+
+ S32 mode = getMode();
+ return scanKey(mGlobalKeyBindings[mode], mGlobalKeyBindings[mode].size(), key, mask, FALSE, TRUE, FALSE, FALSE);
+}
+
+bool LLViewerInput::handleGlobalBindsMouse(EMouseClickType clicktype, MASK mask, bool down)
+{
+ if (LLSetKeyBindDialog::isRecording())
+ {
+ // handleGlobalBindsMouse happens before view handling, so can't
+ // be interupted by LLSetKeyBindDialog, check manually
+ return false;
+ }
+
+ bool res = false;
+ S32 mode = getMode();
+ if (down)
+ {
+ res = scanMouse(mGlobalMouseBindings[mode], mGlobalMouseBindings[mode].size(), clicktype, mask, MOUSE_STATE_DOWN, true);
+ }
+ else
+ {
+ res = scanMouse(mGlobalMouseBindings[mode], mGlobalMouseBindings[mode].size(), clicktype, mask, MOUSE_STATE_UP, true);
+ }
+ return res;
+}
+
BOOL LLViewerInput::bindKey(const S32 mode, const KEY key, const MASK mask, const std::string& function_name)
{
S32 index;
@@ -1061,39 +1173,64 @@ BOOL LLViewerInput::bindKey(const S32 mode, const KEY key, const MASK mask, cons
}
// Not remapped, look for a function
-
- function_t* result = LLKeyboardActionRegistry::getValue(function_name);
+
+ LLKeybindFunctionData* result = LLKeyboardActionRegistry::getValue(function_name);
if (result)
{
- function = *result;
+ function = result->mFunction;
}
if (!function)
{
- LL_ERRS() << "Can't bind key to function " << function_name << ", no function with this name found" << LL_ENDL;
+ LL_WARNS_ONCE() << "Can't bind key to function " << function_name << ", no function with this name found" << LL_ENDL;
return FALSE;
}
- // check for duplicate first and overwrite
- S32 size = mKeyBindings[mode].size();
- for (index = 0; index < size; index++)
+ if (mode >= MODE_COUNT)
{
- if (key == mKeyBindings[mode][index].mKey && mask == mKeyBindings[mode][index].mMask)
- break;
+ LL_ERRS() << "LLKeyboard::bindKey() - unknown mode passed" << mode << LL_ENDL;
+ return FALSE;
}
- if (mode >= MODE_COUNT)
- {
- LL_ERRS() << "LLKeyboard::bindKey() - unknown mode passed" << mode << LL_ENDL;
- return FALSE;
- }
+ // check for duplicate first and overwrite
+ if (result->mIsGlobal)
+ {
+ S32 size = mGlobalKeyBindings[mode].size();
+ for (index = 0; index < size; index++)
+ {
+ if (key == mGlobalKeyBindings[mode][index].mKey && mask == mGlobalKeyBindings[mode][index].mMask)
+ {
+ mGlobalKeyBindings[mode][index].mFunction = function;
+ return TRUE;
+ }
+ }
+ }
+ else
+ {
+ S32 size = mKeyBindings[mode].size();
+ for (index = 0; index < size; index++)
+ {
+ if (key == mKeyBindings[mode][index].mKey && mask == mKeyBindings[mode][index].mMask)
+ {
+ mKeyBindings[mode][index].mFunction = function;
+ return TRUE;
+ }
+ }
+ }
LLKeyboardBinding bind;
bind.mKey = key;
bind.mMask = mask;
bind.mFunction = function;
- mKeyBindings[mode].push_back(bind);
+ if (result->mIsGlobal)
+ {
+ mGlobalKeyBindings[mode].push_back(bind);
+ }
+ else
+ {
+ mKeyBindings[mode].push_back(bind);
+ }
return TRUE;
}
@@ -1104,24 +1241,30 @@ BOOL LLViewerInput::bindMouse(const S32 mode, const EMouseClickType mouse, const
typedef boost::function<bool(EKeystate)> function_t;
function_t function = NULL;
- function_t* result = LLKeyboardActionRegistry::getValue(function_name);
- if (result)
+ if (mouse == CLICK_LEFT
+ && mask == MASK_NONE
+ && function_name == script_mouse_handler_name)
{
- function = *result;
+ // Special case
+ // Left click has script overrides and by default
+ // is handled via agent_control_lbutton as last option
+ // In case of mouselook and present overrides it has highest
+ // priority even over UI and is handled in LLToolCompGun::handleMouseDown
+ // so just mark it as having default handler
+ mLMouseDefaultHandling[mode] = true;
+ return TRUE;
}
- if (!function)
+ LLKeybindFunctionData* result = LLKeyboardActionRegistry::getValue(function_name);
+ if (result)
{
- LL_ERRS() << "Can't bind key to function " << function_name << ", no function with this name found" << LL_ENDL;
- return FALSE;
+ function = result->mFunction;
}
- // check for duplicate first and overwrite
- S32 size = mMouseBindings[mode].size();
- for (index = 0; index < size; index++)
+ if (!function)
{
- if (mouse == mMouseBindings[mode][index].mMouse && mask == mMouseBindings[mode][index].mMask)
- break;
+ LL_WARNS_ONCE() << "Can't bind mouse key to function " << function_name << ", no function with this name found" << LL_ENDL;
+ return FALSE;
}
if (mode >= MODE_COUNT)
@@ -1130,12 +1273,45 @@ BOOL LLViewerInput::bindMouse(const S32 mode, const EMouseClickType mouse, const
return FALSE;
}
+ // check for duplicate first and overwrite
+ if (result->mIsGlobal)
+ {
+ S32 size = mGlobalMouseBindings[mode].size();
+ for (index = 0; index < size; index++)
+ {
+ if (mouse == mGlobalMouseBindings[mode][index].mMouse && mask == mGlobalMouseBindings[mode][index].mMask)
+ {
+ mGlobalMouseBindings[mode][index].mFunction = function;
+ return true;
+ }
+ }
+ }
+ else
+ {
+ S32 size = mMouseBindings[mode].size();
+ for (index = 0; index < size; index++)
+ {
+ if (mouse == mMouseBindings[mode][index].mMouse && mask == mMouseBindings[mode][index].mMask)
+ {
+ mMouseBindings[mode][index].mFunction = function;
+ return true;
+ }
+ }
+ }
+
LLMouseBinding bind;
bind.mMouse = mouse;
bind.mMask = mask;
bind.mFunction = function;
- mMouseBindings[mode].push_back(bind);
+ if (result->mIsGlobal)
+ {
+ mGlobalMouseBindings[mode].push_back(bind);
+ }
+ else
+ {
+ mMouseBindings[mode].push_back(bind);
+ }
return TRUE;
}
@@ -1155,15 +1331,19 @@ LLViewerInput::Keys::Keys()
: first_person("first_person"),
third_person("third_person"),
sitting("sitting"),
- edit_avatar("edit_avatar")
+ edit_avatar("edit_avatar"),
+ xml_version("xml_version", 0)
{}
void LLViewerInput::resetBindings()
{
for (S32 i = 0; i < MODE_COUNT; i++)
{
+ mGlobalKeyBindings[i].clear();
+ mGlobalMouseBindings[i].clear();
mKeyBindings[i].clear();
mMouseBindings[i].clear();
+ mLMouseDefaultHandling[i] = false;
}
}
@@ -1182,6 +1362,65 @@ S32 LLViewerInput::loadBindingsXML(const std::string& filename)
binding_count += loadBindingMode(keys.third_person, MODE_THIRD_PERSON);
binding_count += loadBindingMode(keys.sitting, MODE_SITTING);
binding_count += loadBindingMode(keys.edit_avatar, MODE_EDIT_AVATAR);
+
+ // verify version
+ if (keys.xml_version < 1)
+ {
+ // updating from a version that was not aware of LMouse bindings
+ for (S32 i = 0; i < MODE_COUNT; i++)
+ {
+ mLMouseDefaultHandling[i] = true;
+ }
+
+ // fix missing values
+ KeyBinding mouse_binding;
+ mouse_binding.key = "";
+ mouse_binding.mask = "NONE";
+ mouse_binding.mouse = "LMB";
+ mouse_binding.command = script_mouse_handler_name;
+
+ if (keys.third_person.isProvided())
+ {
+ keys.third_person.bindings.add(mouse_binding);
+ }
+
+ if (keys.first_person.isProvided())
+ {
+ keys.first_person.bindings.add(mouse_binding);
+ }
+
+ if (keys.sitting.isProvided())
+ {
+ keys.sitting.bindings.add(mouse_binding);
+ }
+
+ if (keys.edit_avatar.isProvided())
+ {
+ keys.edit_avatar.bindings.add(mouse_binding);
+ }
+
+ // fix version
+ keys.xml_version.set(keybindings_xml_version, true);
+
+ // Write the resulting XML to file
+ LLXMLNodePtr output_node = new LLXMLNode("keys", false);
+ LLXUIParser write_parser;
+ write_parser.writeXUI(output_node, keys);
+
+ if (!output_node->isNull())
+ {
+ // file in app_settings is supposed to be up to date
+ // this is only for the file from user_settings
+ LL_INFOS("ViewerInput") << "Updating file " << filename << " to a newer version" << LL_ENDL;
+ LLFILE *fp = LLFile::fopen(filename, "w");
+ if (fp != NULL)
+ {
+ LLXMLNode::writeHeaderToFile(fp);
+ output_node->writeToFile(fp);
+ fclose(fp);
+ }
+ }
+ }
}
return binding_count;
}
@@ -1353,17 +1592,6 @@ bool LLViewerInput::scanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level)
bool res = scanKey(mKeyBindings[mode], mKeyBindings[mode].size(), key, mask, key_down, key_up, key_level, repeat);
- if (!res && agent_control_lbutton.canHandle(CLICK_NONE, key, mask))
- {
- if (key_down && !repeat)
- {
- res = agen_control_lbutton_handle(KEYSTATE_DOWN);
- }
- if (key_up)
- {
- res = agen_control_lbutton_handle(KEYSTATE_UP);
- }
- }
return res;
}
@@ -1439,11 +1667,18 @@ BOOL LLViewerInput::handleMouse(LLWindow *window_impl, LLCoordGL pos, MASK mask,
return handled;
}
-bool LLViewerInput::scanMouse(const std::vector<LLMouseBinding> &binding, S32 binding_count, EMouseClickType mouse, MASK mask, EMouseState state) const
+bool LLViewerInput::scanMouse(
+ const std::vector<LLMouseBinding> &binding,
+ S32 binding_count,
+ EMouseClickType mouse,
+ MASK mask,
+ EMouseState state,
+ bool ignore_additional_masks
+) const
{
for (S32 i = 0; i < binding_count; i++)
{
- if (binding[i].mMouse == mouse && (binding[i].mMask & mask) == binding[i].mMask)
+ if (binding[i].mMouse == mouse && (ignore_additional_masks ? (binding[i].mMask & mask) == binding[i].mMask : binding[i].mMask == mask))
{
bool res = false;
switch (state)
@@ -1480,25 +1715,36 @@ bool LLViewerInput::scanMouse(EMouseClickType click, EMouseState state) const
bool res = false;
S32 mode = getMode();
MASK mask = gKeyboard->currentMask(TRUE);
- res = scanMouse(mMouseBindings[mode], mMouseBindings[mode].size(), click, mask, state);
- // no user defined actions found or those actions can't handle the key/button, handle control if nessesary
- if (!res && agent_control_lbutton.canHandle(click, KEY_NONE, mask))
+ res = scanMouse(mMouseBindings[mode], mMouseBindings[mode].size(), click, mask, state, false);
+
+ // No user defined actions found or those actions can't handle the key/button,
+ // so handle CONTROL_LBUTTON if nessesary.
+ //
+ // Default handling for MODE_FIRST_PERSON is in LLToolCompGun::handleMouseDown,
+ // and sends AGENT_CONTROL_ML_LBUTTON_DOWN, but it only applies if ML controls
+ // are leftButtonGrabbed(), send a normal click otherwise.
+
+ if (!res
+ && mLMouseDefaultHandling[mode]
+ && (mode != MODE_FIRST_PERSON || !gAgent.leftButtonGrabbed())
+ && (click == CLICK_LEFT || click == CLICK_DOUBLELEFT)
+ )
{
switch (state)
{
case MOUSE_STATE_DOWN:
- agen_control_lbutton_handle(KEYSTATE_DOWN);
+ agent_control_lbutton_handle(KEYSTATE_DOWN);
res = true;
break;
case MOUSE_STATE_CLICK:
// might not work best with some functions,
// but some function need specific states too specifically
- agen_control_lbutton_handle(KEYSTATE_DOWN);
- agen_control_lbutton_handle(KEYSTATE_UP);
+ agent_control_lbutton_handle(KEYSTATE_DOWN);
+ agent_control_lbutton_handle(KEYSTATE_UP);
res = true;
break;
case MOUSE_STATE_UP:
- agen_control_lbutton_handle(KEYSTATE_UP);
+ agent_control_lbutton_handle(KEYSTATE_UP);
res = true;
break;
default:
@@ -1528,7 +1774,7 @@ void LLViewerInput::scanMouse()
}
}
-bool LLViewerInput::isMouseBindUsed(const EMouseClickType mouse, const MASK mask, const S32 mode)
+bool LLViewerInput::isMouseBindUsed(const EMouseClickType mouse, const MASK mask, const S32 mode) const
{
S32 size = mMouseBindings[mode].size();
for (S32 index = 0; index < size; index++)
@@ -1536,5 +1782,11 @@ bool LLViewerInput::isMouseBindUsed(const EMouseClickType mouse, const MASK mask
if (mouse == mMouseBindings[mode][index].mMouse && mask == mMouseBindings[mode][index].mMask)
return true;
}
+ size = mGlobalMouseBindings[mode].size();
+ for (S32 index = 0; index < size; index++)
+ {
+ if (mouse == mGlobalMouseBindings[mode][index].mMouse && mask == mGlobalMouseBindings[mode][index].mMask)
+ return true;
+ }
return false;
}