SL-6109 Keyaboard support ready

master
andreykproductengine 2019-09-17 21:36:59 +03:00 committed by Andrey Kleshchev
parent 3633ccf1a1
commit 4df05c5a89
14 changed files with 1807 additions and 419 deletions

View File

@ -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();
}

View File

@ -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;
};

View File

@ -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];

View File

@ -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;

View File

@ -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

View File

@ -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)
{

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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);
}
}*/
}

View File

@ -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>

View File

@ -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>