SL-13418 Added converter from old mouse binding settings to new ones

master
Andrey Kleshchev 2020-06-15 18:13:46 +03:00
parent ceea2df596
commit d07ef7df92
5 changed files with 182 additions and 3 deletions

View File

@ -53,7 +53,7 @@ public:
EMouseClickType mMouse;
KEY mKey;
MASK mMask;
// Either to expect exact match or ignore not expected masks
// Either to expect exact match or ignore not expected masks as long as expected mask-bit is present
bool mIgnoreMasks;
};

View File

@ -224,7 +224,6 @@
<binding key="DIVIDE" mask="NONE" command="start_gesture"/>
<binding key="" mask="NONE" mouse="MMB" command="toggle_voice"/>
<binding key="" mask="NONE" mouse="LMB" command="walk_to"/>
</sitting>
<edit_avatar>
<!--Avatar editing camera controls-->

View File

@ -49,6 +49,7 @@
#include "llwindow.h"
#include "llviewerstats.h"
#include "llviewerstatsrecorder.h"
#include "llkeyconflict.h" // for legacy keybinding support, remove later
#include "llmarketplacefunctions.h"
#include "llmarketplacenotifications.h"
#include "llmd5.h"
@ -1004,6 +1005,104 @@ bool LLAppViewer::init()
// Load User's bindings
std::string key_bindings_file = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "key_bindings.xml");
#if 1
// Legacy support
// Remove #if-#endif section half a year after DRTVWR-501 releases.
// Mouse actions are part of keybinding file since DRTVWR-501 instead of being stored in
// settings.xml. To support legacy viewers that were storing in settings.xml we need to
// transfer old variables to new format.
// Also part of backward compatibility is present in LLKeyConflictHandler to modify
// legacy variables on changes in new system (to make sure we won't enforce
// legacy values again if user dropped to defaults in new system)
if (mIsFirstRun
&& !gDirUtilp->fileExists(key_bindings_file)) // if file is missing, assume that there were no changes by user yet
{
// copy mouse actions and voice key changes to new file
LL_INFOS("InitInfo") << "Converting legacy mouse bindings to new format" << LL_ENDL;
// Load settings from file
LLKeyConflictHandler third_person_view(LLKeyConflictHandler::MODE_THIRD_PERSON);
// Since we are only modifying keybindings if personal file doesn't exist yet,
// it should be safe to just overwrite the value
// If key is already in use somewhere by default, LLKeyConflictHandler should resolve it.
BOOL value = gSavedSettings.getBOOL("DoubleClickAutoPilot");
third_person_view.registerControl("walk_to",
0,
value ? EMouseClickType::CLICK_DOUBLELEFT : EMouseClickType::CLICK_NONE,
KEY_NONE,
MASK_NONE,
value);
U32 index = value ? 1 : 0; // we can store multiple combinations per action, so if first is in use by doubleclick, go to second
value = gSavedSettings.getBOOL("ClickToWalk");
third_person_view.registerControl("walk_to",
index,
value ? EMouseClickType::CLICK_LEFT : EMouseClickType::CLICK_NONE,
KEY_NONE,
MASK_NONE,
value);
value = gSavedSettings.getBOOL("DoubleClickTeleport");
third_person_view.registerControl("teleport_to",
0,
value ? EMouseClickType::CLICK_DOUBLELEFT : EMouseClickType::CLICK_NONE,
KEY_NONE,
MASK_NONE,
value);
std::string key_string = gSavedSettings.getString("PushToTalkButton");
EMouseClickType mouse = EMouseClickType::CLICK_NONE;
KEY key = KEY_NONE;
if (key_string == "MiddleMouse")
{
mouse = EMouseClickType::CLICK_MIDDLE;
}
else if (key_string == "MouseButton4")
{
mouse = EMouseClickType::CLICK_BUTTON4;
}
else if (key_string == "MouseButton5")
{
mouse = EMouseClickType::CLICK_BUTTON5;
}
else
{
LLKeyboard::keyFromString(key_string, &key);
}
value = gSavedSettings.getBOOL("PushToTalkToggle");
std::string control_name = value ? "toggle_voice" : "voice_follow_key";
third_person_view.registerControl(control_name, 0, mouse, key, MASK_NONE, true);
if (third_person_view.hasUnsavedChanges())
{
// calls loadBindingsXML()
third_person_view.saveToSettings();
}
// in case of voice we need to repeat this in other modes (teleports and
// autopilot are not entirely practical when sitting or editing)
for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT - 1; ++i)
{
if (i != LLKeyConflictHandler::MODE_THIRD_PERSON)
{
LLKeyConflictHandler handler((LLKeyConflictHandler::ESourceMode)i);
handler.registerControl(control_name, 0, mouse, key, MASK_NONE, true);
if (handler.hasUnsavedChanges())
{
// calls loadBindingsXML()
handler.saveToSettings();
}
}
}
}
// since something might have gone wrong or there might have been nothing to save
// (and because otherwise following code will have to be encased in else{}),
// load everything one last time
#endif
if (!gDirUtilp->fileExists(key_bindings_file) || !gViewerInput.loadBindingsXML(key_bindings_file))
{
// Failed to load custom bindings, try default ones

View File

@ -427,7 +427,7 @@ void LLKeyConflictHandler::saveToSettings(bool temporary)
else if (!key.mKeyBind.empty())
{
// Note: this is currently not in use, might be better for load mechanics to ask for and retain control group
// otherwise settings loaded from other control groups will end in this one
// otherwise settings loaded from other control groups will end in gSavedSettings
LL_INFOS() << "Creating new keybinding " << iter->first << LL_ENDL;
gSavedSettings.declareLLSD(iter->first, key.mKeyBind.asLLSD(), "comment", LLControlVariable::PERSIST_ALWAYS);
}
@ -598,6 +598,71 @@ void LLKeyConflictHandler::saveToSettings(bool temporary)
// will remove any temporary file if there were any
clearUnsavedChanges();
}
#if 1
// Legacy support
// Remove #if-#endif section half a year after DRTVWR-501 releases.
// Update legacy settings in settings.xml
// We only care for third person view since legacy settings can't store
// more than one mode.
// We are saving this even if we are in temporary mode - preferences
// will restore values on cancel
if (mLoadMode == MODE_THIRD_PERSON)
{
bool value = canHandleMouse("walk_to", CLICK_DOUBLELEFT, MASK_NONE);
gSavedSettings.setBOOL("DoubleClickAutoPilot", value);
value = canHandleMouse("walk_to", CLICK_LEFT, MASK_NONE);
gSavedSettings.setBOOL("ClickToWalk", value);
value = canHandleMouse("teleport_to", CLICK_DOUBLELEFT, MASK_NONE);
gSavedSettings.setBOOL("DoubleClickTeleport", value);
// new method can save both toggle and push-to-talk values simultaneously,
// but legacy one can save only one. It also doesn't support mask.
LLKeyData data = getControl("toggle_voice", 0);
bool can_toggle = !data.isEmpty();
if (!can_toggle)
{
data = getControl("voice_follow_key", 0);
}
gSavedSettings.setBOOL("PushToTalkToggle", can_toggle);
if (data.isEmpty())
{
// legacy viewer has a bug that might crash it if NONE value is assigned.
// just reset to default
gSavedSettings.getControl("PushToTalkButton")->resetToDefault(false);
}
else
{
if (data.mKey != KEY_NONE)
{
gSavedSettings.setString("PushToTalkButton", LLKeyboard::stringFromKey(data.mKey));
}
else
{
std::string ctrl_value;
switch (data.mMouse)
{
case CLICK_MIDDLE:
ctrl_value = "MiddleMouse";
break;
case CLICK_BUTTON4:
ctrl_value = "MouseButton4";
break;
case CLICK_BUTTON5:
ctrl_value = "MouseButton5";
break;
default:
ctrl_value = "MiddleMouse";
break;
}
gSavedSettings.setString("PushToTalkButton", ctrl_value);
}
}
}
#endif
}
LLKeyData LLKeyConflictHandler::getDefaultControl(const std::string &control_name, U32 index)

