SL-6109 Keyaboard support ready
parent
3633ccf1a1
commit
4df05c5a89
|
|
@ -36,6 +36,11 @@ LLKeyData::LLKeyData()
|
|||
{
|
||||
}
|
||||
|
||||
LLKeyData::LLKeyData(EMouseClickType mouse, KEY key, MASK mask)
|
||||
: mMouse(mouse), mKey(key), mMask(mask)
|
||||
{
|
||||
}
|
||||
|
||||
LLKeyData::LLKeyData(const LLSD &key_data)
|
||||
{
|
||||
mMouse = (EMouseClickType)key_data["mouse"].asInteger();
|
||||
|
|
@ -72,65 +77,100 @@ LLKeyData& LLKeyData::operator=(const LLKeyData& rhs)
|
|||
return *this;
|
||||
}
|
||||
|
||||
bool LLKeyData::operator==(const LLKeyData& rhs)
|
||||
{
|
||||
if (mMouse != rhs.mMouse) return false;
|
||||
if (mKey != rhs.mKey) return false;
|
||||
if (mMask != rhs.mMask) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LLKeyData::operator!=(const LLKeyData& rhs)
|
||||
{
|
||||
if (mMouse != rhs.mMouse) return true;
|
||||
if (mKey != rhs.mKey) return true;
|
||||
if (mMask != rhs.mMask) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// LLKeyBind
|
||||
|
||||
LLKeyBind::LLKeyBind(const LLSD &key_bind)
|
||||
{
|
||||
if (key_bind.has("DataPrimary"))
|
||||
if (key_bind.isArray())
|
||||
{
|
||||
mDataPrimary = LLKeyData(key_bind["DataPrimary"]);
|
||||
}
|
||||
if (key_bind.has("DataSecondary"))
|
||||
{
|
||||
mDataSecondary = LLKeyData(key_bind["DataSecondary"]);
|
||||
for (LLSD::array_const_iterator data = key_bind.beginArray(), endLists = key_bind.endArray();
|
||||
data != endLists;
|
||||
data++
|
||||
)
|
||||
{
|
||||
mData.push_back(LLKeyData(*data));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool LLKeyBind::operator==(const LLKeyBind& rhs)
|
||||
{
|
||||
if (mDataPrimary.mMouse != rhs.mDataPrimary.mMouse) return false;
|
||||
if (mDataPrimary.mKey != rhs.mDataPrimary.mKey) return false;
|
||||
if (mDataPrimary.mMask != rhs.mDataPrimary.mMask) return false;
|
||||
if (mDataSecondary.mMouse != rhs.mDataSecondary.mMouse) return false;
|
||||
if (mDataSecondary.mKey != rhs.mDataSecondary.mKey) return false;
|
||||
if (mDataSecondary.mMask != rhs.mDataSecondary.mMask) return false;
|
||||
U32 size = mData.size();
|
||||
if (size != rhs.mData.size()) return false;
|
||||
|
||||
for (U32 i = 0; i < size; i++)
|
||||
{
|
||||
if (mData[i] != rhs.mData[i]) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LLKeyBind::empty()
|
||||
bool LLKeyBind::operator!=(const LLKeyBind& rhs)
|
||||
{
|
||||
if (mDataPrimary.mMouse != CLICK_NONE) return false;
|
||||
if (mDataPrimary.mKey != KEY_NONE) return false;
|
||||
if (mDataPrimary.mMask != MASK_NONE) return false;
|
||||
if (mDataSecondary.mMouse != CLICK_NONE) return false;
|
||||
if (mDataSecondary.mKey != KEY_NONE) return false;
|
||||
if (mDataSecondary.mMask != MASK_NONE) return false;
|
||||
U32 size = mData.size();
|
||||
if (size != rhs.mData.size()) return true;
|
||||
|
||||
for (U32 i = 0; i < size; i++)
|
||||
{
|
||||
if (mData[i] != rhs.mData[i]) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool LLKeyBind::isEmpty() const
|
||||
{
|
||||
for (data_vector_t::const_iterator iter = mData.begin(); iter != mData.end(); iter++)
|
||||
{
|
||||
if (!iter->isEmpty()) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
LLSD LLKeyBind::asLLSD() const
|
||||
{
|
||||
LLSD data;
|
||||
if (!mDataPrimary.isEmpty())
|
||||
for (data_vector_t::const_iterator iter = mData.begin(); iter != mData.end(); iter++)
|
||||
{
|
||||
data["DataPrimary"] = mDataPrimary.asLLSD();
|
||||
}
|
||||
if (!mDataSecondary.isEmpty())
|
||||
{
|
||||
data["DataSecondary"] = mDataSecondary.asLLSD();
|
||||
if (!iter->isEmpty())
|
||||
{
|
||||
data.append(iter->asLLSD());
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
bool LLKeyBind::canHandle(EMouseClickType mouse, KEY key, MASK mask) const
|
||||
{
|
||||
if (mDataPrimary.mKey == key && mDataPrimary.mMask == mask && mDataPrimary.mMouse == mouse)
|
||||
if (mouse == CLICK_NONE && key == KEY_NONE)
|
||||
{
|
||||
return true;
|
||||
// assume placeholder
|
||||
return false;
|
||||
}
|
||||
if (mDataSecondary.mKey == key && mDataSecondary.mMask == mask && mDataSecondary.mMouse == mouse)
|
||||
|
||||
for (data_vector_t::const_iterator iter = mData.begin(); iter != mData.end(); iter++)
|
||||
{
|
||||
return true;
|
||||
if (iter->mKey == key && iter->mMask == mask && iter->mMouse == mouse)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
@ -145,3 +185,85 @@ bool LLKeyBind::canHandleMouse(EMouseClickType mouse, MASK mask) const
|
|||
return canHandle(mouse, KEY_NONE, mask);
|
||||
}
|
||||
|
||||
bool LLKeyBind::addKeyData(EMouseClickType mouse, KEY key, MASK mask)
|
||||
{
|
||||
if (!canHandle(mouse, key, mask))
|
||||
{
|
||||
mData.push_back(LLKeyData(mouse, key, mask));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool LLKeyBind::addKeyData(const LLKeyData& data)
|
||||
{
|
||||
if (!canHandle(data.mMouse, data.mKey, data.mMask))
|
||||
{
|
||||
mData.push_back(data);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void LLKeyBind::replaceKeyData(EMouseClickType mouse, KEY key, MASK mask, U32 index)
|
||||
{
|
||||
if (mouse != CLICK_NONE && key != KEY_NONE && mask != MASK_NONE)
|
||||
{
|
||||
for (data_vector_t::const_iterator iter = mData.begin(); iter != mData.end(); iter++)
|
||||
{
|
||||
if (iter->mKey == key && iter->mMask == mask && iter->mMouse == mouse)
|
||||
{
|
||||
mData.erase(iter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mData.size() > index)
|
||||
{
|
||||
mData[index] = LLKeyData(mouse, key, mask);
|
||||
}
|
||||
else
|
||||
{
|
||||
mData.push_back(LLKeyData(mouse, key, mask));
|
||||
}
|
||||
}
|
||||
|
||||
void LLKeyBind::replaceKeyData(const LLKeyData& data, U32 index)
|
||||
{
|
||||
for (data_vector_t::const_iterator iter = mData.begin(); iter != mData.end(); iter++)
|
||||
{
|
||||
if (iter->mKey == data.mKey && iter->mMask == data.mMask && iter->mMouse == data.mMouse)
|
||||
{
|
||||
mData.erase(iter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (mData.size() > index)
|
||||
{
|
||||
mData[index] = data;
|
||||
}
|
||||
else
|
||||
{
|
||||
mData.push_back(data);
|
||||
}
|
||||
}
|
||||
|
||||
bool LLKeyBind::hasKeyData(U32 index) const
|
||||
{
|
||||
return mData.size() > index;
|
||||
}
|
||||
|
||||
LLKeyData LLKeyBind::getKeyData(U32 index) const
|
||||
{
|
||||
if (mData.size() > index)
|
||||
{
|
||||
return mData[index];
|
||||
}
|
||||
return LLKeyData();
|
||||
}
|
||||
|
||||
U32 LLKeyBind::getDataCount()
|
||||
{
|
||||
return mData.size();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -34,12 +34,16 @@ class LL_COMMON_API LLKeyData
|
|||
{
|
||||
public:
|
||||
LLKeyData();
|
||||
LLKeyData(EMouseClickType mouse, KEY key, MASK mask);
|
||||
LLKeyData(const LLSD &key_data);
|
||||
|
||||
LLSD asLLSD() const;
|
||||
bool isEmpty() const;
|
||||
bool empty() const { return isEmpty(); };
|
||||
void reset();
|
||||
LLKeyData& operator=(const LLKeyData& rhs);
|
||||
bool operator==(const LLKeyData& rhs);
|
||||
bool operator!=(const LLKeyData& rhs);
|
||||
|
||||
EMouseClickType mMouse;
|
||||
KEY mKey;
|
||||
|
|
@ -54,7 +58,9 @@ public:
|
|||
LLKeyBind(const LLSD &key_bind);
|
||||
|
||||
bool operator==(const LLKeyBind& rhs);
|
||||
bool empty();
|
||||
bool operator!=(const LLKeyBind& rhs);
|
||||
bool isEmpty() const;
|
||||
bool empty() const { return isEmpty(); };
|
||||
|
||||
LLSD asLLSD() const;
|
||||
|
||||
|
|
@ -62,8 +68,19 @@ public:
|
|||
bool canHandleKey(KEY key, MASK mask) const;
|
||||
bool canHandleMouse(EMouseClickType mouse, MASK mask) const;
|
||||
|
||||
LLKeyData mDataPrimary;
|
||||
LLKeyData mDataSecondary;
|
||||
// these methods enshure there will be no repeats
|
||||
bool addKeyData(EMouseClickType mouse, KEY key, MASK mask);
|
||||
bool addKeyData(const LLKeyData& data);
|
||||
void replaceKeyData(EMouseClickType mouse, KEY key, MASK mask, U32 index);
|
||||
void replaceKeyData(const LLKeyData& data, U32 index);
|
||||
bool hasKeyData(U32 index) const;
|
||||
void clear() { mData.clear(); };
|
||||
LLKeyData getKeyData(U32 index) const;
|
||||
U32 getDataCount();
|
||||
|
||||
private:
|
||||
typedef std::vector<LLKeyData> data_vector_t;
|
||||
data_vector_t mData;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -130,6 +130,7 @@ LLScrollListCtrl::Params::Params()
|
|||
search_column("search_column", 0),
|
||||
sort_column("sort_column", -1),
|
||||
sort_ascending("sort_ascending", true),
|
||||
can_sort("can_sort", true),
|
||||
mouse_wheel_opaque("mouse_wheel_opaque", false),
|
||||
commit_on_keyboard_movement("commit_on_keyboard_movement", true),
|
||||
heading_height("heading_height"),
|
||||
|
|
@ -166,6 +167,7 @@ LLScrollListCtrl::LLScrollListCtrl(const LLScrollListCtrl::Params& p)
|
|||
mSelectionChanged(false),
|
||||
mNeedsScroll(false),
|
||||
mCanSelect(true),
|
||||
mCanSort(p.can_sort),
|
||||
mColumnsDirty(false),
|
||||
mMaxItemCount(INT_MAX),
|
||||
mBorderThickness( 2 ),
|
||||
|
|
@ -2801,6 +2803,8 @@ void LLScrollListCtrl::onClickColumn(void *userdata)
|
|||
LLScrollListCtrl *parent = info->mParentCtrl;
|
||||
if (!parent) return;
|
||||
|
||||
if (!parent->mCanSort) return;
|
||||
|
||||
S32 column_index = info->mIndex;
|
||||
|
||||
LLScrollListColumn* column = parent->mColumnsIndexed[info->mIndex];
|
||||
|
|
|
|||
|
|
@ -115,7 +115,8 @@ public:
|
|||
// sort and search behavior
|
||||
Optional<S32> search_column,
|
||||
sort_column;
|
||||
Optional<bool> sort_ascending;
|
||||
Optional<bool> sort_ascending,
|
||||
can_sort; // whether user is allowed to sort
|
||||
|
||||
// colors
|
||||
Optional<LLUIColor> fg_unselected_color,
|
||||
|
|
@ -460,6 +461,7 @@ private:
|
|||
bool mNeedsScroll;
|
||||
bool mMouseWheelOpaque;
|
||||
bool mCanSelect;
|
||||
bool mCanSort; // Whether user is allowed to sort
|
||||
bool mDisplayColumnHeaders;
|
||||
bool mColumnsDirty;
|
||||
bool mColumnWidthsDirty;
|
||||
|
|
|
|||
|
|
@ -376,6 +376,7 @@ set(viewer_SOURCE_FILES
|
|||
llinventoryobserver.cpp
|
||||
llinventorypanel.cpp
|
||||
lljoystickbutton.cpp
|
||||
llkeyconflict.cpp
|
||||
lllandmarkactions.cpp
|
||||
lllandmarklist.cpp
|
||||
lllegacyatmospherics.cpp
|
||||
|
|
@ -1007,6 +1008,7 @@ set(viewer_HEADER_FILES
|
|||
llinventoryobserver.h
|
||||
llinventorypanel.h
|
||||
lljoystickbutton.h
|
||||
llkeyconflict.h
|
||||
lllandmarkactions.h
|
||||
lllandmarklist.h
|
||||
lllightconstants.h
|
||||
|
|
|
|||
|
|
@ -52,7 +52,6 @@
|
|||
#include "llfavoritesbar.h"
|
||||
#include "llfloatersidepanelcontainer.h"
|
||||
#include "llfloaterimsession.h"
|
||||
#include "llkeybindings.h"
|
||||
#include "llkeyboard.h"
|
||||
#include "llmodaldialog.h"
|
||||
#include "llnavigationbar.h"
|
||||
|
|
@ -72,8 +71,9 @@
|
|||
#include "lltrans.h"
|
||||
#include "llviewercontrol.h"
|
||||
#include "llviewercamera.h"
|
||||
#include "llviewerwindow.h"
|
||||
#include "llviewereventrecorder.h"
|
||||
#include "llviewermessage.h"
|
||||
#include "llviewerwindow.h"
|
||||
#include "llviewershadermgr.h"
|
||||
#include "llviewerthrottle.h"
|
||||
#include "llvoavatarself.h"
|
||||
|
|
@ -160,36 +160,49 @@ struct LabelTable : public LLInitParam::Block<LabelTable>
|
|||
{}
|
||||
};
|
||||
|
||||
class LLVoiceSetKeyDialog : public LLModalDialog
|
||||
// Filters for LLSetKeyBindDialog
|
||||
static const U32 ALLOW_MOUSE = 1;
|
||||
static const U32 ALLOW_MASK_MOUSE = 2;
|
||||
static const U32 ALLOW_KEYS = 4; //keyboard
|
||||
static const U32 ALLOW_MASK_KEYS = 8;
|
||||
static const U32 ALLOW_MASKS = 16;
|
||||
static const U32 IGNORE_MASKS = 32; // For example W (aka Forward) should work regardless of SHIFT being pressed
|
||||
static const U32 DEFAULT_KEY_FILTER = ALLOW_MOUSE | ALLOW_MASK_MOUSE | ALLOW_KEYS | ALLOW_MASK_KEYS;
|
||||
|
||||
class LLSetKeyBindDialog : public LLModalDialog
|
||||
{
|
||||
public:
|
||||
LLVoiceSetKeyDialog(const LLSD& key);
|
||||
~LLVoiceSetKeyDialog();
|
||||
|
||||
LLSetKeyBindDialog(const LLSD& key);
|
||||
~LLSetKeyBindDialog();
|
||||
|
||||
/*virtual*/ BOOL postBuild();
|
||||
|
||||
void setParent(LLFloaterPreference* parent) { mParent = parent; }
|
||||
void setTmpParent(LLPanelPreferenceControls* parent) { mTmpParent = parent; } // todo: voice key will be removed, class renamved, so it will have only one parent
|
||||
|
||||
|
||||
void setParent(LLPanelPreferenceControls* parent, U32 key_mask = DEFAULT_KEY_FILTER);
|
||||
|
||||
BOOL handleKeyHere(KEY key, MASK mask);
|
||||
BOOL handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down);
|
||||
static void onCancel(void* user_data);
|
||||
|
||||
static void onBlank(void* user_data);
|
||||
static void onDefault(void* user_data);
|
||||
|
||||
private:
|
||||
LLFloaterPreference* mParent;
|
||||
LLPanelPreferenceControls* mTmpParent;// todo: voice key will be removed, class renamved, so it will have only one parent
|
||||
LLPanelPreferenceControls* mParent;
|
||||
|
||||
U32 mKeyMask;
|
||||
};
|
||||
|
||||
LLVoiceSetKeyDialog::LLVoiceSetKeyDialog(const LLSD& key)
|
||||
LLSetKeyBindDialog::LLSetKeyBindDialog(const LLSD& key)
|
||||
: LLModalDialog(key),
|
||||
mParent(NULL),
|
||||
mTmpParent(NULL)
|
||||
mKeyMask(DEFAULT_KEY_FILTER)
|
||||
{
|
||||
}
|
||||
|
||||
//virtual
|
||||
BOOL LLVoiceSetKeyDialog::postBuild()
|
||||
BOOL LLSetKeyBindDialog::postBuild()
|
||||
{
|
||||
childSetAction("SetEmpty", onBlank, this);
|
||||
childSetAction("Default", onDefault, this);
|
||||
childSetAction("Cancel", onCancel, this);
|
||||
getChild<LLUICtrl>("Cancel")->setFocus(TRUE);
|
||||
|
||||
|
|
@ -198,47 +211,85 @@ BOOL LLVoiceSetKeyDialog::postBuild()
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
LLVoiceSetKeyDialog::~LLVoiceSetKeyDialog()
|
||||
void LLSetKeyBindDialog::setParent(LLPanelPreferenceControls* parent, U32 key_mask)
|
||||
{
|
||||
mParent = parent;
|
||||
mKeyMask = key_mask;
|
||||
|
||||
LLTextBase *text_ctrl = getChild<LLTextBase>("descritption");
|
||||
|
||||
std::string input;
|
||||
if ((key_mask & ALLOW_MOUSE) != 0)
|
||||
{
|
||||
input = getString("mouse");
|
||||
}
|
||||
if ((key_mask & ALLOW_KEYS) != 0)
|
||||
{
|
||||
if (!input.empty())
|
||||
{
|
||||
input += ", ";
|
||||
}
|
||||
input += getString("keyboard");
|
||||
}
|
||||
text_ctrl->setTextArg("[INPUT]", input);
|
||||
}
|
||||
|
||||
LLSetKeyBindDialog::~LLSetKeyBindDialog()
|
||||
{
|
||||
}
|
||||
|
||||
BOOL LLVoiceSetKeyDialog::handleKeyHere(KEY key, MASK mask)
|
||||
BOOL LLSetKeyBindDialog::handleKeyHere(KEY key, MASK mask)
|
||||
{
|
||||
BOOL result = TRUE;
|
||||
|
||||
if (key == KEY_CONTROL || key == KEY_SHIFT || key == KEY_ALT || key == KEY_NONE)
|
||||
if ((key == 'Q' && mask == MASK_CONTROL)
|
||||
|| key == KEY_ESCAPE)
|
||||
{
|
||||
closeFloater();
|
||||
return true;
|
||||
}
|
||||
|
||||
// forbidden keys
|
||||
if (key == KEY_NONE
|
||||
|| key == KEY_RETURN
|
||||
|| key == KEY_DELETE
|
||||
|| key == KEY_BACKSPACE)
|
||||
{
|
||||
// temp
|
||||
return false;
|
||||
}
|
||||
|
||||
// todo, same for escape
|
||||
if (key == 'Q' && mask == MASK_CONTROL)
|
||||
{
|
||||
result = FALSE;
|
||||
if (mTmpParent)
|
||||
{
|
||||
mTmpParent->onSetKey(KEY_NONE, MASK_NONE);
|
||||
}
|
||||
|
||||
if ((mKeyMask & ALLOW_MASKS) == 0
|
||||
&& (key == KEY_CONTROL || key == KEY_SHIFT || key == KEY_ALT))
|
||||
{
|
||||
// mask by themself are not allowed
|
||||
return false;
|
||||
}
|
||||
else if ((mKeyMask & ALLOW_KEYS) == 0)
|
||||
{
|
||||
// basic keys not allowed
|
||||
return false;
|
||||
}
|
||||
else if ((mKeyMask & ALLOW_MASK_KEYS) == 0 && mask != 0)
|
||||
{
|
||||
// masked keys not allowed
|
||||
return false;
|
||||
}
|
||||
|
||||
else if (mParent)
|
||||
{
|
||||
mParent->setKey(key);
|
||||
}
|
||||
else if (mTmpParent)
|
||||
{
|
||||
mTmpParent->onSetKey(key, mask);
|
||||
mParent->onSetKeyBind(CLICK_NONE, key, mask);
|
||||
}
|
||||
closeFloater();
|
||||
return result;
|
||||
}
|
||||
|
||||
BOOL LLVoiceSetKeyDialog::handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down)
|
||||
BOOL LLSetKeyBindDialog::handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down)
|
||||
{
|
||||
BOOL result = FALSE;
|
||||
|
||||
if (clicktype == CLICK_LEFT)
|
||||
{
|
||||
// try handling buttons first
|
||||
if (down)
|
||||
{
|
||||
result = LLView::handleMouseDown(x, y, mask);
|
||||
|
|
@ -248,30 +299,21 @@ BOOL LLVoiceSetKeyDialog::handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseCli
|
|||
result = LLView::handleMouseUp(x, y, mask);
|
||||
}
|
||||
}
|
||||
if (clicktype == LLMouseHandler::CLICK_LEFT)
|
||||
{
|
||||
result = LLView::handleDoubleClick(x, y, mask);
|
||||
}
|
||||
if (result)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
if (down && clicktype != LLMouseHandler::CLICK_RIGHT) //tmp
|
||||
//&& (clicktype == LLMouseHandler::CLICK_MIDDLE || clicktype == LLMouseHandler::CLICK_BUTTON4 || clicktype == LLMouseHandler::CLICK_BUTTON5)
|
||||
//&& mask == 0)
|
||||
|
||||
if (!result
|
||||
&& ((mKeyMask & ALLOW_MOUSE) != 0)
|
||||
&& (clicktype != CLICK_RIGHT || mask != 0) // reassigning menu button is not supported
|
||||
&& ((mKeyMask & ALLOW_MASK_MOUSE) != 0 || mask == 0))
|
||||
{
|
||||
if (mParent)
|
||||
{
|
||||
mParent->setMouse(clicktype);
|
||||
}
|
||||
else if (mTmpParent)
|
||||
{
|
||||
mTmpParent->onSetMouse(clicktype, mask);
|
||||
mParent->onSetKeyBind(clicktype, KEY_NONE, mask);
|
||||
}
|
||||
result = TRUE;
|
||||
closeFloater();
|
||||
}
|
||||
else
|
||||
|
||||
if (!result)
|
||||
{
|
||||
result = LLMouseHandler::handleAnyMouseClick(x, y, mask, clicktype, down);
|
||||
}
|
||||
|
|
@ -280,17 +322,36 @@ BOOL LLVoiceSetKeyDialog::handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseCli
|
|||
}
|
||||
|
||||
//static
|
||||
void LLVoiceSetKeyDialog::onCancel(void* user_data)
|
||||
void LLSetKeyBindDialog::onCancel(void* user_data)
|
||||
{
|
||||
LLVoiceSetKeyDialog* self = (LLVoiceSetKeyDialog*)user_data;
|
||||
// tmp needs 'no key' button
|
||||
if (self->mTmpParent)
|
||||
{
|
||||
self->mTmpParent->onSetKey(KEY_NONE, MASK_NONE);
|
||||
}
|
||||
LLSetKeyBindDialog* self = (LLSetKeyBindDialog*)user_data;
|
||||
self->closeFloater();
|
||||
}
|
||||
|
||||
//static
|
||||
void LLSetKeyBindDialog::onBlank(void* user_data)
|
||||
{
|
||||
LLSetKeyBindDialog* self = (LLSetKeyBindDialog*)user_data;
|
||||
// tmp needs 'no key' button
|
||||
if (self->mParent)
|
||||
{
|
||||
self->mParent->onSetKeyBind(CLICK_NONE, KEY_NONE, MASK_NONE);
|
||||
}
|
||||
self->closeFloater();
|
||||
}
|
||||
|
||||
//static
|
||||
void LLSetKeyBindDialog::onDefault(void* user_data)
|
||||
{
|
||||
LLSetKeyBindDialog* self = (LLSetKeyBindDialog*)user_data;
|
||||
// tmp needs 'no key' button
|
||||
if (self->mParent)
|
||||
{
|
||||
self->mParent->onDefaultKeyBind();
|
||||
}
|
||||
self->closeFloater();
|
||||
}
|
||||
|
||||
|
||||
// global functions
|
||||
|
||||
|
|
@ -370,37 +431,6 @@ void handleAppearanceCameraMovementChanged(const LLSD& newvalue)
|
|||
}
|
||||
}
|
||||
|
||||
/*bool callback_skip_dialogs(const LLSD& notification, const LLSD& response, LLFloaterPreference* floater)
|
||||
{
|
||||
S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
|
||||
if (0 == option && floater )
|
||||
{
|
||||
if ( floater )
|
||||
{
|
||||
floater->setAllIgnored();
|
||||
// LLFirstUse::disableFirstUse();
|
||||
floater->buildPopupLists();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool callback_reset_dialogs(const LLSD& notification, const LLSD& response, LLFloaterPreference* floater)
|
||||
{
|
||||
S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
|
||||
if ( 0 == option && floater )
|
||||
{
|
||||
if ( floater )
|
||||
{
|
||||
floater->resetAllIgnored();
|
||||
//LLFirstUse::resetFirstUse();
|
||||
floater->buildPopupLists();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
|
||||
void fractionFromDecimal(F32 decimal_val, S32& numerator, S32& denominator)
|
||||
{
|
||||
numerator = 0;
|
||||
|
|
@ -435,7 +465,7 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key)
|
|||
static bool registered_dialog = false;
|
||||
if (!registered_dialog)
|
||||
{
|
||||
LLFloaterReg::add("voice_set_key", "floater_select_key.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLVoiceSetKeyDialog>);
|
||||
LLFloaterReg::add("keybind_dialog", "floater_select_key.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLSetKeyBindDialog>);
|
||||
registered_dialog = true;
|
||||
}
|
||||
|
||||
|
|
@ -1711,53 +1741,6 @@ void LLFloaterPreference::onChangeQuality(const LLSD& data)
|
|||
|
||||
void LLFloaterPreference::onClickSetKey()
|
||||
{
|
||||
LLVoiceSetKeyDialog* dialog = LLFloaterReg::showTypedInstance<LLVoiceSetKeyDialog>("voice_set_key", LLSD(), TRUE);
|
||||
if (dialog)
|
||||
{
|
||||
dialog->setParent(this);
|
||||
}
|
||||
}
|
||||
|
||||
void LLFloaterPreference::setKey(KEY key)
|
||||
{
|
||||
getChild<LLUICtrl>("modifier_combo")->setValue(LLKeyboard::stringFromKey(key));
|
||||
// update the control right away since we no longer wait for apply
|
||||
getChild<LLUICtrl>("modifier_combo")->onCommit();
|
||||
}
|
||||
|
||||
void LLFloaterPreference::setMouse(EMouseClickType click)
|
||||
{
|
||||
std::string bt_name;
|
||||
std::string ctrl_value;
|
||||
switch (click)
|
||||
{
|
||||
case CLICK_MIDDLE:
|
||||
bt_name = "middle_mouse";
|
||||
ctrl_value = MIDDLE_MOUSE_CV;
|
||||
break;
|
||||
case CLICK_BUTTON4:
|
||||
bt_name = "button4_mouse";
|
||||
ctrl_value = MOUSE_BUTTON_4_CV;
|
||||
break;
|
||||
case CLICK_BUTTON5:
|
||||
bt_name = "button5_mouse";
|
||||
ctrl_value = MOUSE_BUTTON_5_CV;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!ctrl_value.empty())
|
||||
{
|
||||
LLUICtrl* p2t_line_editor = getChild<LLUICtrl>("modifier_combo");
|
||||
// We are using text control names for readability and compatibility with voice
|
||||
p2t_line_editor->setControlValue(ctrl_value);
|
||||
LLPanel* advanced_preferences = dynamic_cast<LLPanel*>(p2t_line_editor->getParent());
|
||||
if (advanced_preferences)
|
||||
{
|
||||
p2t_line_editor->setValue(advanced_preferences->getString(bt_name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLFloaterPreference::onClickSetMiddleMouse()
|
||||
|
|
@ -1782,18 +1765,6 @@ void LLFloaterPreference::onClickSetSounds()
|
|||
getChild<LLCheckBoxCtrl>("gesture_audio_play_btn")->setEnabled(!gSavedSettings.getBOOL("MuteSounds"));
|
||||
}
|
||||
|
||||
/*
|
||||
void LLFloaterPreference::onClickSkipDialogs()
|
||||
{
|
||||
LLNotificationsUtil::add("SkipShowNextTimeDialogs", LLSD(), LLSD(), boost::bind(&callback_skip_dialogs, _1, _2, this));
|
||||
}
|
||||
|
||||
void LLFloaterPreference::onClickResetDialogs()
|
||||
{
|
||||
LLNotificationsUtil::add("ResetShowNextTimeDialogs", LLSD(), LLSD(), boost::bind(&callback_reset_dialogs, _1, _2, this));
|
||||
}
|
||||
*/
|
||||
|
||||
void LLFloaterPreference::onClickEnablePopup()
|
||||
{
|
||||
LLScrollListCtrl& disabled_popups = getChildRef<LLScrollListCtrl>("disabled_popups");
|
||||
|
|
@ -2794,7 +2765,7 @@ void LLPanelPreferenceGraphics::setPresetText()
|
|||
}
|
||||
}
|
||||
|
||||
if (hasDirtyChilds() && !preset_graphic_active.empty())
|
||||
if (hasDirtyChilds() && !preset_graphic_active.empty())
|
||||
{
|
||||
gSavedSettings.setString("PresetGraphicActive", "");
|
||||
preset_graphic_active.clear();
|
||||
|
|
@ -2914,98 +2885,124 @@ void LLPanelPreferenceGraphics::setHardwareDefaults()
|
|||
resetDirtyChilds();
|
||||
}
|
||||
|
||||
|
||||
//-------------------For LLPanelPreferenceControls' list---------------------------
|
||||
class LLGroupControlsListItem : public LLScrollListItem, public LLHandleProvider<LLGroupControlsListItem>
|
||||
{
|
||||
public:
|
||||
LLGroupControlsListItem(const LLScrollListItem::Params& p)
|
||||
: LLScrollListItem(p)
|
||||
{
|
||||
}
|
||||
|
||||
LLGroupControlsListItem(const LLScrollListItem::Params& p, const LLUUID& icon_id)
|
||||
: LLScrollListItem(p), mIconId(icon_id)
|
||||
{
|
||||
}
|
||||
|
||||
void draw(const LLRect& rect, const LLColor4& fg_color, const LLColor4& bg_color, const LLColor4& highlight_color, S32 column_padding)
|
||||
{
|
||||
// todo: insert image and adjust rect
|
||||
LLScrollListItem::draw(rect, fg_color, bg_color, highlight_color, column_padding);
|
||||
}
|
||||
private:
|
||||
LLUUID mIconId;
|
||||
};
|
||||
|
||||
static const std::string tmp_typetostring[LLControlBindings::CONTROL_NUM_INDICES] = {
|
||||
"control_view_actions",
|
||||
"control_about",
|
||||
"control_orbit",
|
||||
"control_pan",
|
||||
"control_world_map",
|
||||
"control_zoom",
|
||||
"control_interactions",
|
||||
"control_build",
|
||||
"control_drag",
|
||||
"control_edit",
|
||||
"control_menu",
|
||||
"control_open",
|
||||
"control_touch",
|
||||
"control_wear",
|
||||
"control_movements",
|
||||
"control_moveto",
|
||||
"control_sit",
|
||||
"control_teleportto",
|
||||
"control_forward",
|
||||
"control_backward",
|
||||
"control_left",
|
||||
"control_right",
|
||||
"control_lstrafe",
|
||||
"control_rstrafe",
|
||||
"control_jump",
|
||||
"control_down",
|
||||
"control_run",
|
||||
"control_toggle_run",
|
||||
"control_fly",
|
||||
"control_mediacontent",
|
||||
"control_parcel",
|
||||
"control_media",
|
||||
"control_voice",
|
||||
"control_toggle_voice",
|
||||
"control_reserved",
|
||||
"control_menu",
|
||||
"control_reserved_select",
|
||||
"control_shift_select",
|
||||
"control_cntrl_select"
|
||||
};
|
||||
|
||||
//------------------------LLPanelPreferenceControls--------------------------------
|
||||
static LLPanelInjector<LLPanelPreferenceControls> t_pref_contrls("panel_preference_controls");
|
||||
|
||||
LLPanelPreferenceControls::LLPanelPreferenceControls()
|
||||
:LLPanelPreference(),
|
||||
mEditingIndex(-1),
|
||||
mEditingColumn(-1),
|
||||
mEditingMode(0),
|
||||
mShowKeyDialog(false)
|
||||
{
|
||||
}
|
||||
|
||||
LLPanelPreferenceControls::~LLPanelPreferenceControls()
|
||||
{
|
||||
}
|
||||
|
||||
BOOL LLPanelPreferenceControls::postBuild()
|
||||
{
|
||||
//todo: on open instead of on the go
|
||||
//todo: add pitch/yaw?
|
||||
//todo: Scroll?
|
||||
//todo: should be auto-expandable with menu items and should pull names from menu when possible
|
||||
|
||||
|
||||
// populate list of controls
|
||||
pControlsTable = getChild<LLScrollListCtrl>("controls_list");
|
||||
populateControlTable();
|
||||
pKeyModeBox = getChild<LLComboBox>("key_mode");
|
||||
|
||||
pControlsTable->setCommitCallback(boost::bind(&LLPanelPreferenceControls::onListCommit, this));
|
||||
pKeyModeBox->setCommitCallback(boost::bind(&LLPanelPreferenceControls::onModeCommit, this));
|
||||
getChild<LLButton>("restore_defaults")->setCommitCallback(boost::bind(&LLPanelPreferenceControls::onRestoreDefaults, this));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Something of a workaround: cells don't handle clicks, so we catch a click, then process it on hover.
|
||||
BOOL LLPanelPreferenceControls::handleHover(S32 x, S32 y, MASK mask)
|
||||
{
|
||||
if (mShowKeyDialog)
|
||||
{
|
||||
if (mEditingIndex > 0 && mConflictHandler[mEditingMode].canAssignControl((LLKeyConflictHandler::EControlTypes)mEditingIndex))
|
||||
{
|
||||
mEditingColumn = pControlsTable->getColumnIndexFromOffset(x);
|
||||
|
||||
if (mEditingColumn >0)
|
||||
{
|
||||
LLSetKeyBindDialog* dialog = LLFloaterReg::showTypedInstance<LLSetKeyBindDialog>("keybind_dialog", LLSD(), TRUE);
|
||||
if (dialog)
|
||||
{
|
||||
if (mConflictHandler[mEditingMode].getLoadedMode() == LLKeyConflictHandler::MODE_GENERAL)
|
||||
{
|
||||
dialog->setParent(this, DEFAULT_KEY_FILTER);
|
||||
}
|
||||
else
|
||||
{
|
||||
dialog->setParent(this, ALLOW_KEYS | ALLOW_MASK_KEYS);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
mShowKeyDialog = false;
|
||||
}
|
||||
return LLPanelPreference::handleHover(x, y, mask);
|
||||
}
|
||||
|
||||
void LLPanelPreferenceControls::addGroupRow(const std::string &icon, S32 index)
|
||||
{
|
||||
LLScrollListItem::Params item_params;
|
||||
item_params.value = LLSD::Integer(-1);
|
||||
|
||||
LLScrollListCell::Params icon_cell_params;
|
||||
icon_cell_params.font = LLFontGL::getFontSansSerif();
|
||||
icon_cell_params.font_halign = LLFontGL::LEFT;
|
||||
icon_cell_params.type = "icontext";
|
||||
|
||||
LLScrollListCell::Params cell_params;
|
||||
// init basic cell params
|
||||
cell_params.font = LLFontGL::getFontSansSerif();
|
||||
cell_params.font_halign = LLFontGL::LEFT;
|
||||
|
||||
std::string control_name = LLKeyConflictHandler::getControlName((LLKeyConflictHandler::EControlTypes)index);
|
||||
std::string label;
|
||||
if (hasString(control_name))
|
||||
{
|
||||
label = getString(control_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
label = control_name;
|
||||
}
|
||||
icon_cell_params.column = "lst_action";
|
||||
icon_cell_params.text = label;
|
||||
icon_cell_params.value = icon;
|
||||
item_params.columns.add(icon_cell_params);
|
||||
//dummy cells
|
||||
cell_params.column = "lst_ctrl1";
|
||||
cell_params.value = "";
|
||||
item_params.columns.add(cell_params);
|
||||
cell_params.column = "lst_ctrl2";
|
||||
cell_params.value = "";
|
||||
item_params.columns.add(cell_params);
|
||||
cell_params.column = "lst_ctrl3";
|
||||
cell_params.value = "";
|
||||
item_params.columns.add(cell_params);
|
||||
pControlsTable->addRow(item_params, EAddPosition::ADD_BOTTOM);
|
||||
}
|
||||
|
||||
void LLPanelPreferenceControls::regenerateControls()
|
||||
{
|
||||
mEditingMode = pKeyModeBox->getValue().asInteger();
|
||||
mConflictHandler[mEditingMode].loadFromSettings((LLKeyConflictHandler::EModes)mEditingMode);
|
||||
populateControlTable();
|
||||
}
|
||||
|
||||
void LLPanelPreferenceControls::populateControlTable()
|
||||
{
|
||||
pControlsTable->clearRows();
|
||||
|
||||
// todo: subsections need sorting?
|
||||
std::string label;
|
||||
std::string label, control_name;
|
||||
LLScrollListCell::Params cell_params;
|
||||
// init basic cell params
|
||||
cell_params.font = LLFontGL::getFontSansSerif();
|
||||
|
|
@ -3013,81 +3010,71 @@ void LLPanelPreferenceControls::populateControlTable()
|
|||
cell_params.column = "";
|
||||
cell_params.value = label;
|
||||
|
||||
LLScrollListItem::Params item_params_blank;
|
||||
cell_params.enabled = false;
|
||||
item_params_blank.value = LLSD::Integer(-1);
|
||||
item_params_blank.columns.add(cell_params);
|
||||
cell_params.enabled = true;
|
||||
|
||||
for (U32 i = LLControlBindings::CONTROL_VIEW_ACTIONS; i < LLControlBindings::CONTROL_NUM_INDICES; i++)
|
||||
S32 start = mEditingMode == LLKeyConflictHandler::MODE_GENERAL ? LLKeyConflictHandler::CONTROL_VIEW_ACTIONS : LLKeyConflictHandler::CONTROL_MOVEMENTS;
|
||||
S32 end = mEditingMode == LLKeyConflictHandler::MODE_GENERAL ? LLKeyConflictHandler::CONTROL_NUM_INDICES : LLKeyConflictHandler::CONTROL_RESERVED;
|
||||
for (S32 i = start; i < end; i++)
|
||||
{
|
||||
switch (i)
|
||||
LLKeyConflictHandler::EControlTypes type = (LLKeyConflictHandler::EControlTypes)i;
|
||||
switch (type)
|
||||
{
|
||||
case LLControlBindings::CONTROL_VIEW_ACTIONS:
|
||||
{
|
||||
// same as below, but without separator
|
||||
LLScrollListItem::Params item_params;
|
||||
item_params.value = LLSD::Integer(i);
|
||||
|
||||
label = getString(tmp_typetostring[i]);
|
||||
cell_params.column = "lst_action";
|
||||
cell_params.value = label;
|
||||
//dummy cells
|
||||
item_params.columns.add(cell_params);
|
||||
cell_params.column = "lst_ctrl1";
|
||||
cell_params.value = "";
|
||||
item_params.columns.add(cell_params);
|
||||
cell_params.column = "lst_ctrl2";
|
||||
cell_params.value = "";
|
||||
item_params.columns.add(cell_params);
|
||||
LLUUID id;
|
||||
LLGroupControlsListItem* item = new LLGroupControlsListItem(item_params, id);
|
||||
pControlsTable->addRow(item, item_params, EAddPosition::ADD_BOTTOM);
|
||||
break;
|
||||
}
|
||||
case LLControlBindings::CONTROL_INTERACTIONS:
|
||||
case LLControlBindings::CONTROL_MOVEMENTS:
|
||||
case LLControlBindings::CONTROL_MEDIACONTENT:
|
||||
case LLControlBindings::CONTROL_RESERVED:
|
||||
{
|
||||
// insert blank
|
||||
pControlsTable->addRow(item_params_blank, EAddPosition::ADD_BOTTOM);
|
||||
// inster with icon
|
||||
LLScrollListItem::Params item_params;
|
||||
item_params.value = LLSD::Integer(i);
|
||||
|
||||
label = getString(tmp_typetostring[i]);
|
||||
cell_params.column = "lst_action";
|
||||
cell_params.value = label;
|
||||
//dummy cells
|
||||
item_params.columns.add(cell_params);
|
||||
cell_params.column = "lst_ctrl1";
|
||||
cell_params.value = "";
|
||||
item_params.columns.add(cell_params);
|
||||
cell_params.column = "lst_ctrl2";
|
||||
cell_params.value = "";
|
||||
item_params.columns.add(cell_params);
|
||||
LLUUID id;
|
||||
LLGroupControlsListItem* item = new LLGroupControlsListItem(item_params, id);
|
||||
pControlsTable->addRow(item, item_params, EAddPosition::ADD_BOTTOM);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
case LLKeyConflictHandler::CONTROL_VIEW_ACTIONS:
|
||||
addSeparator();
|
||||
addGroupRow("Search_Icon", i);
|
||||
break;
|
||||
case LLKeyConflictHandler::CONTROL_INTERACTIONS:
|
||||
addSeparator();
|
||||
addGroupRow("Command_Gestures_Icon", i);
|
||||
break;
|
||||
case LLKeyConflictHandler::CONTROL_MOVEMENTS:
|
||||
addSeparator();
|
||||
addGroupRow("Move_Walk_Off", i);
|
||||
break;
|
||||
case LLKeyConflictHandler::CONTROL_MEDIACONTENT:
|
||||
addSeparator();
|
||||
addGroupRow("Audio_Press", i);
|
||||
break;
|
||||
case LLKeyConflictHandler::CONTROL_CAMERA:
|
||||
addSeparator();
|
||||
addGroupRow("Cam_FreeCam_Off", i);
|
||||
break;
|
||||
case LLKeyConflictHandler::CONTROL_EDIT_TITLE:
|
||||
addSeparator();
|
||||
addGroupRow("Tool_Dozer", i);
|
||||
break;
|
||||
case LLKeyConflictHandler::CONTROL_RESERVED:
|
||||
addSeparator();
|
||||
addGroupRow("Info_Small", i);
|
||||
break;
|
||||
default:
|
||||
{
|
||||
//default insert
|
||||
LLScrollListItem::Params item_params;
|
||||
item_params.value = LLSD::Integer(i);
|
||||
|
||||
// todo oddset
|
||||
cell_params.column = "lst_action";
|
||||
label = getString(tmp_typetostring[i]);
|
||||
bool enabled = mConflictHandler[mEditingMode].canAssignControl(type);
|
||||
control_name = LLKeyConflictHandler::getControlName(type);
|
||||
if (hasString(control_name))
|
||||
{
|
||||
label = getString(control_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
label = control_name;
|
||||
}
|
||||
cell_params.value = label;
|
||||
item_params.columns.add(cell_params);
|
||||
cell_params.column = "lst_ctrl1";
|
||||
cell_params.value = gControlBindings.getPrimaryControl((LLControlBindings::EControlTypes)i).asString();
|
||||
cell_params.value = mConflictHandler[mEditingMode].getControlString(type, 0);
|
||||
cell_params.enabled = enabled;
|
||||
item_params.columns.add(cell_params);
|
||||
cell_params.column = "lst_ctrl2";
|
||||
cell_params.value = gControlBindings.getSecondaryControl((LLControlBindings::EControlTypes)i).asString();
|
||||
cell_params.value = mConflictHandler[mEditingMode].getControlString(type, 1);
|
||||
cell_params.enabled = enabled;
|
||||
item_params.columns.add(cell_params);
|
||||
cell_params.column = "lst_ctrl3";
|
||||
cell_params.value = mConflictHandler[mEditingMode].getControlString(type, 2);
|
||||
cell_params.enabled = enabled;
|
||||
item_params.columns.add(cell_params);
|
||||
|
||||
pControlsTable->addRow(item_params, EAddPosition::ADD_BOTTOM);
|
||||
|
|
@ -3095,23 +3082,64 @@ void LLPanelPreferenceControls::populateControlTable()
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
//temp
|
||||
if (mEditingMode == LLKeyConflictHandler::MODE_GENERAL)
|
||||
pControlsTable->setEnabled(false);
|
||||
}
|
||||
|
||||
// Just a workaround to not care about first separator before headers (we can start from random header)
|
||||
void LLPanelPreferenceControls::addSeparator()
|
||||
{
|
||||
if (pControlsTable->getItemCount() > 0)
|
||||
{
|
||||
pControlsTable->addSeparator(EAddPosition::ADD_BOTTOM);
|
||||
}
|
||||
}
|
||||
|
||||
void LLPanelPreferenceControls::apply()
|
||||
{
|
||||
for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT; ++i)
|
||||
{
|
||||
if (mConflictHandler[i].hasUnsavedChanges())
|
||||
{
|
||||
mConflictHandler[i].saveToSettings();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLPanelPreferenceControls::cancel()
|
||||
{
|
||||
for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT; ++i)
|
||||
{
|
||||
if (mConflictHandler[i].hasUnsavedChanges())
|
||||
{
|
||||
mConflictHandler[i].clear();
|
||||
}
|
||||
}
|
||||
pControlsTable->clear();
|
||||
}
|
||||
|
||||
void LLPanelPreferenceControls::saveSettings()
|
||||
{
|
||||
for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT; ++i)
|
||||
{
|
||||
if (mConflictHandler[i].hasUnsavedChanges())
|
||||
{
|
||||
mConflictHandler[i].saveToSettings();
|
||||
}
|
||||
}
|
||||
|
||||
S32 mode = pKeyModeBox->getValue().asInteger();
|
||||
if (mConflictHandler[mode].empty())
|
||||
{
|
||||
regenerateControls();
|
||||
}
|
||||
}
|
||||
|
||||
void LLPanelPreferenceControls::resetDirtyChilds()
|
||||
{
|
||||
}
|
||||
|
||||
bool LLPanelPreferenceControls::hasDirtyChilds()
|
||||
{
|
||||
return false;
|
||||
regenerateControls();
|
||||
}
|
||||
|
||||
void LLPanelPreferenceControls::onListCommit()
|
||||
|
|
@ -3124,63 +3152,87 @@ void LLPanelPreferenceControls::onListCommit()
|
|||
|
||||
S32 control = item->getValue().asInteger();
|
||||
|
||||
if (!gControlBindings.canAssignControl((LLControlBindings::EControlTypes)control))
|
||||
if (control <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// todo: add code to determine what cell was clicked, probably cells themself should be clickable
|
||||
|
||||
LLVoiceSetKeyDialog* dialog = LLFloaterReg::showTypedInstance<LLVoiceSetKeyDialog>("voice_set_key", LLSD(), TRUE);
|
||||
if (dialog)
|
||||
if (!mConflictHandler[mEditingMode].canAssignControl((LLKeyConflictHandler::EControlTypes)control))
|
||||
{
|
||||
dialog->setTmpParent(this); // will be remade from being voice later
|
||||
return;
|
||||
}
|
||||
|
||||
// List does not tell us what cell was clicked, so we have to figure it out manually, but
|
||||
// fresh mouse coordinates are not yet accessible during onCommit() and there are other issues,
|
||||
// so we cheat: remember item user clicked at, trigger 'key dialog' on hover that comes next,
|
||||
// use coordinates from hover to calculate cell
|
||||
mEditingIndex = control;
|
||||
mShowKeyDialog = true;
|
||||
}
|
||||
|
||||
void LLPanelPreferenceControls::onSetKey(KEY key, MASK mask)
|
||||
void LLPanelPreferenceControls::onModeCommit()
|
||||
{
|
||||
LLScrollListItem* item = pControlsTable->getFirstSelected();
|
||||
if (item == NULL)
|
||||
regenerateControls();
|
||||
}
|
||||
|
||||
void LLPanelPreferenceControls::onSetKeyBind(EMouseClickType click, KEY key, MASK mask)
|
||||
{
|
||||
LLKeyConflictHandler::EControlTypes control = (LLKeyConflictHandler::EControlTypes)mEditingIndex;
|
||||
|
||||
if (!mConflictHandler[mEditingMode].canAssignControl(control))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
LLControlBindings::EControlTypes control = (LLControlBindings::EControlTypes)item->getValue().asInteger();
|
||||
|
||||
if (!gControlBindings.canAssignControl(control))
|
||||
pControlsTable->deselectAllItems();
|
||||
pControlsTable->selectByValue(mEditingIndex);
|
||||
LLScrollListItem *item = pControlsTable->getFirstSelected();
|
||||
if (item && mEditingColumn > 0)
|
||||
{
|
||||
return;
|
||||
|
||||
mConflictHandler[mEditingMode].registerControl(control, mEditingColumn - 1, click, key, mask);
|
||||
|
||||
LLScrollListCell *cell = item->getColumn(1);
|
||||
cell->setValue(mConflictHandler[mEditingMode].getControlString(control, 0));
|
||||
cell = item->getColumn(2);
|
||||
cell->setValue(mConflictHandler[mEditingMode].getControlString(control, 1));
|
||||
cell = item->getColumn(3);
|
||||
cell->setValue(mConflictHandler[mEditingMode].getControlString(control, 2));
|
||||
}
|
||||
|
||||
gControlBindings.registerPrimaryControl(control, LLMouseHandler::CLICK_NONE, key, mask);
|
||||
|
||||
// instead of populating, update single element
|
||||
populateControlTable();
|
||||
}
|
||||
|
||||
void LLPanelPreferenceControls::onSetMouse(LLMouseHandler::EClickType click, MASK mask)
|
||||
void LLPanelPreferenceControls::onRestoreDefaults()
|
||||
{
|
||||
|
||||
LLScrollListItem* item = pControlsTable->getFirstSelected();
|
||||
if (item == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
LLControlBindings::EControlTypes control = (LLControlBindings::EControlTypes)item->getValue().asInteger();
|
||||
|
||||
if (!gControlBindings.canAssignControl(control))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
gControlBindings.registerPrimaryControl(control, click, KEY_NONE, mask);
|
||||
|
||||
// instead of populating, update single element
|
||||
mConflictHandler[mEditingMode].resetToDefaults();
|
||||
populateControlTable();
|
||||
}
|
||||
|
||||
void LLPanelPreferenceControls::onDefaultKeyBind()
|
||||
{
|
||||
LLKeyConflictHandler::EControlTypes control = (LLKeyConflictHandler::EControlTypes)mEditingIndex;
|
||||
|
||||
if (!mConflictHandler[mEditingMode].canAssignControl(control))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
pControlsTable->deselectAllItems();
|
||||
pControlsTable->selectByValue(mEditingIndex);
|
||||
LLScrollListItem *item = pControlsTable->getFirstSelected();
|
||||
if (item)
|
||||
{
|
||||
LLScrollListCell *cell = item->getColumn(mEditingColumn);
|
||||
|
||||
if (mEditingColumn > 0)
|
||||
{
|
||||
mConflictHandler[mEditingMode].resetToDefault(control, mEditingColumn - 1);
|
||||
cell->setValue(mConflictHandler[mEditingMode].getControlString(control, mEditingColumn - 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LLFloaterPreferenceGraphicsAdvanced::LLFloaterPreferenceGraphicsAdvanced(const LLSD& key)
|
||||
: LLFloater(key)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -37,12 +37,14 @@
|
|||
#include "llavatarpropertiesprocessor.h"
|
||||
#include "llconversationlog.h"
|
||||
#include "llsearcheditor.h"
|
||||
#include "llkeyconflict.h"
|
||||
|
||||
class LLConversationLogObserver;
|
||||
class LLPanelPreference;
|
||||
class LLPanelLCD;
|
||||
class LLPanelDebug;
|
||||
class LLMessageSystem;
|
||||
class LLComboBox;
|
||||
class LLScrollListCtrl;
|
||||
class LLSliderCtrl;
|
||||
class LLSD;
|
||||
|
|
@ -147,8 +149,6 @@ public:
|
|||
void onClickSkin(LLUICtrl* ctrl,const LLSD& userdata);
|
||||
void onSelectSkin();
|
||||
void onClickSetKey();
|
||||
void setKey(KEY key);
|
||||
void setMouse(EMouseClickType click);
|
||||
void onClickSetMiddleMouse();
|
||||
void onClickSetSounds();
|
||||
void onClickEnablePopup();
|
||||
|
|
@ -298,21 +298,36 @@ class LLPanelPreferenceControls : public LLPanelPreference
|
|||
{
|
||||
LOG_CLASS(LLPanelPreferenceControls);
|
||||
public:
|
||||
LLPanelPreferenceControls();
|
||||
~LLPanelPreferenceControls();
|
||||
|
||||
BOOL postBuild();
|
||||
void populateControlTable();
|
||||
BOOL handleHover(S32 x, S32 y, MASK mask);
|
||||
|
||||
void apply();
|
||||
void cancel();
|
||||
void saveSettings();
|
||||
void resetDirtyChilds();
|
||||
|
||||
void onListCommit();
|
||||
void onSetKey(KEY key, MASK mask);
|
||||
void onSetMouse(LLMouseHandler::EClickType click, MASK mask);
|
||||
|
||||
protected:
|
||||
bool hasDirtyChilds();
|
||||
void onModeCommit();
|
||||
void onSetKeyBind(EMouseClickType click, KEY key, MASK mask);
|
||||
void onRestoreDefaults();
|
||||
void onDefaultKeyBind();
|
||||
|
||||
private:
|
||||
void addGroupRow(const std::string &icon, S32 index);
|
||||
void regenerateControls();
|
||||
void populateControlTable();
|
||||
void addSeparator();
|
||||
|
||||
LLScrollListCtrl* pControlsTable;
|
||||
LLComboBox *pKeyModeBox;
|
||||
LLKeyConflictHandler mConflictHandler[LLKeyConflictHandler::MODE_COUNT];
|
||||
S32 mEditingIndex;
|
||||
S32 mEditingColumn;
|
||||
S32 mEditingMode;
|
||||
bool mShowKeyDialog;
|
||||
};
|
||||
|
||||
class LLFloaterPreferenceGraphicsAdvanced : public LLFloater
|
||||
|
|
|
|||
|
|
@ -0,0 +1,789 @@
|
|||
/**
|
||||
* @file llkeyconflict.cpp
|
||||
* @brief
|
||||
*
|
||||
* $LicenseInfo:firstyear=2019&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2019, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
/*
|
||||
* App-wide preferences. Note that these are not per-user,
|
||||
* because we need to load many preferences before we have
|
||||
* a login name.
|
||||
*/
|
||||
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
|
||||
#include "llkeyconflict.h"
|
||||
|
||||
#include "llinitparam.h"
|
||||
#include "llkeyboard.h"
|
||||
#include "llviewercontrol.h"
|
||||
#include "llviewerkeyboard.h"
|
||||
#include "llxuiparser.h"
|
||||
//#include "llstring.h"
|
||||
|
||||
static const std::string typetostring[LLKeyConflictHandler::CONTROL_NUM_INDICES] = {
|
||||
"control_view_actions",
|
||||
"control_about",
|
||||
"control_orbit",
|
||||
"control_pan",
|
||||
"control_world_map",
|
||||
"control_zoom",
|
||||
"control_interactions",
|
||||
"control_build",
|
||||
//"control_drag",
|
||||
"control_edit",
|
||||
//"control_menu",
|
||||
"control_open",
|
||||
"control_touch",
|
||||
"control_wear",
|
||||
"control_movements",
|
||||
"control_moveto",
|
||||
"control_sit",
|
||||
"control_teleportto",
|
||||
"push_forward",
|
||||
"push_backward",
|
||||
"turn_left",
|
||||
"turn_right",
|
||||
"slide_left",
|
||||
"slide_right",
|
||||
"jump",
|
||||
"push_down",
|
||||
//"control_run",
|
||||
"control_toggle_run",
|
||||
"toggle_fly",
|
||||
"stop_moving",
|
||||
"control_camera",
|
||||
"look_up",
|
||||
"look_down",
|
||||
"move_forward",
|
||||
"move_backward",
|
||||
"move_forward_fast",
|
||||
"move_backward_fast",
|
||||
"move_forward_sitting",
|
||||
"move_backward_sitting",
|
||||
"spin_over",
|
||||
"spin_under",
|
||||
"spin_over_sitting",
|
||||
"spin_under_sitting",
|
||||
"pan_up",
|
||||
"pan_down",
|
||||
"pan_left",
|
||||
"pan_right",
|
||||
"pan_in",
|
||||
"pan_out",
|
||||
"spin_around_ccw",
|
||||
"spin_around_cw",
|
||||
"spin_around_ccw_sitting",
|
||||
"spin_around_cw_sitting",
|
||||
"control_edit_title",
|
||||
"edit_avatar_spin_ccw",
|
||||
"edit_avatar_spin_cw",
|
||||
"edit_avatar_spin_over",
|
||||
"edit_avatar_spin_under",
|
||||
"edit_avatar_move_forward",
|
||||
"edit_avatar_move_backward",
|
||||
"control_mediacontent",
|
||||
"control_parcel",
|
||||
"control_media",
|
||||
"control_voice",
|
||||
"control_toggle_voice",
|
||||
"start_chat",
|
||||
"start_gesture",
|
||||
"control_reserved",
|
||||
"control_delete",
|
||||
"control_menu",
|
||||
"control_reserved_select",
|
||||
"control_shift_select",
|
||||
"control_cntrl_select"
|
||||
};
|
||||
|
||||
// note, a solution is needed that will keep this up to date with llviewerkeyboard
|
||||
typedef std::map<std::string, LLKeyConflictHandler::EControlTypes> control_enum_t;
|
||||
static const control_enum_t command_to_key =
|
||||
{
|
||||
{ "jump", LLKeyConflictHandler::CONTROL_JUMP },
|
||||
{ "push_down", LLKeyConflictHandler::CONTROL_DOWN },
|
||||
{ "push_forward", LLKeyConflictHandler::CONTROL_FORWARD },
|
||||
{ "push_backward", LLKeyConflictHandler::CONTROL_BACKWARD },
|
||||
{ "look_up", LLKeyConflictHandler::CONTROL_LOOK_UP },
|
||||
{ "look_down", LLKeyConflictHandler::CONTROL_LOOK_DOWN },
|
||||
{ "toggle_fly", LLKeyConflictHandler::CONTROL_TOGGLE_FLY },
|
||||
{ "turn_left", LLKeyConflictHandler::CONTROL_LEFT },
|
||||
{ "turn_right", LLKeyConflictHandler::CONTROL_RIGHT },
|
||||
{ "slide_left", LLKeyConflictHandler::CONTROL_LSTRAFE },
|
||||
{ "slide_right", LLKeyConflictHandler::CONTROL_RSTRAFE },
|
||||
{ "spin_around_ccw", LLKeyConflictHandler::CONTROL_CAMERA_SPIN_CCW }, // todo, no idea what these spins are
|
||||
{ "spin_around_cw", LLKeyConflictHandler::CONTROL_CAMERA_SPIN_CW },
|
||||
{ "spin_around_ccw_sitting", LLKeyConflictHandler::CONTROL_CAMERA_SPIN_CCW_SITTING },
|
||||
{ "spin_around_cw_sitting", LLKeyConflictHandler::CONTROL_CAMERA_SPIN_CCW_SITTING },
|
||||
{ "spin_over", LLKeyConflictHandler::CONTROL_CAMERA_SOVER },
|
||||
{ "spin_under", LLKeyConflictHandler::CONTROL_CAMERA_SUNDER },
|
||||
{ "spin_over_sitting", LLKeyConflictHandler::CONTROL_CAMERA_SOVER_SITTING },
|
||||
{ "spin_under_sitting", LLKeyConflictHandler::CONTROL_CAMERA_SUNDER_SITTING },
|
||||
{ "move_forward", LLKeyConflictHandler::CONTROL_CAMERA_FORWARD },
|
||||
{ "move_backward", LLKeyConflictHandler::CONTROL_CAMERA_BACKWARD },
|
||||
{ "move_forward_sitting", LLKeyConflictHandler::CONTROL_CAMERA_FSITTING },
|
||||
{ "move_backward_sitting", LLKeyConflictHandler::CONTROL_CAMERA_BSITTING },
|
||||
{ "pan_up", LLKeyConflictHandler::CONTROL_CAMERA_PANUP },
|
||||
{ "pan_down", LLKeyConflictHandler::CONTROL_CAMERA_PANDOWN },
|
||||
{ "pan_left", LLKeyConflictHandler::CONTROL_CAMERA_PANLEFT },
|
||||
{ "pan_right", LLKeyConflictHandler::CONTROL_CAMERA_PANRIGHT },
|
||||
{ "pan_in", LLKeyConflictHandler::CONTROL_CAMERA_PANIN },
|
||||
{ "pan_out", LLKeyConflictHandler::CONTROL_CAMERA_PANOUT },
|
||||
{ "move_forward_fast", LLKeyConflictHandler::CONTROL_CAMERA_FFORWARD },
|
||||
{ "move_backward_fast", LLKeyConflictHandler::CONTROL_CAMERA_FBACKWARD },
|
||||
{ "edit_avatar_spin_ccw", LLKeyConflictHandler::CONTROL_EDIT_AV_SPIN_CCW },
|
||||
{ "edit_avatar_spin_cw", LLKeyConflictHandler::CONTROL_EDIT_AV_SPIN_CW },
|
||||
{ "edit_avatar_spin_over", LLKeyConflictHandler::CONTROL_EDIT_AV_SPIN_OVER },
|
||||
{ "edit_avatar_spin_under", LLKeyConflictHandler::CONTROL_EDIT_AV_SPIN_UNDER },
|
||||
{ "edit_avatar_move_forward", LLKeyConflictHandler::CONTROL_EDIT_AV_MV_FORWARD },
|
||||
{ "edit_avatar_move_backward", LLKeyConflictHandler::CONTROL_EDIT_AV_MV_BACKWARD },
|
||||
{ "stop_moving", LLKeyConflictHandler::CONTROL_STOP },
|
||||
{ "start_chat", LLKeyConflictHandler::CONTROL_START_CHAT },
|
||||
{ "start_gesture", LLKeyConflictHandler::CONTROL_START_GESTURE },
|
||||
};
|
||||
|
||||
|
||||
// LLKeyboard::stringFromMask is meant for UI and is OS dependent,
|
||||
// so this class uses it's own version
|
||||
std::string string_from_mask(MASK mask)
|
||||
{
|
||||
std::string res;
|
||||
if ((mask & MASK_CONTROL) != 0)
|
||||
{
|
||||
res = "CTL";
|
||||
}
|
||||
if ((mask & MASK_ALT) != 0)
|
||||
{
|
||||
if (!res.empty()) res += "_";
|
||||
res += "ALT";
|
||||
}
|
||||
if ((mask & MASK_SHIFT) != 0)
|
||||
{
|
||||
if (!res.empty()) res += "_";
|
||||
res += "SHIFT";
|
||||
}
|
||||
|
||||
if (mask == MASK_NONE)
|
||||
{
|
||||
res = "NONE";
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// LLKeyConflictHandler
|
||||
|
||||
LLKeyConflictHandler::LLKeyConflictHandler()
|
||||
: mHasUnsavedChanges(false)
|
||||
{
|
||||
// todo: assign conflic priorities
|
||||
// todo: load from keys.xml?
|
||||
|
||||
// Thise controls are meant to cause conflicts when user tries to assign same control somewhere else
|
||||
/*registerTemporaryControl(CONTROL_RESERVED_MENU, CLICK_RIGHT, KEY_NONE, MASK_NONE, 0);
|
||||
registerTemporaryControl(CONTROL_SHIFT_SELECT, CLICK_LEFT, KEY_NONE, MASK_SHIFT, 0);
|
||||
registerTemporaryControl(CONTROL_CNTRL_SELECT, CLICK_LEFT, KEY_NONE, MASK_CONTROL, 0);
|
||||
registerTemporaryControl(CONTROL_DELETE, CLICK_NONE, KEY_DELETE, MASK_NONE, 0);
|
||||
|
||||
loadFromSettings();*/
|
||||
}
|
||||
|
||||
LLKeyConflictHandler::LLKeyConflictHandler(EModes mode)
|
||||
: mHasUnsavedChanges(false),
|
||||
mLoadedMode(mode)
|
||||
{
|
||||
loadFromSettings(mode);
|
||||
}
|
||||
|
||||
bool LLKeyConflictHandler::canHandleControl(LLKeyConflictHandler::EControlTypes control_type, EMouseClickType mouse_ind, KEY key, MASK mask)
|
||||
{
|
||||
return mControlsMap[control_type].canHandle(mouse_ind, key, mask);
|
||||
}
|
||||
|
||||
bool LLKeyConflictHandler::canHandleKey(EControlTypes control_type, KEY key, MASK mask)
|
||||
{
|
||||
return canHandleControl(control_type, CLICK_NONE, key, mask);
|
||||
}
|
||||
|
||||
bool LLKeyConflictHandler::canHandleMouse(LLKeyConflictHandler::EControlTypes control_type, EMouseClickType mouse_ind, MASK mask)
|
||||
{
|
||||
return canHandleControl(control_type, mouse_ind, KEY_NONE, mask);
|
||||
}
|
||||
|
||||
bool LLKeyConflictHandler::canHandleMouse(EControlTypes control_type, S32 mouse_ind, MASK mask)
|
||||
{
|
||||
return canHandleControl(control_type, (EMouseClickType)mouse_ind, KEY_NONE, mask);
|
||||
}
|
||||
|
||||
bool LLKeyConflictHandler::canAssignControl(EControlTypes control_type)
|
||||
{
|
||||
std::map<EControlTypes, LLKeyConflict>::iterator iter = mControlsMap.find(control_type);
|
||||
if (iter != mControlsMap.end())
|
||||
{
|
||||
return iter->second.mAssignable;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void LLKeyConflictHandler::registerControl(EControlTypes control_type, U32 index, EMouseClickType mouse, KEY key, MASK mask)
|
||||
{
|
||||
LLKeyConflict &type_data = mControlsMap[control_type];
|
||||
if (!type_data.mAssignable)
|
||||
{
|
||||
LL_ERRS() << "Error in code, user or system should not be able to change certain controls" << LL_ENDL;
|
||||
}
|
||||
type_data.mKeyBind.replaceKeyData(mouse, key, mask, index);
|
||||
|
||||
mHasUnsavedChanges = true;
|
||||
}
|
||||
|
||||
LLKeyData LLKeyConflictHandler::getControl(EControlTypes control_type, U32 index)
|
||||
{
|
||||
return mControlsMap[control_type].getKeyData(index);
|
||||
}
|
||||
|
||||
// static
|
||||
std::string LLKeyConflictHandler::getStringFromKeyData(const LLKeyData& keydata)
|
||||
{
|
||||
std::string result;
|
||||
|
||||
if (keydata.mMask != MASK_NONE && keydata.mKey != KEY_NONE)
|
||||
{
|
||||
result = LLKeyboard::stringFromAccelerator(keydata.mMask, keydata.mKey);
|
||||
}
|
||||
else if (keydata.mKey != KEY_NONE)
|
||||
{
|
||||
result = LLKeyboard::stringFromKey(keydata.mKey);
|
||||
}
|
||||
else if (keydata.mMask != MASK_NONE)
|
||||
{
|
||||
LL_ERRS() << "Masks binding without keys is not supported yet" << LL_ENDL;
|
||||
}
|
||||
|
||||
#ifdef LL_DARWIN
|
||||
// darwin uses special symbols and doesn't need '+' for masks
|
||||
if (mMouse != CLICK_NONE && mKey != KEY_NONE)
|
||||
{
|
||||
result += " + ";
|
||||
}
|
||||
#else
|
||||
if (keydata.mMouse != CLICK_NONE && !result.empty())
|
||||
{
|
||||
result += " + ";
|
||||
}
|
||||
#endif
|
||||
|
||||
switch (keydata.mMouse)
|
||||
{
|
||||
case CLICK_LEFT:
|
||||
result += "LMB";
|
||||
break;
|
||||
case CLICK_MIDDLE:
|
||||
result += "MMB";
|
||||
break;
|
||||
case CLICK_RIGHT:
|
||||
result += "RMB";
|
||||
break;
|
||||
case CLICK_BUTTON4:
|
||||
result += "MB4";
|
||||
break;
|
||||
case CLICK_BUTTON5:
|
||||
result += "MB5";
|
||||
break;
|
||||
case CLICK_DOUBLELEFT:
|
||||
result += "Double LMB";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// static
|
||||
std::string LLKeyConflictHandler::getControlName(EControlTypes control_type)
|
||||
{
|
||||
return typetostring[control_type];
|
||||
}
|
||||
|
||||
std::string LLKeyConflictHandler::getControlString(EControlTypes control_type, U32 index)
|
||||
{
|
||||
return getStringFromKeyData(mControlsMap[control_type].getKeyData(index));
|
||||
}
|
||||
|
||||
void LLKeyConflictHandler::loadFromSettings(const LLViewerKeyboard::KeyMode& keymode, control_map_t *destination)
|
||||
{
|
||||
for (LLInitParam::ParamIterator<LLViewerKeyboard::KeyBinding>::const_iterator it = keymode.bindings.begin(),
|
||||
end_it = keymode.bindings.end();
|
||||
it != end_it;
|
||||
++it)
|
||||
{
|
||||
KEY key;
|
||||
MASK mask;
|
||||
if (it->key.getValue().empty())
|
||||
{
|
||||
key = KEY_NONE;
|
||||
}
|
||||
else
|
||||
{
|
||||
LLKeyboard::keyFromString(it->key, &key);
|
||||
}
|
||||
LLKeyboard::maskFromString(it->mask, &mask);
|
||||
std::string command_name = it->command;
|
||||
// it->command
|
||||
// It might be better to have <string,bind> map, but at the moment enum is easier to iterate through.
|
||||
// Besides keys.xml might not contain all commands
|
||||
control_enum_t::const_iterator iter = command_to_key.find(command_name);
|
||||
if (iter != command_to_key.end())
|
||||
{
|
||||
LLKeyConflict &type_data = (*destination)[iter->second];
|
||||
type_data.mAssignable = true;
|
||||
// Don't care about conflict level, all movement and view commands already account for it
|
||||
type_data.mKeyBind.addKeyData(CLICK_NONE, key, mask);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLKeyConflictHandler::loadFromSettings(const EModes &load_mode, const std::string &filename, control_map_t *destination)
|
||||
{
|
||||
if (filename.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
LLViewerKeyboard::Keys keys;
|
||||
LLSimpleXUIParser parser;
|
||||
|
||||
if (parser.readXUI(filename, keys)
|
||||
&& keys.validateBlock())
|
||||
{
|
||||
switch (load_mode)
|
||||
{
|
||||
case MODE_FIRST_PERSON:
|
||||
if (keys.first_person.isProvided())
|
||||
{
|
||||
loadFromSettings(keys.first_person, destination);
|
||||
}
|
||||
break;
|
||||
case MODE_THIRD_PERSON:
|
||||
if (keys.third_person.isProvided())
|
||||
{
|
||||
loadFromSettings(keys.third_person, destination);
|
||||
}
|
||||
break;
|
||||
case MODE_EDIT:
|
||||
if (keys.edit.isProvided())
|
||||
{
|
||||
loadFromSettings(keys.edit, destination);
|
||||
}
|
||||
break;
|
||||
case MODE_EDIT_AVATAR:
|
||||
if (keys.edit_avatar.isProvided())
|
||||
{
|
||||
loadFromSettings(keys.edit_avatar, destination);
|
||||
}
|
||||
break;
|
||||
case MODE_SITTING:
|
||||
if (keys.sitting.isProvided())
|
||||
{
|
||||
loadFromSettings(keys.sitting, destination);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLKeyConflictHandler::loadFromSettings(EModes load_mode)
|
||||
{
|
||||
mControlsMap.clear();
|
||||
mDefaultsMap.clear();
|
||||
if (load_mode == MODE_GENERAL)
|
||||
{
|
||||
for (U32 i = 0; i < CONTROL_NUM_INDICES; i++)
|
||||
{
|
||||
EControlTypes type = (EControlTypes)i;
|
||||
switch (type)
|
||||
{
|
||||
case LLKeyConflictHandler::CONTROL_VIEW_ACTIONS:
|
||||
case LLKeyConflictHandler::CONTROL_INTERACTIONS:
|
||||
case LLKeyConflictHandler::CONTROL_MOVEMENTS:
|
||||
case LLKeyConflictHandler::CONTROL_MEDIACONTENT:
|
||||
case LLKeyConflictHandler::CONTROL_CAMERA:
|
||||
case LLKeyConflictHandler::CONTROL_EDIT_TITLE:
|
||||
case LLKeyConflictHandler::CONTROL_RESERVED:
|
||||
// ignore 'headers', they are for representation and organization purposes
|
||||
break;
|
||||
default:
|
||||
{
|
||||
std::string name = getControlName(type);
|
||||
LLControlVariablePtr var = gSavedSettings.getControl(name);
|
||||
if (var)
|
||||
{
|
||||
LLKeyBind bind(var->getValue());
|
||||
LLKeyConflict key(bind, true, 0);
|
||||
mControlsMap[type] = key;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// load defaults
|
||||
std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "keys.xml");
|
||||
loadFromSettings(load_mode, filename, &mDefaultsMap);
|
||||
|
||||
// load user's
|
||||
filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "keys.xml");
|
||||
if (gDirUtilp->fileExists(filename))
|
||||
{
|
||||
loadFromSettings(load_mode, filename, &mControlsMap);
|
||||
}
|
||||
else
|
||||
{
|
||||
mControlsMap = mDefaultsMap;
|
||||
}
|
||||
}
|
||||
mLoadedMode = load_mode;
|
||||
|
||||
generatePlaceholders();
|
||||
}
|
||||
|
||||
void LLKeyConflictHandler::saveToSettings()
|
||||
{
|
||||
if (mControlsMap.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (mLoadedMode == MODE_GENERAL)
|
||||
{
|
||||
for (U32 i = 0; i < CONTROL_NUM_INDICES; i++)
|
||||
{
|
||||
EControlTypes type = (EControlTypes)i;
|
||||
switch (type)
|
||||
{
|
||||
case LLKeyConflictHandler::CONTROL_VIEW_ACTIONS:
|
||||
case LLKeyConflictHandler::CONTROL_INTERACTIONS:
|
||||
case LLKeyConflictHandler::CONTROL_MOVEMENTS:
|
||||
case LLKeyConflictHandler::CONTROL_MEDIACONTENT:
|
||||
case LLKeyConflictHandler::CONTROL_CAMERA:
|
||||
case LLKeyConflictHandler::CONTROL_EDIT_TITLE:
|
||||
case LLKeyConflictHandler::CONTROL_RESERVED:
|
||||
// ignore 'headers', they are for representation and organization purposes
|
||||
break;
|
||||
default:
|
||||
{
|
||||
if (mControlsMap[type].mAssignable)
|
||||
{
|
||||
std::string name = getControlName(type);
|
||||
if (gSavedSettings.controlExists(name))
|
||||
{
|
||||
gSavedSettings.setLLSD(name, mControlsMap[type].mKeyBind.asLLSD());
|
||||
}
|
||||
else if (!mControlsMap[type].mKeyBind.empty())
|
||||
{
|
||||
// shouldn't happen user side since all settings are supposed to be declared already, but handy when creating new ones
|
||||
// (just don't forget to change comment and to copy them from user's folder)
|
||||
LL_INFOS() << "Creating new keybinding " << name << LL_ENDL;
|
||||
gSavedSettings.declareLLSD(name, mControlsMap[type].mKeyBind.asLLSD(), "comment", LLControlVariable::PERSIST_ALWAYS);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// loaded full copy of original file
|
||||
std::string filename = gDirUtilp->findFile("keys.xml",
|
||||
gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, ""),
|
||||
gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, ""));
|
||||
|
||||
LLViewerKeyboard::Keys keys;
|
||||
LLSimpleXUIParser parser;
|
||||
|
||||
if (parser.readXUI(filename, keys)
|
||||
&& keys.validateBlock())
|
||||
{
|
||||
// replace category we edited
|
||||
|
||||
// todo: fix this
|
||||
// workaround to avoid doing own param container
|
||||
LLViewerKeyboard::KeyMode mode;
|
||||
LLViewerKeyboard::KeyBinding binding;
|
||||
|
||||
control_map_t::iterator iter = mControlsMap.begin();
|
||||
control_map_t::iterator end = mControlsMap.end();
|
||||
for (; iter != end; ++iter)
|
||||
{
|
||||
U32 size = iter->second.mKeyBind.getDataCount();
|
||||
for (U32 i = 0; i < size; ++i)
|
||||
{
|
||||
// Still write empty keys to make sure we will maintain UI position
|
||||
LLKeyData data = iter->second.mKeyBind.getKeyData(i);
|
||||
if (data.mKey == KEY_NONE)
|
||||
{
|
||||
binding.key = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
// Note: this is UI string, we might want to hardcode our own for 'fixed' use in keys.xml
|
||||
binding.key = LLKeyboard::stringFromKey(data.mKey);
|
||||
}
|
||||
binding.mask = string_from_mask(data.mMask);
|
||||
binding.command = getControlName(iter->first);
|
||||
mode.bindings.add(binding);
|
||||
}
|
||||
}
|
||||
|
||||
switch (mLoadedMode)
|
||||
{
|
||||
case MODE_FIRST_PERSON:
|
||||
if (keys.first_person.isProvided())
|
||||
{
|
||||
keys.first_person.bindings.set(mode.bindings, true);
|
||||
}
|
||||
break;
|
||||
case MODE_THIRD_PERSON:
|
||||
if (keys.third_person.isProvided())
|
||||
{
|
||||
keys.third_person.bindings.set(mode.bindings, true);
|
||||
}
|
||||
break;
|
||||
case MODE_EDIT:
|
||||
if (keys.edit.isProvided())
|
||||
{
|
||||
keys.edit.bindings.set(mode.bindings, true);
|
||||
}
|
||||
break;
|
||||
case MODE_EDIT_AVATAR:
|
||||
if (keys.edit_avatar.isProvided())
|
||||
{
|
||||
keys.edit_avatar.bindings.set(mode.bindings, true);
|
||||
}
|
||||
break;
|
||||
case MODE_SITTING:
|
||||
if (keys.sitting.isProvided())
|
||||
{
|
||||
keys.sitting.bindings.set(mode.bindings, true);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// write back to user's xml;
|
||||
std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "keys.xml");
|
||||
|
||||
LLXMLNodePtr output_node = new LLXMLNode("keys", false);
|
||||
LLXUIParser parser;
|
||||
parser.writeXUI(output_node, keys);
|
||||
|
||||
// Write the resulting XML to file
|
||||
if (!output_node->isNull())
|
||||
{
|
||||
LLFILE *fp = LLFile::fopen(filename, "w");
|
||||
if (fp != NULL)
|
||||
{
|
||||
LLXMLNode::writeHeaderToFile(fp);
|
||||
output_node->writeToFile(fp);
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
// Now force a rebind for keyboard
|
||||
if (gDirUtilp->fileExists(filename))
|
||||
{
|
||||
gViewerKeyboard.loadBindingsXML(filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
mHasUnsavedChanges = false;
|
||||
}
|
||||
|
||||
LLKeyData LLKeyConflictHandler::getDefaultControl(EControlTypes control_type, U32 index)
|
||||
{
|
||||
if (mLoadedMode == MODE_GENERAL)
|
||||
{
|
||||
std::string name = getControlName(control_type);
|
||||
LLControlVariablePtr var = gSavedSettings.getControl(name);
|
||||
if (var)
|
||||
{
|
||||
return LLKeyBind(var->getDefault()).getKeyData(index);
|
||||
}
|
||||
return LLKeyData();
|
||||
}
|
||||
else
|
||||
{
|
||||
control_map_t::iterator iter = mDefaultsMap.find(control_type);
|
||||
if (iter != mDefaultsMap.end())
|
||||
{
|
||||
return iter->second.mKeyBind.getKeyData(index);
|
||||
}
|
||||
return LLKeyData();
|
||||
}
|
||||
}
|
||||
|
||||
void LLKeyConflictHandler::resetToDefault(EControlTypes control_type, U32 index)
|
||||
{
|
||||
LLKeyData data = getDefaultControl(control_type, index);
|
||||
mControlsMap[control_type].setKeyData(data, index);
|
||||
}
|
||||
|
||||
void LLKeyConflictHandler::resetToDefault(EControlTypes control_type)
|
||||
{
|
||||
if (mLoadedMode == MODE_GENERAL)
|
||||
{
|
||||
std::string name = getControlName(control_type);
|
||||
LLControlVariablePtr var = gSavedSettings.getControl(name);
|
||||
if (var)
|
||||
{
|
||||
mControlsMap[control_type].mKeyBind = LLKeyBind(var->getDefault());
|
||||
}
|
||||
else
|
||||
{
|
||||
mControlsMap[control_type].mKeyBind.clear();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
control_map_t::iterator iter = mDefaultsMap.find(control_type);
|
||||
if (iter != mDefaultsMap.end())
|
||||
{
|
||||
mControlsMap[control_type].mKeyBind = iter->second.mKeyBind;
|
||||
}
|
||||
else
|
||||
{
|
||||
mControlsMap[control_type].mKeyBind.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLKeyConflictHandler::resetToDefaults(EModes mode)
|
||||
{
|
||||
if (mode == MODE_GENERAL)
|
||||
{
|
||||
for (U32 i = 0; i < CONTROL_NUM_INDICES; i++)
|
||||
{
|
||||
EControlTypes type = (EControlTypes)i;
|
||||
switch (type)
|
||||
{
|
||||
case LLKeyConflictHandler::CONTROL_VIEW_ACTIONS:
|
||||
case LLKeyConflictHandler::CONTROL_INTERACTIONS:
|
||||
case LLKeyConflictHandler::CONTROL_MOVEMENTS:
|
||||
case LLKeyConflictHandler::CONTROL_MEDIACONTENT:
|
||||
case LLKeyConflictHandler::CONTROL_CAMERA:
|
||||
case LLKeyConflictHandler::CONTROL_EDIT_TITLE:
|
||||
case LLKeyConflictHandler::CONTROL_RESERVED:
|
||||
// ignore 'headers', they are for representation and organization purposes
|
||||
break;
|
||||
default:
|
||||
{
|
||||
resetToDefault(type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mControlsMap.clear();
|
||||
mControlsMap = mDefaultsMap;
|
||||
generatePlaceholders();
|
||||
}
|
||||
|
||||
mHasUnsavedChanges = true;
|
||||
}
|
||||
|
||||
void LLKeyConflictHandler::resetToDefaults()
|
||||
{
|
||||
if (!empty())
|
||||
{
|
||||
resetToDefaults(mLoadedMode);
|
||||
}
|
||||
}
|
||||
|
||||
void LLKeyConflictHandler::resetAllToDefaults()
|
||||
{
|
||||
std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "keys.xml");
|
||||
if (gDirUtilp->fileExists(filename))
|
||||
{
|
||||
LLFile::remove(filename);
|
||||
std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "keys.xml");
|
||||
gViewerKeyboard.loadBindingsXML(filename);
|
||||
}
|
||||
|
||||
for (U32 i = 0; i < CONTROL_NUM_INDICES; i++)
|
||||
{
|
||||
EControlTypes type = (EControlTypes)i;
|
||||
switch (type)
|
||||
{
|
||||
case LLKeyConflictHandler::CONTROL_VIEW_ACTIONS:
|
||||
case LLKeyConflictHandler::CONTROL_INTERACTIONS:
|
||||
case LLKeyConflictHandler::CONTROL_MOVEMENTS:
|
||||
case LLKeyConflictHandler::CONTROL_MEDIACONTENT:
|
||||
case LLKeyConflictHandler::CONTROL_RESERVED:
|
||||
// ignore 'headers', they are for representation and organization purposes
|
||||
break;
|
||||
default:
|
||||
{
|
||||
resetToDefault(type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
mHasUnsavedChanges = false;
|
||||
}
|
||||
|
||||
void LLKeyConflictHandler::clear()
|
||||
{
|
||||
mHasUnsavedChanges = false;
|
||||
mControlsMap.clear();
|
||||
mDefaultsMap.clear();
|
||||
}
|
||||
|
||||
void LLKeyConflictHandler::resetKeyboardBindings()
|
||||
{
|
||||
std::string filename = gDirUtilp->findFile("keys.xml",
|
||||
gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, ""),
|
||||
gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, ""));
|
||||
|
||||
gViewerKeyboard.loadBindingsXML(filename);
|
||||
}
|
||||
|
||||
void LLKeyConflictHandler::generatePlaceholders()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void LLKeyConflictHandler::registerTemporaryControl(EControlTypes control_type, EMouseClickType mouse, KEY key, MASK mask, U32 conflict_mask)
|
||||
{
|
||||
LLKeyConflict *type_data = &mControlsMap[control_type];
|
||||
type_data->mAssignable = false;
|
||||
type_data->mConflictMask = conflict_mask;
|
||||
type_data->mKeyBind.addKeyData(mouse, key, mask);
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,214 @@
|
|||
/**
|
||||
* @file llkeyconflict.h
|
||||
* @brief
|
||||
*
|
||||
* $LicenseInfo:firstyear=2019&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2019, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLKEYCONFLICT_H
|
||||
#define LL_LLKEYCONFLICT_H
|
||||
|
||||
#include "llkeybind.h"
|
||||
#include "llviewerkeyboard.h"
|
||||
|
||||
|
||||
class LLKeyConflict
|
||||
{
|
||||
public:
|
||||
LLKeyConflict() : mAssignable(true), mConflictMask(0) {} //temporary assignable, don't forget to change once all keys are recorded
|
||||
LLKeyConflict(bool assignable, U32 conflict_mask)
|
||||
: mAssignable(assignable), mConflictMask(conflict_mask) {}
|
||||
LLKeyConflict(const LLKeyBind &bind, bool assignable, U32 conflict_mask)
|
||||
: mAssignable(assignable), mConflictMask(conflict_mask), mKeyBind(bind) {}
|
||||
|
||||
LLKeyData getPrimaryKeyData() { return mKeyBind.getKeyData(0); }
|
||||
LLKeyData getKeyData(U32 index) { return mKeyBind.getKeyData(index); }
|
||||
void setPrimaryKeyData(const LLKeyData& data) { mKeyBind.replaceKeyData(data, 0); }
|
||||
void setKeyData(const LLKeyData& data, U32 index) { mKeyBind.replaceKeyData(data, index); }
|
||||
bool canHandle(EMouseClickType mouse, KEY key, MASK mask) { return mKeyBind.canHandle(mouse, key, mask); }
|
||||
|
||||
LLKeyBind mKeyBind;
|
||||
bool mAssignable; // whether user can change key or key simply acts as placeholder
|
||||
U32 mConflictMask;
|
||||
};
|
||||
|
||||
class LLKeyConflictHandler
|
||||
{
|
||||
public:
|
||||
|
||||
enum EModes // partially repeats e_keyboard_mode
|
||||
{
|
||||
MODE_FIRST_PERSON,
|
||||
MODE_THIRD_PERSON,
|
||||
MODE_EDIT,
|
||||
MODE_EDIT_AVATAR,
|
||||
MODE_SITTING,
|
||||
MODE_GENERAL,
|
||||
MODE_COUNT
|
||||
};
|
||||
|
||||
enum EConflictTypes // priority higherst to lowest
|
||||
{
|
||||
CONFLICT_LAND = 1,
|
||||
CONFLICT_OBJECT = 2,
|
||||
CONFLICT_TOUCH = 4,
|
||||
CONFLICT_INTERACTIBLE = 8,
|
||||
CONFLICT_AVATAR = 16,
|
||||
CONFLICT_ANY = 511
|
||||
};
|
||||
|
||||
// todo, unfortunately will have to remove this and use map/array of strings
|
||||
enum EControlTypes
|
||||
{
|
||||
CONTROL_VIEW_ACTIONS = 0, // Group control, for visual representation in view, not for use
|
||||
CONTROL_ABOUT,
|
||||
CONTROL_ORBIT,
|
||||
CONTROL_PAN,
|
||||
CONTROL_WORLD_MAP,
|
||||
CONTROL_ZOOM,
|
||||
CONTROL_INTERACTIONS, // Group control, for visual representation
|
||||
CONTROL_BUILD,
|
||||
//CONTROL_DRAG,
|
||||
CONTROL_EDIT,
|
||||
//CONTROL_MENU,
|
||||
CONTROL_OPEN,
|
||||
CONTROL_TOUCH,
|
||||
CONTROL_WEAR,
|
||||
CONTROL_MOVEMENTS, // Group control, for visual representation
|
||||
CONTROL_MOVETO,
|
||||
CONTROL_SIT,
|
||||
CONTROL_TELEPORTTO,
|
||||
CONTROL_FORWARD,
|
||||
CONTROL_BACKWARD,
|
||||
CONTROL_LEFT, // Check and sinc name with real movement names
|
||||
CONTROL_RIGHT,
|
||||
CONTROL_LSTRAFE,
|
||||
CONTROL_RSTRAFE,
|
||||
CONTROL_JUMP,
|
||||
CONTROL_DOWN,
|
||||
//CONTROL_RUN,
|
||||
CONTROL_TOGGLE_RUN,
|
||||
CONTROL_TOGGLE_FLY,
|
||||
CONTROL_STOP,
|
||||
CONTROL_CAMERA, // Group control, for visual representation
|
||||
CONTROL_LOOK_UP,
|
||||
CONTROL_LOOK_DOWN,
|
||||
CONTROL_CAMERA_FORWARD,
|
||||
CONTROL_CAMERA_BACKWARD,
|
||||
CONTROL_CAMERA_FFORWARD,
|
||||
CONTROL_CAMERA_FBACKWARD,
|
||||
CONTROL_CAMERA_FSITTING,
|
||||
CONTROL_CAMERA_BSITTING,
|
||||
CONTROL_CAMERA_SOVER,
|
||||
CONTROL_CAMERA_SUNDER,
|
||||
CONTROL_CAMERA_SOVER_SITTING,
|
||||
CONTROL_CAMERA_SUNDER_SITTING,
|
||||
CONTROL_CAMERA_PANUP,
|
||||
CONTROL_CAMERA_PANDOWN,
|
||||
CONTROL_CAMERA_PANLEFT,
|
||||
CONTROL_CAMERA_PANRIGHT,
|
||||
CONTROL_CAMERA_PANIN,
|
||||
CONTROL_CAMERA_PANOUT,
|
||||
CONTROL_CAMERA_SPIN_CCW,
|
||||
CONTROL_CAMERA_SPIN_CW,
|
||||
CONTROL_CAMERA_SPIN_CCW_SITTING,
|
||||
CONTROL_CAMERA_SPIN_CW_SITTING,
|
||||
CONTROL_EDIT_TITLE, // Group control, for visual representation
|
||||
CONTROL_EDIT_AV_SPIN_CCW,
|
||||
CONTROL_EDIT_AV_SPIN_CW,
|
||||
CONTROL_EDIT_AV_SPIN_OVER,
|
||||
CONTROL_EDIT_AV_SPIN_UNDER,
|
||||
CONTROL_EDIT_AV_MV_FORWARD,
|
||||
CONTROL_EDIT_AV_MV_BACKWARD,
|
||||
CONTROL_MEDIACONTENT, // Group control, for visual representation
|
||||
CONTROL_PARCEL, // Play pause
|
||||
CONTROL_MEDIA, // Play stop
|
||||
CONTROL_VOICE, // Keep pressing for it to be ON
|
||||
CONTROL_TOGGLE_VOICE, // Press once to ON/OFF
|
||||
CONTROL_START_CHAT, // Press once to ON/OFF
|
||||
CONTROL_START_GESTURE, // Press once to ON/OFF
|
||||
CONTROL_RESERVED, // Special group control, controls that are disabled by default and not meant to be changed
|
||||
CONTROL_DELETE,
|
||||
CONTROL_RESERVED_MENU,
|
||||
CONTROL_RESERVED_SELECT,
|
||||
CONTROL_SHIFT_SELECT,
|
||||
CONTROL_CNTRL_SELECT,
|
||||
CONTROL_NUM_INDICES // Size, always should be last
|
||||
};
|
||||
|
||||
// Note: missed selection and edition commands (would be really nice to go through selection via MB4/5 or wheel)
|
||||
|
||||
LLKeyConflictHandler();
|
||||
LLKeyConflictHandler(EModes mode);
|
||||
|
||||
bool canHandleControl(EControlTypes control_type, EMouseClickType mouse_ind, KEY key, MASK mask);
|
||||
bool canHandleKey(EControlTypes control_type, KEY key, MASK mask);
|
||||
bool canHandleMouse(EControlTypes control_type, EMouseClickType mouse_ind, MASK mask);
|
||||
bool canHandleMouse(EControlTypes control_type, S32 mouse_ind, MASK mask); //Just for convinience
|
||||
bool canAssignControl(EControlTypes control_type);
|
||||
void registerControl(EControlTypes control_type, U32 data_index, EMouseClickType mouse_ind, KEY key, MASK mask); //todo: return conflicts?
|
||||
|
||||
LLKeyData getControl(EControlTypes control_type, U32 data_index);
|
||||
|
||||
static std::string LLKeyConflictHandler::getStringFromKeyData(const LLKeyData& keydata);
|
||||
static std::string getControlName(EControlTypes control_type);
|
||||
std::string getControlString(EControlTypes control_type, U32 data_index);
|
||||
|
||||
|
||||
// Drops any changes loads controls with ones from 'saved settings' or from xml
|
||||
void loadFromSettings(EModes load_mode);
|
||||
// Saves settings to 'saved settings' or to xml
|
||||
void saveToSettings();
|
||||
|
||||
LLKeyData getDefaultControl(EControlTypes control_type, U32 data_index);
|
||||
// Resets keybinding to default variant from 'saved settings' or xml
|
||||
void resetToDefault(EControlTypes control_type, U32 index);
|
||||
void resetToDefault(EControlTypes control_type);
|
||||
void resetToDefaults(EModes mode);
|
||||
void resetToDefaults();
|
||||
void resetAllToDefaults();
|
||||
|
||||
bool empty() { return mControlsMap.empty(); }
|
||||
void clear();
|
||||
|
||||
bool hasUnsavedChanges() { return mHasUnsavedChanges; }
|
||||
EModes getLoadedMode() { return mLoadedMode; }
|
||||
// todo: conflict search
|
||||
|
||||
private:
|
||||
// at the moment these kind of control is not savable, but takes part will take part in conflict resolution
|
||||
void registerTemporaryControl(EControlTypes control_type, EMouseClickType mouse_ind, KEY key, MASK mask, U32 conflict_mask);
|
||||
|
||||
typedef std::map<EControlTypes, LLKeyConflict> control_map_t;
|
||||
void loadFromSettings(const LLViewerKeyboard::KeyMode& keymode, control_map_t *destination);
|
||||
void loadFromSettings(const EModes &load_mode, const std::string &filename, control_map_t *destination);
|
||||
void resetKeyboardBindings();
|
||||
void generatePlaceholders(); //'headers' for ui and non-assignable values
|
||||
|
||||
control_map_t mControlsMap;
|
||||
control_map_t mDefaultsMap;
|
||||
bool mHasUnsavedChanges;
|
||||
EModes mLoadedMode;
|
||||
};
|
||||
|
||||
|
||||
#endif // LL_LLKEYCONFLICT_H
|
||||
|
|
@ -605,6 +605,12 @@ void start_gesture( EKeystate s )
|
|||
}
|
||||
}
|
||||
|
||||
void toggle_parcel_media(EKeystate s)
|
||||
{
|
||||
bool pause = LLViewerMedia::isAnyMediaPlaying();
|
||||
LLViewerMedia::setAllMediaPaused(pause);
|
||||
}
|
||||
|
||||
#define REGISTER_KEYBOARD_ACTION(KEY, ACTION) LLREGISTER_STATIC(LLKeyboardActionRegistry, KEY, ACTION);
|
||||
REGISTER_KEYBOARD_ACTION("jump", agent_jump);
|
||||
REGISTER_KEYBOARD_ACTION("push_down", agent_push_down);
|
||||
|
|
@ -646,6 +652,7 @@ REGISTER_KEYBOARD_ACTION("edit_avatar_move_backward", edit_avatar_move_backward)
|
|||
REGISTER_KEYBOARD_ACTION("stop_moving", stop_moving);
|
||||
REGISTER_KEYBOARD_ACTION("start_chat", start_chat);
|
||||
REGISTER_KEYBOARD_ACTION("start_gesture", start_gesture);
|
||||
REGISTER_KEYBOARD_ACTION("toggle_parcel_media", toggle_parcel_media);
|
||||
#undef REGISTER_KEYBOARD_ACTION
|
||||
|
||||
LLViewerKeyboard::LLViewerKeyboard()
|
||||
|
|
@ -807,7 +814,7 @@ BOOL LLViewerKeyboard::bindKey(const S32 mode, const KEY key, const MASK mask, c
|
|||
mBindings[mode][index].mFunction = function;
|
||||
|
||||
if (index == mBindingCount[mode])
|
||||
mBindingCount[mode]++;
|
||||
mBindingCount[mode]++;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
|
@ -818,21 +825,25 @@ LLViewerKeyboard::KeyBinding::KeyBinding()
|
|||
command("command")
|
||||
{}
|
||||
|
||||
LLViewerKeyboard::KeyMode::KeyMode(EKeyboardMode _mode)
|
||||
: bindings("binding"),
|
||||
mode(_mode)
|
||||
LLViewerKeyboard::KeyMode::KeyMode()
|
||||
: bindings("binding")
|
||||
{}
|
||||
|
||||
LLViewerKeyboard::Keys::Keys()
|
||||
: first_person("first_person", KeyMode(MODE_FIRST_PERSON)),
|
||||
third_person("third_person", KeyMode(MODE_THIRD_PERSON)),
|
||||
edit("edit", KeyMode(MODE_EDIT)),
|
||||
sitting("sitting", KeyMode(MODE_SITTING)),
|
||||
edit_avatar("edit_avatar", KeyMode(MODE_EDIT_AVATAR))
|
||||
: first_person("first_person"),
|
||||
third_person("third_person"),
|
||||
edit("edit"),
|
||||
sitting("sitting"),
|
||||
edit_avatar("edit_avatar")
|
||||
{}
|
||||
|
||||
S32 LLViewerKeyboard::loadBindingsXML(const std::string& filename)
|
||||
{
|
||||
for (S32 i = 0; i < MODE_COUNT; i++)
|
||||
{
|
||||
mBindingCount[i] = 0;
|
||||
}
|
||||
|
||||
S32 binding_count = 0;
|
||||
Keys keys;
|
||||
LLSimpleXUIParser parser;
|
||||
|
|
@ -840,16 +851,16 @@ S32 LLViewerKeyboard::loadBindingsXML(const std::string& filename)
|
|||
if (parser.readXUI(filename, keys)
|
||||
&& keys.validateBlock())
|
||||
{
|
||||
binding_count += loadBindingMode(keys.first_person);
|
||||
binding_count += loadBindingMode(keys.third_person);
|
||||
binding_count += loadBindingMode(keys.edit);
|
||||
binding_count += loadBindingMode(keys.sitting);
|
||||
binding_count += loadBindingMode(keys.edit_avatar);
|
||||
binding_count += loadBindingMode(keys.first_person, MODE_FIRST_PERSON);
|
||||
binding_count += loadBindingMode(keys.third_person, MODE_THIRD_PERSON);
|
||||
binding_count += loadBindingMode(keys.edit, MODE_EDIT);
|
||||
binding_count += loadBindingMode(keys.sitting, MODE_SITTING);
|
||||
binding_count += loadBindingMode(keys.edit_avatar, MODE_EDIT_AVATAR);
|
||||
}
|
||||
return binding_count;
|
||||
}
|
||||
|
||||
S32 LLViewerKeyboard::loadBindingMode(const LLViewerKeyboard::KeyMode& keymode)
|
||||
S32 LLViewerKeyboard::loadBindingMode(const LLViewerKeyboard::KeyMode& keymode, S32 mode)
|
||||
{
|
||||
S32 binding_count = 0;
|
||||
for (LLInitParam::ParamIterator<KeyBinding>::const_iterator it = keymode.bindings.begin(),
|
||||
|
|
@ -857,12 +868,15 @@ S32 LLViewerKeyboard::loadBindingMode(const LLViewerKeyboard::KeyMode& keymode)
|
|||
it != end_it;
|
||||
++it)
|
||||
{
|
||||
KEY key;
|
||||
MASK mask;
|
||||
LLKeyboard::keyFromString(it->key, &key);
|
||||
LLKeyboard::maskFromString(it->mask, &mask);
|
||||
bindKey(keymode.mode, key, mask, it->command);
|
||||
binding_count++;
|
||||
if (!it->key.getValue().empty())
|
||||
{
|
||||
KEY key;
|
||||
MASK mask;
|
||||
LLKeyboard::keyFromString(it->key, &key);
|
||||
LLKeyboard::maskFromString(it->mask, &mask);
|
||||
bindKey(mode, key, mask, it->command);
|
||||
binding_count++;
|
||||
}
|
||||
}
|
||||
|
||||
return binding_count;
|
||||
|
|
|
|||
|
|
@ -71,8 +71,8 @@ public:
|
|||
struct KeyMode : public LLInitParam::Block<KeyMode>
|
||||
{
|
||||
Multiple<KeyBinding> bindings;
|
||||
EKeyboardMode mode;
|
||||
KeyMode(EKeyboardMode mode);
|
||||
|
||||
KeyMode();
|
||||
};
|
||||
|
||||
struct Keys : public LLInitParam::Block<Keys>
|
||||
|
|
@ -100,7 +100,7 @@ public:
|
|||
void scanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level);
|
||||
|
||||
private:
|
||||
S32 loadBindingMode(const LLViewerKeyboard::KeyMode& keymode);
|
||||
S32 loadBindingMode(const LLViewerKeyboard::KeyMode& keymode, S32 mode);
|
||||
BOOL bindKey(const S32 mode, const KEY key, const MASK mask, const std::string& function_name);
|
||||
|
||||
// Hold all the ugly stuff torn out to make LLKeyboard non-viewer-specific here
|
||||
|
|
|
|||
|
|
@ -35,7 +35,6 @@
|
|||
#include "llnotificationsutil.h"
|
||||
#include "llsdserialize.h"
|
||||
#include "llui.h"
|
||||
#include "llkeybindings.h"
|
||||
#include "llkeyboard.h"
|
||||
#include "llagent.h"
|
||||
|
||||
|
|
@ -692,33 +691,38 @@ void LLVoiceClient::keyDown(KEY key, MASK mask)
|
|||
return;
|
||||
}
|
||||
|
||||
if (LLAgent::isActionAllowed("speak") && gControlBindings.canHandleKey(LLControlBindings::CONTROL_VOICE, key, mask))
|
||||
//
|
||||
/*static LLCachedControl<LLSD> key_bind(gSavedSettings, "control_toggle_voice");
|
||||
LLKeyBind bind(key_bind);
|
||||
if (LLAgent::isActionAllowed("speak") && bind().canHandleKey(key, mask))
|
||||
{
|
||||
bool down = gKeyboard->getKeyDown(mPTTKey);
|
||||
if (down)
|
||||
{
|
||||
inputUserControlState(down);
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
}
|
||||
void LLVoiceClient::keyUp(KEY key, MASK mask)
|
||||
{
|
||||
if (gControlBindings.canHandleKey(LLControlBindings::CONTROL_VOICE, key, mask))
|
||||
/*static LLCachedControl<LLKeyBind> key_bind(gSavedSettings, "control_toggle_voice");
|
||||
if (key_bind().canHandleKey(key, mask))
|
||||
{
|
||||
bool down = gKeyboard->getKeyDown(mPTTKey);
|
||||
if (!down)
|
||||
{
|
||||
inputUserControlState(down);
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
void LLVoiceClient::updateMouseState(S32 click, MASK mask, bool down)
|
||||
{
|
||||
if(LLAgent::isActionAllowed("speak") && gControlBindings.canHandleMouse(LLControlBindings::CONTROL_VOICE, click, mask))
|
||||
/*static LLCachedControl<LLKeyBind> mouse_bind(gSavedSettings, "control_toggle_voice");
|
||||
if (mouse_bind().canHandleMouse((EMouseClickType)click, mask))
|
||||
{
|
||||
inputUserControlState(down);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,15 @@
|
|||
height="90"
|
||||
layout="topleft"
|
||||
name="modal container"
|
||||
width="240">
|
||||
width="272">
|
||||
<floater.string
|
||||
name="keyboard">
|
||||
Keyboard
|
||||
</floater.string>
|
||||
<floater.string
|
||||
name="mouse">
|
||||
Mouse Buttons
|
||||
</floater.string>
|
||||
<text
|
||||
type="string"
|
||||
halign="center"
|
||||
|
|
@ -16,19 +24,35 @@
|
|||
height="30"
|
||||
layout="topleft"
|
||||
left="30"
|
||||
name="Save item as:"
|
||||
name="descritption"
|
||||
top="25"
|
||||
word_wrap="true"
|
||||
width="180">
|
||||
Press a key to set your Speak button trigger.
|
||||
width="212">
|
||||
Press a key to set your trigger.
|
||||
Allowed input: [INPUT].
|
||||
</text>
|
||||
<button
|
||||
height="23"
|
||||
label="Cancel"
|
||||
label_selected="Cancel"
|
||||
label="Set Empty"
|
||||
layout="topleft"
|
||||
right="-10"
|
||||
name="Cancel"
|
||||
left="8"
|
||||
name="SetEmpty"
|
||||
top_pad="8"
|
||||
width="100" />
|
||||
width="80" />
|
||||
<button
|
||||
height="23"
|
||||
label="Default"
|
||||
layout="topleft"
|
||||
left_pad="8"
|
||||
name="Default"
|
||||
top_delta="0"
|
||||
width="80" />
|
||||
<button
|
||||
height="23"
|
||||
label="Cancel"
|
||||
layout="topleft"
|
||||
left_pad="8"
|
||||
name="Cancel"
|
||||
top_delta="0"
|
||||
width="80" />
|
||||
</floater>
|
||||
|
|
|
|||
|
|
@ -82,37 +82,37 @@
|
|||
Teleport To
|
||||
</panel.string>
|
||||
<panel.string
|
||||
name="control_forward">
|
||||
name="push_forward">
|
||||
Move Forward
|
||||
</panel.string>
|
||||
<panel.string
|
||||
name="control_backward">
|
||||
name="push_backward">
|
||||
Move Backward
|
||||
</panel.string>
|
||||
<panel.string
|
||||
name="control_left">
|
||||
name="turn_left">
|
||||
Left
|
||||
</panel.string>
|
||||
<panel.string
|
||||
name="control_right">
|
||||
name="turn_right">
|
||||
Right
|
||||
</panel.string>
|
||||
<!--(check with move floater)-->
|
||||
<panel.string
|
||||
name="control_lstrafe">
|
||||
name="slide_left">
|
||||
Strafe left
|
||||
</panel.string>
|
||||
<panel.string
|
||||
name="control_rstrafe">
|
||||
name="slide_right">
|
||||
Strafe right
|
||||
</panel.string>
|
||||
<panel.string
|
||||
name="control_jump">
|
||||
Strafe right
|
||||
name="jump">
|
||||
Jump/Up
|
||||
</panel.string>
|
||||
<panel.string
|
||||
name="control_down">
|
||||
Strafe right
|
||||
name="push_down">
|
||||
Down
|
||||
</panel.string>
|
||||
<panel.string
|
||||
name="control_run">
|
||||
|
|
@ -123,9 +123,85 @@
|
|||
Toggle Run
|
||||
</panel.string>
|
||||
<panel.string
|
||||
name="control_fly">
|
||||
name="toggle_fly">
|
||||
Fly/Stop flying
|
||||
</panel.string>
|
||||
<panel.string
|
||||
name="control_camera">
|
||||
Camera
|
||||
</panel.string>
|
||||
<panel.string
|
||||
name="look_up">
|
||||
Look Up
|
||||
</panel.string>
|
||||
<panel.string
|
||||
name="look_down">
|
||||
Look Down
|
||||
</panel.string>
|
||||
<panel.string
|
||||
name="move_forward">
|
||||
Camera Forward
|
||||
</panel.string>
|
||||
<panel.string
|
||||
name="move_backward">
|
||||
Camera Backward
|
||||
</panel.string>
|
||||
<panel.string
|
||||
name="move_forward_fast">
|
||||
Camera Forward Fast
|
||||
</panel.string>
|
||||
<panel.string
|
||||
name="move_backward_fast">
|
||||
Camera Backward Fast
|
||||
</panel.string>
|
||||
<panel.string
|
||||
name="move_forward_sitting">
|
||||
Camera Forward Sitting
|
||||
</panel.string>
|
||||
<panel.string
|
||||
name="move_backward_sitting">
|
||||
Camera Backward Sitting
|
||||
</panel.string>
|
||||
<panel.string
|
||||
name="spin_over">
|
||||
Camera Spin Over
|
||||
</panel.string>
|
||||
<panel.string
|
||||
name="spin_under">
|
||||
Camera Spin Under
|
||||
</panel.string>
|
||||
<panel.string
|
||||
name="spin_over_sitting">
|
||||
Camera Spin Over
|
||||
</panel.string>
|
||||
<panel.string
|
||||
name="spin_under_sitting">
|
||||
Camera Spin Under
|
||||
</panel.string>
|
||||
<panel.string
|
||||
name="pan_up">
|
||||
Camera Pan Up
|
||||
</panel.string>
|
||||
<panel.string
|
||||
name="pan_down">
|
||||
Camera Pan Down
|
||||
</panel.string>
|
||||
<panel.string
|
||||
name="pan_left">
|
||||
Camera Pan Left
|
||||
</panel.string>
|
||||
<panel.string
|
||||
name="pan_right">
|
||||
Camera Pan Right
|
||||
</panel.string>
|
||||
<panel.string
|
||||
name="pan_left">
|
||||
Camera Pan In
|
||||
</panel.string>
|
||||
<panel.string
|
||||
name="pan_right">
|
||||
Camera Pan Out
|
||||
</panel.string>
|
||||
<panel.string
|
||||
name="control_mediacontent">
|
||||
Sound and Media
|
||||
|
|
@ -150,6 +226,10 @@
|
|||
name="control_reserved">
|
||||
Reserved Controls
|
||||
</panel.string>
|
||||
<panel.string
|
||||
name="control_delete">
|
||||
Delete
|
||||
</panel.string>
|
||||
<!--
|
||||
name="control_menu" not needed
|
||||
-->
|
||||
|
|
@ -166,15 +246,60 @@
|
|||
Add to Selection
|
||||
</panel.string>
|
||||
|
||||
<combo_box
|
||||
follows="top|left"
|
||||
layout="topleft"
|
||||
top="6"
|
||||
left="10"
|
||||
height="23"
|
||||
width="110"
|
||||
name="key_mode">
|
||||
<combo_box.item
|
||||
label="First Person "
|
||||
name="first_person"
|
||||
value="0"/>
|
||||
<combo_box.item
|
||||
label="Third Person "
|
||||
name="third_person"
|
||||
value="1"/>
|
||||
<combo_box.item
|
||||
label="Edit"
|
||||
name="edit"
|
||||
value="2"/>
|
||||
<combo_box.item
|
||||
label="Edit Avatar"
|
||||
name="edit_avatar"
|
||||
value="3"/>
|
||||
<combo_box.item
|
||||
label="Sitting"
|
||||
name="sitting"
|
||||
value="4"/>
|
||||
<combo_box.item
|
||||
label="General"
|
||||
name="general"
|
||||
value="5"/>
|
||||
</combo_box>
|
||||
|
||||
<button
|
||||
follows="top|left"
|
||||
layout="topleft"
|
||||
top="6"
|
||||
right="-10"
|
||||
height="23"
|
||||
width="110"
|
||||
label="Restore Default"
|
||||
name="restore_defaults"/>
|
||||
|
||||
<scroll_list
|
||||
draw_heading="true"
|
||||
follows="all"
|
||||
layout="topleft"
|
||||
column_padding="0"
|
||||
top="3"
|
||||
top="31"
|
||||
left="3"
|
||||
bottom="-3"
|
||||
right="-3"
|
||||
can_sort="false"
|
||||
multi_select="false"
|
||||
name="controls_list">
|
||||
<scroll_list.columns
|
||||
|
|
@ -182,13 +307,17 @@
|
|||
label="Action"
|
||||
name="lst_action" />
|
||||
<scroll_list.columns
|
||||
relative_width="0.33"
|
||||
label="Primary Control Method"
|
||||
relative_width="0.22"
|
||||
label="Control Method 1"
|
||||
name="lst_ctrl1" />
|
||||
<scroll_list.columns
|
||||
relative_width="0.33"
|
||||
label="Secondary Control Method"
|
||||
relative_width="0.22"
|
||||
label="Control Method 2"
|
||||
name="lst_ctrl2" />
|
||||
<scroll_list.columns
|
||||
relative_width="0.22"
|
||||
label="Control Method 3"
|
||||
name="lst_ctrl3" />
|
||||
<scroll_list.commit_callback
|
||||
function="Pref.CommitControl" />
|
||||
</scroll_list>
|
||||
|
|
|
|||
Loading…
Reference in New Issue