View File

@ -82,6 +82,18 @@ public:
bool canAssignControl(const std::string &control_name);
static bool isReservedByMenu(const KEY &key, const MASK &mask);
static bool isReservedByMenu(const LLKeyData &data);
// @control_name - see REGISTER_KEYBOARD_ACTION in llviewerinput for avaliable options,
// usually this is just name of the function
// @data_index - single control (function) can have multiple key combinations trigering
// it, this index indicates combination function will change/add note that preferences
// floater can only display up to 3 options, but data_index can be bigger then that
// @mouse_ind - mouse action (middle click, MB5 etc)
// @key - keyboard key action
// @mask - shift/ctrl/alt flags
// @ignore_mask - Either to expect exact match (ctrl+K will not trigger if ctrl+shift+K
// is active) or ignore not expected masks as long as expected mask is present
// (ctrl+K will be triggered if ctrl+shift+K is active)
bool registerControl(const std::string &control_name, U32 data_index, EMouseClickType mouse_ind, KEY key, MASK mask, bool ignore_mask); //todo: return conflicts?
LLKeyData getControl(const std::string &control_name, U32 data_index);
@ -101,6 +113,10 @@ public:
// 'temporary' does not support gSavedSettings, those are handled
// by preferences, so 'temporary' is such case will simply not
// reset mHasUnsavedChanges
//
// 'temporary' exists to support ability of live-editing settings in
// preferences: temporary for testing changes 'live' without saving them,
// then hitting ok/cancel and save/discard values permanently.
void saveToSettings(bool apply_temporary = false);
LLKeyData getDefaultControl(const std::string &control_name, U32 data_index);