diff options
| -rw-r--r-- | indra/llcommon/indra_constants.h | 3 | ||||
| -rw-r--r-- | indra/llcommon/llkeybind.cpp | 152 | ||||
| -rw-r--r-- | indra/llcommon/llkeybind.h | 13 | ||||
| -rw-r--r-- | indra/llui/llscrolllistcell.cpp | 5 | ||||
| -rw-r--r-- | indra/newview/llagent.cpp | 11 | ||||
| -rw-r--r-- | indra/newview/llagent.h | 1 | ||||
| -rw-r--r-- | indra/newview/llappviewer.cpp | 1 | ||||
| -rw-r--r-- | indra/newview/llfloaterpreference.cpp | 92 | ||||
| -rw-r--r-- | indra/newview/llfloaterpreference.h | 2 | ||||
| -rw-r--r-- | indra/newview/llkeyconflict.cpp | 131 | ||||
| -rw-r--r-- | indra/newview/llkeyconflict.h | 10 | ||||
| -rw-r--r-- | indra/newview/llviewerkeyboard.cpp | 424 | ||||
| -rw-r--r-- | indra/newview/llviewerkeyboard.h | 82 | ||||
| -rw-r--r-- | indra/newview/llviewerwindow.cpp | 68 | ||||
| -rw-r--r-- | indra/newview/llviewerwindow.h | 3 | ||||
| -rw-r--r-- | indra/newview/skins/default/xui/en/floater_select_key.xml | 16 | ||||
| -rw-r--r-- | indra/newview/skins/default/xui/en/panel_preferences_controls.xml | 10 | 
17 files changed, 813 insertions, 211 deletions
| diff --git a/indra/llcommon/indra_constants.h b/indra/llcommon/indra_constants.h index e763d413e5..ef29e7e5cd 100644 --- a/indra/llcommon/indra_constants.h +++ b/indra/llcommon/indra_constants.h @@ -61,7 +61,8 @@ enum EMouseClickType{      CLICK_RIGHT,      CLICK_BUTTON4,      CLICK_BUTTON5, -    CLICK_DOUBLELEFT +    CLICK_DOUBLELEFT, +    CLICK_COUNT // 'size', CLICK_NONE does not counts  };  // keys diff --git a/indra/llcommon/llkeybind.cpp b/indra/llcommon/llkeybind.cpp index 765084bbf6..0eca289d4b 100644 --- a/indra/llcommon/llkeybind.cpp +++ b/indra/llcommon/llkeybind.cpp @@ -32,20 +32,59 @@  #include "llsdutil.h"  LLKeyData::LLKeyData() -    : mMouse(CLICK_NONE), mKey(KEY_NONE), mMask(MASK_NONE) +    : +    mMouse(CLICK_NONE), +    mKey(KEY_NONE), +    mMask(MASK_NONE), +    mIgnoreMasks(false)  {  }  LLKeyData::LLKeyData(EMouseClickType mouse, KEY key, MASK mask) -: mMouse(mouse), mKey(key), mMask(mask) +    : +    mMouse(mouse), +    mKey(key), +    mMask(mask), +    mIgnoreMasks(false) +{ +} + +LLKeyData::LLKeyData(EMouseClickType mouse, KEY key, bool ignore_mask) +    : +    mMouse(mouse), +    mKey(key), +    mMask(MASK_NONE), +    mIgnoreMasks(ignore_mask) +{ +} + +LLKeyData::LLKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignore_mask) +    : +    mMouse(mouse), +    mKey(key), +    mMask(mask), +    mIgnoreMasks(ignore_mask)  {  }  LLKeyData::LLKeyData(const LLSD &key_data)  { -    mMouse = (EMouseClickType)key_data["mouse"].asInteger(); -    mKey = key_data["key"].asInteger(); -    mMask = key_data["mask"].asInteger(); +    if (key_data.has("mouse")) +    { +        mMouse = (EMouseClickType)key_data["mouse"].asInteger(); +    } +    if (key_data.has("key")) +    { +        mKey = key_data["key"].asInteger(); +    } +    if (key_data.has("ignore_accelerators")) +    { +        mIgnoreMasks = key_data["ignore_accelerators"]; +    } +    if (key_data.has("mask")) +    { +        mMask = key_data["mask"].asInteger(); +    }  }  LLSD LLKeyData::asLLSD() const @@ -53,13 +92,20 @@ LLSD LLKeyData::asLLSD() const      LLSD data;      data["mouse"] = (LLSD::Integer)mMouse;      data["key"] = (LLSD::Integer)mKey; -    data["mask"] = (LLSD::Integer)mMask; +    if (mIgnoreMasks) +    { +        data["ignore_accelerators"] = (LLSD::Boolean)mIgnoreMasks; +    } +    else +    { +        data["mask"] = (LLSD::Integer)mMask; +    }      return data;  }  bool LLKeyData::isEmpty() const  { -    return mMouse == CLICK_NONE && mKey == KEY_NONE &&  mMask == MASK_NONE; +    return mMouse == CLICK_NONE && mKey == KEY_NONE;  }  void LLKeyData::reset() @@ -67,6 +113,7 @@ void LLKeyData::reset()      mMouse = CLICK_NONE;      mKey = KEY_NONE;      mMask = MASK_NONE; +    mIgnoreMasks = false;  }  LLKeyData& LLKeyData::operator=(const LLKeyData& rhs) @@ -74,6 +121,7 @@ LLKeyData& LLKeyData::operator=(const LLKeyData& rhs)      mMouse = rhs.mMouse;      mKey = rhs.mKey;      mMask = rhs.mMask; +    mIgnoreMasks = rhs.mIgnoreMasks;      return *this;  } @@ -82,6 +130,7 @@ bool LLKeyData::operator==(const LLKeyData& rhs)      if (mMouse != rhs.mMouse) return false;      if (mKey != rhs.mKey) return false;      if (mMask != rhs.mMask) return false; +    if (mIgnoreMasks != rhs.mIgnoreMasks) return false;      return true;  } @@ -90,6 +139,29 @@ bool LLKeyData::operator!=(const LLKeyData& rhs)      if (mMouse != rhs.mMouse) return true;      if (mKey != rhs.mKey) return true;      if (mMask != rhs.mMask) return true; +    if (mIgnoreMasks != rhs.mIgnoreMasks) return true; +    return false; +} + +bool LLKeyData::canHandle(const LLKeyData& data) const +{ +    if (data.mKey == mKey +        && data.mMouse == mMouse +        && (mIgnoreMasks || data.mMask == mMask)) +    { +        return true; +    } +    return false; +} + +bool LLKeyData::canHandle(EMouseClickType mouse, KEY key, MASK mask) const +{ +    if (mouse == mMouse +        && key == mKey +        && (mIgnoreMasks || mask == mMask)) +    { +        return true; +    }      return false;  } @@ -167,7 +239,7 @@ bool LLKeyBind::canHandle(EMouseClickType mouse, KEY key, MASK mask) const      for (data_vector_t::const_iterator iter = mData.begin(); iter != mData.end(); iter++)      { -        if (iter->mKey == key && iter->mMask == mask && iter->mMouse == mouse) +        if (iter->canHandle(mouse, key, mask))          {              return true;          } @@ -185,11 +257,34 @@ bool LLKeyBind::canHandleMouse(EMouseClickType mouse, MASK mask) const      return canHandle(mouse, KEY_NONE, mask);  } -bool LLKeyBind::addKeyData(EMouseClickType mouse, KEY key, MASK mask) +bool LLKeyBind::hasKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignore) const +{ +    if (mouse != CLICK_NONE || key != KEY_NONE) +    { +        for (data_vector_t::const_iterator iter = mData.begin(); iter != mData.end(); iter++) +        { +            if (iter->mKey == key +                && iter->mMask == mask +                && iter->mMouse == mouse +                && iter->mIgnoreMasks == ignore) +            { +                return true; +            } +        } +    } +    return false; +} + +bool LLKeyBind::hasKeyData(const LLKeyData& data) const  { -    if (!canHandle(mouse, key, mask)) +    return hasKeyData(data.mMouse, data.mKey, data.mMask, data.mIgnoreMasks); +} + +bool LLKeyBind::addKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignore) +{ +    if (!hasKeyData(mouse, key, mask, ignore))      { -        mData.push_back(LLKeyData(mouse, key, mask)); +        mData.push_back(LLKeyData(mouse, key, mask, ignore));          return true;      }      return false; @@ -197,7 +292,7 @@ bool LLKeyBind::addKeyData(EMouseClickType mouse, KEY key, MASK mask)  bool LLKeyBind::addKeyData(const LLKeyData& data)  { -    if (!canHandle(data.mMouse, data.mKey, data.mMask)) +    if (!hasKeyData(data))      {          mData.push_back(data);          return true; @@ -205,37 +300,48 @@ bool LLKeyBind::addKeyData(const LLKeyData& data)      return false;  } -void LLKeyBind::replaceKeyData(EMouseClickType mouse, KEY key, MASK mask, U32 index) +void LLKeyBind::replaceKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignore, U32 index)  { -    if (mouse != CLICK_NONE && key != KEY_NONE && mask != MASK_NONE) +    if (mouse != CLICK_NONE || key != KEY_NONE )      { -        for (data_vector_t::const_iterator iter = mData.begin(); iter != mData.end(); iter++) +        // if both click and key are none, we are inserting a placeholder, we don't want to reset anything +        // otherwise reset identical key +        for (data_vector_t::iterator iter = mData.begin(); iter != mData.end(); iter++)          { -            if (iter->mKey == key && iter->mMask == mask && iter->mMouse == mouse) +            if (iter->mKey == key +                && iter->mMouse == mouse +                && iter->mIgnoreMasks == ignore +                && (iter->mIgnoreMasks || iter->mMask == mask))              { -                mData.erase(iter); +                iter->reset();                  break;              }          }      }      if (mData.size() > index)      { -        mData[index] = LLKeyData(mouse, key, mask); +        mData[index] = LLKeyData(mouse, key, mask, ignore);      }      else      { -        mData.push_back(LLKeyData(mouse, key, mask)); +        mData.push_back(LLKeyData(mouse, key, mask, ignore));      }  }  void LLKeyBind::replaceKeyData(const LLKeyData& data, U32 index)  { -    for (data_vector_t::const_iterator iter = mData.begin(); iter != mData.end(); iter++) +    if (!data.isEmpty())      { -        if (iter->mKey == data.mKey && iter->mMask == data.mMask && iter->mMouse == data.mMouse) +        for (data_vector_t::iterator iter = mData.begin(); iter != mData.end(); iter++)          { -            mData.erase(iter); -            break; +            if (iter->mKey == data.mKey +                && iter->mMouse == data.mMouse +                && iter->mIgnoreMasks == data.mIgnoreMasks +                && (iter->mIgnoreMasks || iter->mMask == data.mMask)) +            { +                iter->reset(); +                break; +            }          }      }      if (mData.size() > index) diff --git a/indra/llcommon/llkeybind.h b/indra/llcommon/llkeybind.h index 481949f275..25179a57f3 100644 --- a/indra/llcommon/llkeybind.h +++ b/indra/llcommon/llkeybind.h @@ -35,6 +35,8 @@ class LL_COMMON_API LLKeyData  public:      LLKeyData();      LLKeyData(EMouseClickType mouse, KEY key, MASK mask); +    LLKeyData(EMouseClickType mouse, KEY key, bool ignore_mask); +    LLKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignore_mask);      LLKeyData(const LLSD &key_data);      LLSD asLLSD() const; @@ -45,9 +47,13 @@ public:      bool operator==(const LLKeyData& rhs);      bool operator!=(const LLKeyData& rhs); +    bool canHandle(const LLKeyData& data) const; +    bool canHandle(EMouseClickType mouse, KEY key, MASK mask) const; +      EMouseClickType mMouse;      KEY mKey;      MASK mMask; +    bool mIgnoreMasks;  };  // One function can bind to multiple Key options @@ -68,10 +74,13 @@ public:      bool canHandleKey(KEY key, MASK mask) const;      bool canHandleMouse(EMouseClickType mouse, MASK mask) const; +    bool LLKeyBind::hasKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignore) const; +    bool LLKeyBind::hasKeyData(const LLKeyData& data) const; +      // these methods enshure there will be no repeats -    bool addKeyData(EMouseClickType mouse, KEY key, MASK mask); +    bool addKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignore);      bool addKeyData(const LLKeyData& data); -    void replaceKeyData(EMouseClickType mouse, KEY key, MASK mask, U32 index); +    void replaceKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignore, U32 index);      void replaceKeyData(const LLKeyData& data, U32 index);      bool hasKeyData(U32 index) const;      void clear() { mData.clear(); }; diff --git a/indra/llui/llscrolllistcell.cpp b/indra/llui/llscrolllistcell.cpp index 63762ab8b8..0a33ee8878 100644 --- a/indra/llui/llscrolllistcell.cpp +++ b/indra/llui/llscrolllistcell.cpp @@ -314,6 +314,11 @@ void LLScrollListText::draw(const LLColor4& color, const LLColor4& highlight_col  				left + mFont->getWidth(mText.getString(), mHighlightOffset, mHighlightCount) + 1,   				1);  		mRoundedRectImage->draw(highlight_rect, highlight_color); +		/*LLRect highlight_rect(left - 2,  +				mFont->getLineHeight() + 2,  +				left + getWidth() + 2,  +				1); +		mRoundedRectImage->draw(highlight_rect, LLColor4::black);*/  	}  	// Try to draw the entire string diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index be90e623ad..0e43af91df 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -829,6 +829,17 @@ bool LLAgent::enableFlying()  	return !sitting;  } +// static +bool LLAgent::isSitting() +{ +    BOOL sitting = FALSE; +    if (isAgentAvatarValid()) +    { +        sitting = gAgentAvatarp->isSitting(); +    } +    return sitting; +} +  void LLAgent::standUp()  {  	setControlFlags(AGENT_CONTROL_STAND_UP); diff --git a/indra/newview/llagent.h b/indra/newview/llagent.h index 5ba1083d8e..a5d37ef496 100644 --- a/indra/newview/llagent.h +++ b/indra/newview/llagent.h @@ -343,6 +343,7 @@ public:  	static void		toggleFlying();  	static bool		enableFlying();  	BOOL			canFly(); 			// Does this parcel allow you to fly? +	static bool		isSitting();  	//--------------------------------------------------------------------  	// Voice diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index d3067456fa..dde7275e8e 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -1451,6 +1451,7 @@ bool LLAppViewer::doFrame()  			{  				joystick->scanJoystick();  				gKeyboard->scanKeyboard(); +                gViewerKeyboard.scanMouse();  			}  			// Update state based on messages, user input, object idle. diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 4a4f66db14..9c706a0d3a 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -166,7 +166,7 @@ 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 CAN_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 @@ -176,6 +176,7 @@ public:  	~LLSetKeyBindDialog();  	/*virtual*/ BOOL postBuild(); +	/*virtual*/ void onClose(bool app_quiting);  	void setParent(LLPanelPreferenceControls* parent, U32 key_mask = DEFAULT_KEY_FILTER); @@ -186,18 +187,23 @@ public:  	static void onDefault(void* user_data);  private: -	LLPanelPreferenceControls* mParent; +	LLPanelPreferenceControls* pParent; +	LLCheckBoxCtrl* pCheckBox;  	U32 mKeyMask;  };  LLSetKeyBindDialog::LLSetKeyBindDialog(const LLSD& key)    : LLModalDialog(key), -	mParent(NULL), +	pParent(NULL),  	mKeyMask(DEFAULT_KEY_FILTER)  {  } +LLSetKeyBindDialog::~LLSetKeyBindDialog() +{ +} +  //virtual  BOOL LLSetKeyBindDialog::postBuild()  { @@ -205,15 +211,24 @@ BOOL LLSetKeyBindDialog::postBuild()  	childSetAction("Default", onDefault, this);  	childSetAction("Cancel", onCancel, this);  	getChild<LLUICtrl>("Cancel")->setFocus(TRUE); -	 + +	pCheckBox = getChild<LLCheckBoxCtrl>("ignore_masks"); +  	gFocusMgr.setKeystrokesOnly(TRUE);  	return TRUE;  } +//virtual +void LLSetKeyBindDialog::onClose(bool app_quiting) +{ +    pParent = NULL; +    LLModalDialog::onClose(app_quiting); +} +  void LLSetKeyBindDialog::setParent(LLPanelPreferenceControls* parent, U32 key_mask)  { -    mParent = parent; +    pParent = parent;      mKeyMask = key_mask;      LLTextBase *text_ctrl = getChild<LLTextBase>("descritption"); @@ -232,10 +247,10 @@ void LLSetKeyBindDialog::setParent(LLPanelPreferenceControls* parent, U32 key_ma          input += getString("keyboard");      }      text_ctrl->setTextArg("[INPUT]", input); -} -LLSetKeyBindDialog::~LLSetKeyBindDialog() -{ +    bool can_ignore_masks = (key_mask & CAN_IGNORE_MASKS) != 0; +    pCheckBox->setVisible(can_ignore_masks); +    pCheckBox->setValue(false);  }  BOOL LLSetKeyBindDialog::handleKeyHere(KEY key, MASK mask) @@ -249,10 +264,19 @@ BOOL LLSetKeyBindDialog::handleKeyHere(KEY key, MASK mask)          return true;      } +    if (key == KEY_DELETE) +    { +        if (pParent) +        { +            pParent->onSetKeyBind(CLICK_NONE, KEY_NONE, MASK_NONE, false); +        } +        closeFloater(); +        return true; +    } +      // forbidden keys      if (key == KEY_NONE          || key == KEY_RETURN -        || key == KEY_DELETE          || key == KEY_BACKSPACE)      {          return false; @@ -275,9 +299,9 @@ BOOL LLSetKeyBindDialog::handleKeyHere(KEY key, MASK mask)          return false;      } -	else if (mParent) +	if (pParent)  	{ -		mParent->onSetKeyBind(CLICK_NONE, key, mask); +        pParent->onSetKeyBind(CLICK_NONE, key, mask, pCheckBox->getValue().asBoolean());  	}  	closeFloater();  	return result; @@ -305,9 +329,9 @@ BOOL LLSetKeyBindDialog::handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClic          && (clicktype != CLICK_RIGHT || mask != 0) // reassigning menu button is not supported          && ((mKeyMask & ALLOW_MASK_MOUSE) != 0 || mask == 0))      { -        if (mParent) +        if (pParent)          { -            mParent->onSetKeyBind(clicktype, KEY_NONE, mask); +            pParent->onSetKeyBind(clicktype, KEY_NONE, mask, pCheckBox->getValue().asBoolean());          }          result = TRUE;          closeFloater(); @@ -333,9 +357,9 @@ void LLSetKeyBindDialog::onBlank(void* user_data)  {      LLSetKeyBindDialog* self = (LLSetKeyBindDialog*)user_data;      // tmp needs 'no key' button -    if (self->mParent) +    if (self->pParent)      { -        self->mParent->onSetKeyBind(CLICK_NONE, KEY_NONE, MASK_NONE); +        self->pParent->onSetKeyBind(CLICK_NONE, KEY_NONE, MASK_NONE, false);      }      self->closeFloater();  } @@ -345,9 +369,9 @@ void LLSetKeyBindDialog::onDefault(void* user_data)  {      LLSetKeyBindDialog* self = (LLSetKeyBindDialog*)user_data;      // tmp needs 'no key' button -    if (self->mParent) +    if (self->pParent)      { -        self->mParent->onDefaultKeyBind(); +        self->pParent->onDefaultKeyBind();      }      self->closeFloater();  } @@ -2972,6 +2996,23 @@ BOOL LLPanelPreferenceControls::postBuild()  // 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)  { +    /*S32 column = pControlsTable->getColumnIndexFromOffset(x); +    LLScrollListItem* item = pControlsTable->hitItem(x, y); +    static LLScrollListCell* last_cell = NULL; +    if (item && column > 0) +    { +        LLScrollListCell* cell = item->getColumn(column); +        if (cell) +        { +            cell->highlightText(0, CHAR_MAX); +            if (last_cell != NULL && last_cell !=cell) +            { +                last_cell->highlightText(0, 0); +            } +            last_cell = cell; +        } +    }*/ +      if (mShowKeyDialog)      {          if (mEditingIndex > 0 && mConflictHandler[mEditingMode].canAssignControl((LLKeyConflictHandler::EControlTypes)mEditingIndex)) @@ -2983,14 +3024,14 @@ BOOL LLPanelPreferenceControls::handleHover(S32 x, S32 y, MASK mask)                  LLSetKeyBindDialog* dialog = LLFloaterReg::showTypedInstance<LLSetKeyBindDialog>("keybind_dialog", LLSD(), TRUE);                  if (dialog)                  { -                    if (mConflictHandler[mEditingMode].getLoadedMode() == LLKeyConflictHandler::MODE_GENERAL) -                    { +                    /*if (mConflictHandler[mEditingMode].getLoadedMode() == LLKeyConflictHandler::MODE_GENERAL) +                    {*/                          dialog->setParent(this, DEFAULT_KEY_FILTER); -                    } +                    /*}                      else                      {                          dialog->setParent(this, ALLOW_KEYS | ALLOW_MASK_KEYS); -                    } +                    }*/                  }              }          } @@ -3133,10 +3174,6 @@ 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) @@ -3226,7 +3263,8 @@ void LLPanelPreferenceControls::onModeCommit()      regenerateControls();  } -void LLPanelPreferenceControls::onSetKeyBind(EMouseClickType click, KEY key, MASK mask) +// todo: copy onSetKeyBind to interface and inherit from interface +void LLPanelPreferenceControls::onSetKeyBind(EMouseClickType click, KEY key, MASK mask, bool ignore_mask)  {      LLKeyConflictHandler::EControlTypes control = (LLKeyConflictHandler::EControlTypes)mEditingIndex; @@ -3241,7 +3279,7 @@ void LLPanelPreferenceControls::onSetKeyBind(EMouseClickType click, KEY key, MAS      if (item && mEditingColumn > 0)      { -        mConflictHandler[mEditingMode].registerControl(control, mEditingColumn - 1, click, key, mask); +        mConflictHandler[mEditingMode].registerControl(control, mEditingColumn - 1, click, key, mask, ignore_mask);          LLScrollListCell *cell = item->getColumn(1);          cell->setValue(mConflictHandler[mEditingMode].getControlString(control, 0)); diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h index bce84387ab..1ac0f076d2 100644 --- a/indra/newview/llfloaterpreference.h +++ b/indra/newview/llfloaterpreference.h @@ -310,7 +310,7 @@ public:  	void onListCommit();  	void onModeCommit(); -	void onSetKeyBind(EMouseClickType click, KEY key, MASK mask); +	void onSetKeyBind(EMouseClickType click, KEY key, MASK mask, bool ignore_mask);  	void onRestoreDefaults();  	void onDefaultKeyBind(); diff --git a/indra/newview/llkeyconflict.cpp b/indra/newview/llkeyconflict.cpp index 0f0129bf68..be0b8fd4ca 100644 --- a/indra/newview/llkeyconflict.cpp +++ b/indra/newview/llkeyconflict.cpp @@ -58,7 +58,6 @@ static const std::string typetostring[LLKeyConflictHandler::CONTROL_NUM_INDICES]      "control_wear",      "control_movements",      "control_moveto", -    "control_sit",      "control_teleportto",      "push_forward",      "push_backward", @@ -69,8 +68,9 @@ static const std::string typetostring[LLKeyConflictHandler::CONTROL_NUM_INDICES]      "jump",      "push_down",      //"control_run", -    "control_toggle_run", +    "toggle_run",      "toggle_fly", +    "toggle_sit",      "stop_moving",      "control_camera",      "look_up", @@ -103,8 +103,8 @@ static const std::string typetostring[LLKeyConflictHandler::CONTROL_NUM_INDICES]      "edit_avatar_move_forward",      "edit_avatar_move_backward",      "control_mediacontent", -    "control_parcel", -    "control_media", +    "toggle_pause_media", +    "toggle_enable_media",      "control_voice",      "control_toggle_voice",      "start_chat", @@ -161,6 +161,10 @@ static const control_enum_t command_to_key =      { "stop_moving", LLKeyConflictHandler::CONTROL_STOP },      { "start_chat", LLKeyConflictHandler::CONTROL_START_CHAT },      { "start_gesture", LLKeyConflictHandler::CONTROL_START_GESTURE }, +    { "toggle_run", LLKeyConflictHandler::CONTROL_TOGGLE_RUN }, +    { "toggle_sit", LLKeyConflictHandler::CONTROL_SIT }, +    { "toggle_parcel_media", LLKeyConflictHandler::CONTROL_PAUSE_MEDIA }, +    { "toggle_enable_media", LLKeyConflictHandler::CONTROL_ENABLE_MEDIA },   }; @@ -191,6 +195,60 @@ std::string string_from_mask(MASK mask)      return res;  } +std::string string_from_mouse(EMouseClickType click) +{ +    std::string res; +    switch (click) +    { +    case CLICK_LEFT: +        res = "LMB"; +        break; +    case CLICK_MIDDLE: +        res = "MMB"; +        break; +    case CLICK_RIGHT: +        res = "RMB"; +        break; +    case CLICK_BUTTON4: +        res = "MB4"; +        break; +    case CLICK_BUTTON5: +        res = "MB5"; +        break; +    case CLICK_DOUBLELEFT: +        res = "Double LMB"; +        break; +    default: +        break; +    } +    return res; +} + +EMouseClickType mouse_from_string(const std::string& input) +{ +    if (input == "LMB") +    { +        return CLICK_LEFT; +    } +    if (input == "MMB") +    { +        return CLICK_MIDDLE; +    } +    if (input == "RMB") +    { +        return CLICK_RIGHT; +    } +    if (input == "MB4") +    { +        return CLICK_BUTTON4; +    } +    if (input == "MB5") +    { +        return CLICK_BUTTON5; +    } +    return CLICK_NONE; +} +  // LLKeyConflictHandler  LLKeyConflictHandler::LLKeyConflictHandler() @@ -245,14 +303,14 @@ bool LLKeyConflictHandler::canAssignControl(EControlTypes control_type)      return false;  } -void LLKeyConflictHandler::registerControl(EControlTypes control_type, U32 index, EMouseClickType mouse, KEY key, MASK mask) +void LLKeyConflictHandler::registerControl(EControlTypes control_type, U32 index, EMouseClickType mouse, KEY key, MASK mask, bool ignore_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); +    type_data.mKeyBind.replaceKeyData(mouse, key, mask, ignore_mask, index);      mHasUnsavedChanges = true;  } @@ -277,45 +335,11 @@ std::string LLKeyConflictHandler::getStringFromKeyData(const LLKeyData& keydata)      }      else if (keydata.mMask != MASK_NONE)      { -        LL_ERRS() << "Masks binding without keys is not supported yet" << LL_ENDL; +        result = LLKeyboard::stringFromAccelerator(keydata.mMask);      } -    #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 +    result += string_from_mouse(keydata.mMouse); -    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;  } @@ -339,6 +363,8 @@ void  LLKeyConflictHandler::loadFromSettings(const LLViewerKeyboard::KeyMode& ke      {          KEY key;          MASK mask; +        EMouseClickType mouse = it->mouse.isProvided() ? mouse_from_string(it->mouse) : CLICK_NONE; +        bool ignore = it->ignore.isProvided() ? it->ignore.getValue() : false;          if (it->key.getValue().empty())          {              key = KEY_NONE; @@ -358,7 +384,7 @@ void  LLKeyConflictHandler::loadFromSettings(const LLViewerKeyboard::KeyMode& ke              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); +            type_data.mKeyBind.addKeyData(mouse, key, mask, ignore);          }      }  } @@ -418,6 +444,10 @@ void  LLKeyConflictHandler::loadFromSettings(EModes load_mode)  {      mControlsMap.clear();      mDefaultsMap.clear(); + +    // E.X. In case we need placeholder keys for conflict resolution. +    generatePlaceholders(load_mode); +      if (load_mode == MODE_GENERAL)      {          for (U32 i = 0; i < CONTROL_NUM_INDICES; i++) @@ -463,12 +493,11 @@ void  LLKeyConflictHandler::loadFromSettings(EModes load_mode)          }          else          { -            mControlsMap = mDefaultsMap; +            // mind placeholders +            mControlsMap.insert(mDefaultsMap.begin(), mDefaultsMap.end());          }      }      mLoadedMode = load_mode; - -    generatePlaceholders();  }  void  LLKeyConflictHandler::saveToSettings() @@ -555,6 +584,8 @@ void  LLKeyConflictHandler::saveToSettings()                          binding.key = LLKeyboard::stringFromKey(data.mKey);                      }                      binding.mask = string_from_mask(data.mMask); +                    binding.mouse.set(string_from_mouse(data.mMouse), true); //set() because 'optional', for compatibility purposes +                    binding.ignore.set(data.mIgnoreMasks, true);                      binding.command = getControlName(iter->first);                      mode.bindings.add(binding);                  } @@ -711,8 +742,8 @@ void LLKeyConflictHandler::resetToDefaults(EModes mode)      else      {          mControlsMap.clear(); -        mControlsMap = mDefaultsMap; -        generatePlaceholders(); +        generatePlaceholders(mode); +        mControlsMap.insert(mDefaultsMap.begin(), mDefaultsMap.end());      }      mHasUnsavedChanges = true; @@ -774,7 +805,7 @@ void LLKeyConflictHandler::resetKeyboardBindings()      gViewerKeyboard.loadBindingsXML(filename);  } -void LLKeyConflictHandler::generatePlaceholders() +void LLKeyConflictHandler::generatePlaceholders(EModes load_mode)  {  } @@ -784,6 +815,6 @@ void LLKeyConflictHandler::registerTemporaryControl(EControlTypes control_type,      LLKeyConflict *type_data = &mControlsMap[control_type];      type_data->mAssignable = false;      type_data->mConflictMask = conflict_mask; -    type_data->mKeyBind.addKeyData(mouse, key, mask); +    type_data->mKeyBind.addKeyData(mouse, key, mask, false);  } diff --git a/indra/newview/llkeyconflict.h b/indra/newview/llkeyconflict.h index 79bd9b8438..7890be1e28 100644 --- a/indra/newview/llkeyconflict.h +++ b/indra/newview/llkeyconflict.h @@ -95,7 +95,6 @@ public:          CONTROL_WEAR,          CONTROL_MOVEMENTS, // Group control, for visual representation          CONTROL_MOVETO, -        CONTROL_SIT,          CONTROL_TELEPORTTO,          CONTROL_FORWARD,          CONTROL_BACKWARD, @@ -108,6 +107,7 @@ public:          //CONTROL_RUN,          CONTROL_TOGGLE_RUN,          CONTROL_TOGGLE_FLY, +        CONTROL_SIT,          CONTROL_STOP,          CONTROL_CAMERA, // Group control, for visual representation          CONTROL_LOOK_UP, @@ -140,8 +140,8 @@ public:          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_PAUSE_MEDIA, // Play pause +        CONTROL_ENABLE_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 @@ -165,7 +165,7 @@ public:      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? +    void registerControl(EControlTypes control_type, U32 data_index, EMouseClickType mouse_ind, KEY key, MASK mask, bool ignore_mask); //todo: return conflicts?      LLKeyData getControl(EControlTypes control_type, U32 data_index); @@ -202,7 +202,7 @@ private:      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 +    void generatePlaceholders(EModes load_mode); //E.x. non-assignable values      control_map_t mControlsMap;      control_map_t mDefaultsMap; diff --git a/indra/newview/llviewerkeyboard.cpp b/indra/newview/llviewerkeyboard.cpp index 878810e0dd..f1a2b037e2 100644 --- a/indra/newview/llviewerkeyboard.cpp +++ b/indra/newview/llviewerkeyboard.cpp @@ -603,12 +603,50 @@ void start_gesture( EKeystate s )  	}  } -void toggle_parcel_media(EKeystate s) +void toggle_run(EKeystate s)  { +    if (KEYSTATE_DOWN != s) return; +    bool run = gAgent.getAlwaysRun(); +    if (run) +    { +        gAgent.clearAlwaysRun(); +        gAgent.clearRunning(); +    } +    else +    { +        gAgent.setAlwaysRun(); +        gAgent.setRunning(); +    } +    gAgent.sendWalkRun(!run); +} + +void toggle_sit(EKeystate s) +{ +    if (KEYSTATE_DOWN != s) return; +    if (gAgent.isSitting()) +    { +        gAgent.standUp(); +    } +    else +    { +        gAgent.sitDown(); +    } +} + +void toggle_pause_media(EKeystate s) // analogue of play/pause button in top bar +{ +    if (KEYSTATE_DOWN != s) return;      bool pause = LLViewerMedia::isAnyMediaPlaying();      LLViewerMedia::setAllMediaPaused(pause);  } +void toggle_enable_media(EKeystate s) +{ +    if (KEYSTATE_DOWN != s) return; +    bool pause = LLViewerMedia::isAnyMediaPlaying() || LLViewerMedia::isAnyMediaShowing(); +    LLViewerMedia::setAllMediaEnabled(!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); @@ -650,20 +688,24 @@ 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); +REGISTER_KEYBOARD_ACTION("toggle_run", toggle_run); +REGISTER_KEYBOARD_ACTION("toggle_sit", toggle_sit); +REGISTER_KEYBOARD_ACTION("toggle_pause_media", toggle_pause_media); +REGISTER_KEYBOARD_ACTION("toggle_enable_media", toggle_enable_media);  #undef REGISTER_KEYBOARD_ACTION  LLViewerKeyboard::LLViewerKeyboard()  { -	for (S32 i = 0; i < MODE_COUNT; i++) -	{ -		mBindingCount[i] = 0; -	} +    resetBindings();  	for (S32 i = 0; i < KEY_COUNT; i++)  	{  		mKeyHandledByUI[i] = FALSE; -	} +    } +    for (S32 i = 0; i < CLICK_COUNT; i++) +    { +        mMouseLevel[i] = MOUSE_STATE_SILENT; +    }  	// we want the UI to never see these keys so that they can always control the avatar/camera  	for(KEY k = KEY_PAD_UP; k <= KEY_PAD_DIVIDE; k++)   	{ @@ -671,7 +713,7 @@ LLViewerKeyboard::LLViewerKeyboard()  	}  } -BOOL LLViewerKeyboard::modeFromString(const std::string& string, S32 *mode) +BOOL LLViewerKeyboard::modeFromString(const std::string& string, S32 *mode) const  {  	if (string == "FIRST_PERSON")  	{ @@ -705,6 +747,40 @@ BOOL LLViewerKeyboard::modeFromString(const std::string& string, S32 *mode)  	}  } +BOOL LLViewerKeyboard::mouseFromString(const std::string& string, EMouseClickType *mode) const +{ +    if (string == "LMB") +    { +        *mode = CLICK_LEFT; +        return TRUE; +    } +    else if (string == "DLMB") +    { +        *mode = CLICK_DOUBLELEFT; +        return TRUE; +    } +    else if (string == "MMB") +    { +        *mode = CLICK_MIDDLE; +        return TRUE; +    } +    else if (string == "MB4") +    { +        *mode = CLICK_BUTTON4; +        return TRUE; +    } +    else if (string == "MB5") +    { +        *mode = CLICK_BUTTON5; +        return TRUE; +    } +    else +    { +        *mode = CLICK_NONE; +        return FALSE; +    } +} +  BOOL LLViewerKeyboard::handleKey(KEY translated_key,  MASK translated_mask, BOOL repeated)  {  	// check for re-map @@ -748,7 +824,7 @@ BOOL LLViewerKeyboard::handleKeyUp(KEY translated_key, MASK translated_mask)  	return gViewerWindow->handleKeyUp(translated_key, translated_mask);  } -BOOL LLViewerKeyboard::bindKey(const S32 mode, const KEY key, const MASK mask, const std::string& function_name) +BOOL LLViewerKeyboard::bindKey(const S32 mode, const KEY key, const MASK mask, const bool ignore, const std::string& function_name)  {  	S32 index;  	typedef boost::function<void(EKeystate)> function_t; @@ -789,11 +865,22 @@ BOOL LLViewerKeyboard::bindKey(const S32 mode, const KEY key, const MASK mask, c  	}  	// check for duplicate first and overwrite -	for (index = 0; index < mBindingCount[mode]; index++) -	{ -		if (key == mBindings[mode][index].mKey && mask == mBindings[mode][index].mMask) -			break; -	} +    if (ignore) +    { +        for (index = 0; index < mKeyIgnoreMaskCount[mode]; index++) +        { +            if (key == mKeyIgnoreMask[mode][index].mKey) +                break; +        } +    } +    else +    { +        for (index = 0; index < mKeyBindingCount[mode]; index++) +        { +            if (key == mKeyBindings[mode][index].mKey && mask == mKeyBindings[mode][index].mMask) +                break; +        } +    }  	if (index >= MAX_KEY_BINDINGS)  	{ @@ -807,20 +894,102 @@ BOOL LLViewerKeyboard::bindKey(const S32 mode, const KEY key, const MASK mask, c  		return FALSE;  	} -	mBindings[mode][index].mKey = key; -	mBindings[mode][index].mMask = mask; -	mBindings[mode][index].mFunction = function; +    if (ignore) +    { +        mKeyIgnoreMask[mode][index].mKey = key; +        mKeyIgnoreMask[mode][index].mFunction = function; + +        if (index == mKeyIgnoreMaskCount[mode]) +            mKeyIgnoreMaskCount[mode]++; +    } +    else +    { +        mKeyBindings[mode][index].mKey = key; +        mKeyBindings[mode][index].mMask = mask; +        mKeyBindings[mode][index].mFunction = function; -	if (index == mBindingCount[mode]) -        mBindingCount[mode]++; +        if (index == mKeyBindingCount[mode]) +            mKeyBindingCount[mode]++; +    }  	return TRUE;  } +BOOL LLViewerKeyboard::bindMouse(const S32 mode, const EMouseClickType mouse, const MASK mask, const bool ignore, const std::string& function_name) +{ +    S32 index; +    typedef boost::function<void(EKeystate)> function_t; +    function_t function = NULL; + +    function_t* result = LLKeyboardActionRegistry::getValue(function_name); +    if (result) +    { +        function = *result; +    } + +    if (!function) +    { +        LL_ERRS() << "Can't bind key to function " << function_name << ", no function with this name found" << LL_ENDL; +        return FALSE; +    } + +    // check for duplicate first and overwrite +    if (ignore) +    { +        for (index = 0; index < mMouseIgnoreMaskCount[mode]; index++) +        { +            if (mouse == mMouseIgnoreMask[mode][index].mMouse) +                break; +        } +    } +    else +    { +        for (index = 0; index < mMouseBindingCount[mode]; index++) +        { +            if (mouse == mMouseBindings[mode][index].mMouse && mask == mMouseBindings[mode][index].mMask) +                break; +        } +    } + +    if (index >= MAX_KEY_BINDINGS) +    { +        LL_ERRS() << "LLKeyboard::bindKey() - too many keys for mode " << mode << LL_ENDL; +        return FALSE; +    } + +    if (mode >= MODE_COUNT) +    { +        LL_ERRS() << "LLKeyboard::bindKey() - unknown mode passed" << mode << LL_ENDL; +        return FALSE; +    } + +    if (ignore) +    { +        mMouseIgnoreMask[mode][index].mMouse = mouse; +        mMouseIgnoreMask[mode][index].mFunction = function; + +        if (index == mMouseIgnoreMaskCount[mode]) +            mMouseIgnoreMaskCount[mode]++; +    } +    else +    { +        mMouseBindings[mode][index].mMouse = mouse; +        mMouseBindings[mode][index].mMask = mask; +        mMouseBindings[mode][index].mFunction = function; + +        if (index == mMouseBindingCount[mode]) +            mMouseBindingCount[mode]++; +    } + +    return TRUE; +} +  LLViewerKeyboard::KeyBinding::KeyBinding()  :	key("key"), +	mouse("mouse"),  	mask("mask"), -	command("command") +	command("command"), +	ignore("ignore", false)  {}  LLViewerKeyboard::KeyMode::KeyMode() @@ -835,12 +1004,20 @@ LLViewerKeyboard::Keys::Keys()  	edit_avatar("edit_avatar")  {} +void LLViewerKeyboard::resetBindings() +{ +    for (S32 i = 0; i < MODE_COUNT; i++) +    { +        mKeyBindingCount[i] = 0; +        mKeyIgnoreMaskCount[i] = 0; +        mMouseBindingCount[i] = 0; +        mMouseIgnoreMaskCount[i] = 0; +    } +} +  S32 LLViewerKeyboard::loadBindingsXML(const std::string& filename)  { -	for (S32 i = 0; i < MODE_COUNT; i++) -	{ -		mBindingCount[i] = 0; -	} +    resetBindings();  	S32 binding_count = 0;  	Keys keys; @@ -870,9 +1047,20 @@ S32 LLViewerKeyboard::loadBindingMode(const LLViewerKeyboard::KeyMode& keymode,          {              KEY key;              MASK mask; +            bool ignore = it->ignore.isProvided() ? it->ignore.getValue() : false;              LLKeyboard::keyFromString(it->key, &key);              LLKeyboard::maskFromString(it->mask, &mask); -            bindKey(mode, key, mask, it->command); +            bindKey(mode, key, mask, ignore, it->command); +            binding_count++; +        } +        else if (it->mouse.isProvided() && !it->mouse.getValue().empty()) +        { +            EMouseClickType mouse; +            MASK mask; +            bool ignore = it->ignore.isProvided() ? it->ignore.getValue() : false; +            mouseFromString(it->mouse.getValue(), &mouse); +            LLKeyboard::maskFromString(it->mask, &mask); +            bindMouse(mode, mouse, mask, ignore, it->command);              binding_count++;          }  	} @@ -964,7 +1152,7 @@ S32 LLViewerKeyboard::loadBindings(const std::string& filename)  		}  		// bind key -		if (bindKey(mode, key, mask, function_string)) +		if (bindKey(mode, key, mask, false, function_string))  		{  			binding_count++;  		} @@ -976,7 +1164,7 @@ S32 LLViewerKeyboard::loadBindings(const std::string& filename)  } -EKeyboardMode LLViewerKeyboard::getMode() +EKeyboardMode LLViewerKeyboard::getMode() const  {  	if ( gAgentCamera.cameraMouselook() )  	{ @@ -996,56 +1184,184 @@ EKeyboardMode LLViewerKeyboard::getMode()  	}  } - -// Called from scanKeyboard. -void LLViewerKeyboard::scanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level) +bool LLViewerKeyboard::scanKey(const LLKeyboardBinding* binding, +                               S32 binding_count, +                               KEY key, +                               MASK mask, +                               BOOL key_down, +                               BOOL key_up, +                               BOOL key_level, +                               bool repeat) const  { -	if (LLApp::isExiting()) -	{ -		return; -	} - -	S32 mode = getMode(); -	// Consider keyboard scanning as NOT mouse event. JC -	MASK mask = gKeyboard->currentMask(FALSE); - -	LLKeyBinding* binding = mBindings[mode]; -	S32 binding_count = mBindingCount[mode]; - - -	if (mKeyHandledByUI[key]) -	{ -		return; -	} - -	// don't process key down on repeated keys -	BOOL repeat = gKeyboard->getKeyRepeated(key); -  	for (S32 i = 0; i < binding_count; i++)  	{ -		//for (S32 key = 0; key < KEY_COUNT; key++)  		if (binding[i].mKey == key)  		{ -			//if (binding[i].mKey == key && binding[i].mMask == mask)  			if (binding[i].mMask == mask)  			{  				if (key_down && !repeat)  				{  					// ...key went down this frame, call function  					binding[i].mFunction( KEYSTATE_DOWN ); +					return true;  				}  				else if (key_up)  				{  					// ...key went down this frame, call function  					binding[i].mFunction( KEYSTATE_UP ); +					return true;  				}  				else if (key_level)  				{  					// ...key held down from previous frame  					// Not windows, just call the function.  					binding[i].mFunction( KEYSTATE_LEVEL ); +					return true;  				}//if +				// Key+Mask combinations are supposed to be unique, so we won't find anything else +				return false;  			}//if -		}//for +		}//if  	}//for +	return false; +} + +// Called from scanKeyboard. +void LLViewerKeyboard::scanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level) const +{ +	if (LLApp::isExiting()) +	{ +		return; +	} + +	S32 mode = getMode(); +	// Consider keyboard scanning as NOT mouse event. JC +	MASK mask = gKeyboard->currentMask(FALSE); + +	if (mKeyHandledByUI[key]) +	{ +		return; +	} + +	// don't process key down on repeated keys +	BOOL repeat = gKeyboard->getKeyRepeated(key); + +    if (scanKey(mKeyBindings[mode], mKeyBindingCount[mode], key, mask, key_down, key_up, key_level, repeat)) +    { +        // Nothing found, try ignore list +        scanKey(mKeyIgnoreMask[mode], mKeyIgnoreMaskCount[mode], key, MASK_NONE, key_down, key_up, key_level, repeat); +    } +} + +BOOL LLViewerKeyboard::handleMouse(LLWindow *window_impl, LLCoordGL pos, MASK mask, EMouseClickType clicktype, BOOL down) +{ +    BOOL handled = gViewerWindow->handleAnyMouseClick(window_impl, pos, mask, clicktype, down); + +    if (clicktype != CLICK_NONE) +    { +        // special case +        // if UI doesn't handle double click, LMB click is issued, so supres LMB 'down' when doubleclick is set +        // handle !down as if we are handling doubleclick +        bool override_lmb = (clicktype == CLICK_LEFT +            && (mMouseLevel[CLICK_DOUBLELEFT] == MOUSE_STATE_DOWN || mMouseLevel[CLICK_DOUBLELEFT] == MOUSE_STATE_LEVEL)); + +        if (override_lmb && !down) +        { +            // process doubleclick instead +            clicktype = CLICK_DOUBLELEFT; +        } + +        if (override_lmb && down) +        { +            // else-supress +        } +        // if UI handled 'down', it should handle 'up' as well +        // if we handle 'down' not by UI, then we should handle 'up'/'level' regardless of UI +        else if (handled && mMouseLevel[clicktype] != MOUSE_STATE_SILENT) +        { +            // UI handled new 'down' so iterupt whatever state we were in. +            mMouseLevel[clicktype] = MOUSE_STATE_UP; +        } +        else if (down) +        { +            if (mMouseLevel[clicktype] == MOUSE_STATE_DOWN) +            { +                // this is repeated hit (mouse does not repeat event until release) +                // for now treat rapid clicking like mouse being held +                mMouseLevel[clicktype] = MOUSE_STATE_LEVEL; +            } +            else +            { +                mMouseLevel[clicktype] = MOUSE_STATE_DOWN; +            } +        } +        else +        { +            // Released mouse key +            mMouseLevel[clicktype] = MOUSE_STATE_UP; +        } +    } + +    return handled; +} + +bool LLViewerKeyboard::scanMouse(const LLMouseBinding *binding, S32 binding_count, EMouseClickType mouse, MASK mask, EMouseState state) const +{ +    for (S32 i = 0; i < binding_count; i++) +    { +        if (binding[i].mMouse == mouse && binding[i].mMask == mask) +        { +            switch (state) +            { +            case MOUSE_STATE_DOWN: +                binding[i].mFunction(KEYSTATE_DOWN); +                break; +            case MOUSE_STATE_LEVEL: +                binding[i].mFunction(KEYSTATE_LEVEL); +                break; +            case MOUSE_STATE_UP: +                binding[i].mFunction(KEYSTATE_UP); +                break; +            default: +                break; +            } +            // Key+Mask combinations are supposed to be unique, no need to continue +            return true; +        } +    } +    return false; +} + +// todo: this recods key, scanMouse() triggers functions with EKeystate +bool LLViewerKeyboard::scanMouse(EMouseClickType click, EMouseState state) const +{ +    bool res = false; +    S32 mode = getMode(); +    MASK mask = gKeyboard->currentMask(TRUE); +    res = scanMouse(mMouseBindings[mode], mMouseBindingCount[mode], click, mask, state); +    if (!res) +    { +        res = scanMouse(mMouseIgnoreMask[mode], mMouseIgnoreMaskCount[mode], click, MASK_NONE, state); +    } +    return res; +} + +void LLViewerKeyboard::scanMouse() +{ +    for (S32 i = 0; i < CLICK_COUNT; i++) +    { +        if (mMouseLevel[i] != MOUSE_STATE_SILENT) +        { +            scanMouse((EMouseClickType)i, mMouseLevel[i]); +            if (mMouseLevel[i] == MOUSE_STATE_DOWN) +            { +                // mouse doesn't support 'continued' state like keyboard does, so after handling, switch to LEVEL +                mMouseLevel[i] = MOUSE_STATE_LEVEL; +            } +            else if (mMouseLevel[i] == MOUSE_STATE_UP) +            { +                mMouseLevel[i] = MOUSE_STATE_SILENT; +            } +        } +    }  } diff --git a/indra/newview/llviewerkeyboard.h b/indra/newview/llviewerkeyboard.h index 2bfe285be4..3ba033509c 100644 --- a/indra/newview/llviewerkeyboard.h +++ b/indra/newview/llviewerkeyboard.h @@ -43,6 +43,27 @@ public:  	LLKeyFunc	mFunction;  }; +class LLKeyboardBinding +{ +public: +    KEY				mKey; +    MASK			mMask; +    bool			mIgnoreMask; // whether CTRL/ALT/SHIFT should be checked + +    LLKeyFunc		mFunction; +}; + +class LLMouseBinding +{ +public: +    EMouseClickType	mMouse; +    MASK			mMask; +    bool			mIgnoreMask; // whether CTRL/ALT/SHIFT should be checked + +    LLKeyFunc		mFunction; +}; + +  typedef enum e_keyboard_mode  {  	MODE_FIRST_PERSON, @@ -53,6 +74,7 @@ typedef enum e_keyboard_mode  	MODE_COUNT  } EKeyboardMode; +class LLWindow;  void bind_keyboard_functions(); @@ -64,6 +86,8 @@ public:  		Mandatory<std::string>	key,  								mask,  								command; +		Optional<std::string>	mouse; // Note, not mandatory for the sake of backward campatibility +		Optional<bool>			ignore;  		KeyBinding();  	}; @@ -93,24 +117,68 @@ public:  	S32				loadBindings(const std::string& filename);										// returns number bound, 0 on error  	S32				loadBindingsXML(const std::string& filename);										// returns number bound, 0 on error -	EKeyboardMode	getMode(); +	EKeyboardMode	getMode() const; + +	BOOL			modeFromString(const std::string& string, S32 *mode) const;			// False on failure +	BOOL			mouseFromString(const std::string& string, EMouseClickType *mode) const;// False on failure -	BOOL			modeFromString(const std::string& string, S32 *mode);			// False on failure +    void			scanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level) const; -	void			scanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level); +    // handleMouse() records state, scanMouse() goes through states, scanMouse(click) processes individual saved states after UI is done with them +    BOOL			handleMouse(LLWindow *window_impl, LLCoordGL pos, MASK mask, EMouseClickType clicktype, BOOL down); +	void LLViewerKeyboard::scanMouse();  private: -	S32				loadBindingMode(const LLViewerKeyboard::KeyMode& keymode, S32 mode); -	BOOL			bindKey(const S32 mode, const KEY key, const MASK mask, const std::string& function_name); +    bool            scanKey(const LLKeyboardBinding* binding, +                            S32 binding_count, +                            KEY key, +                            MASK mask, +                            BOOL key_down, +                            BOOL key_up, +                            BOOL key_level, +                            bool repeat) const; + +    enum EMouseState +    { +        MOUSE_STATE_DOWN, // key down this frame +        MOUSE_STATE_LEVEL, // clicked again fast, or never released +        MOUSE_STATE_UP, // went up this frame +        MOUSE_STATE_SILENT // notified about 'up', do not notify again +    }; +    bool			scanMouse(EMouseClickType click, EMouseState state) const; +    bool            scanMouse(const LLMouseBinding *binding, +                          S32 binding_count, +                          EMouseClickType mouse, +                          MASK mask, +                          EMouseState state) const; + +    S32				loadBindingMode(const LLViewerKeyboard::KeyMode& keymode, S32 mode); +    BOOL			bindKey(const S32 mode, const KEY key, const MASK mask, const bool ignore, const std::string& function_name); +    BOOL			bindMouse(const S32 mode, const EMouseClickType mouse, const MASK mask, const bool ignore, const std::string& function_name); +    void			resetBindings();  	// Hold all the ugly stuff torn out to make LLKeyboard non-viewer-specific here -	S32				mBindingCount[MODE_COUNT]; -	LLKeyBinding	mBindings[MODE_COUNT][MAX_KEY_BINDINGS]; +    // We process specific keys first, then keys that should ignore mask. +    // This way with W+ignore defined to 'forward' and with ctrl+W tied to camera, +    // pressing undefined Shift+W will do 'forward', yet ctrl+W will do 'camera forward' +    // With A defined to 'turn', shift+A defined to strafe, pressing Shift+W+A will do strafe+forward +    S32				mKeyBindingCount[MODE_COUNT]; +    S32				mKeyIgnoreMaskCount[MODE_COUNT]; +    S32				mMouseBindingCount[MODE_COUNT]; +    S32				mMouseIgnoreMaskCount[MODE_COUNT]; +    LLKeyboardBinding	mKeyBindings[MODE_COUNT][MAX_KEY_BINDINGS]; +    LLKeyboardBinding	mKeyIgnoreMask[MODE_COUNT][MAX_KEY_BINDINGS]; +    LLMouseBinding		mMouseBindings[MODE_COUNT][MAX_KEY_BINDINGS]; +    LLMouseBinding		mMouseIgnoreMask[MODE_COUNT][MAX_KEY_BINDINGS];  	typedef std::map<U32, U32> key_remap_t;  	key_remap_t		mRemapKeys[MODE_COUNT];  	std::set<KEY>	mKeysSkippedByUI;  	BOOL			mKeyHandledByUI[KEY_COUNT];		// key processed successfully by UI + +    // This is indentical to what llkeyboard does (mKeyRepeated, mKeyLevel, mKeyDown e t c), +    // just instead of remembering individually as bools,  we record state as enum +    EMouseState		mMouseLevel[CLICK_COUNT];	// records of key state  };  extern LLViewerKeyboard gViewerKeyboard; diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 2c58295814..bd5370f07f 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -898,6 +898,17 @@ LLViewerWindow::Params::Params()  {} +void LLViewerWindow::handlePieMenu(S32 x, S32 y, MASK mask) +{ +    if (CAMERA_MODE_CUSTOMIZE_AVATAR != gAgentCamera.getCameraMode() && LLToolMgr::getInstance()->getCurrentTool() != LLToolPie::getInstance() && gAgent.isInitialized()) +    { +        // If the current tool didn't process the click, we should show +        // the pie menu.  This can be done by passing the event to the pie +        // menu tool. +        LLToolPie::getInstance()->handleRightMouseDown(x, y, mask); +    } +} +  BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK mask, EMouseClickType clicktype, BOOL down)  {  	const char* buttonname = ""; @@ -996,6 +1007,11 @@ BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK m  				LLViewerEventRecorder::instance().logMouseEvent(std::string(buttonstatestr),std::string(buttonname));   			} +			else if (down && clicktype == CLICK_RIGHT) +			{ +				handlePieMenu(x, y, mask); +				r = TRUE; +			}  			return r;  		} @@ -1042,7 +1058,12 @@ BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK m  		return TRUE;  	} -	 +	if (down && clicktype == CLICK_RIGHT) +	{ +		handlePieMenu(x, y, mask); +		return TRUE; +	} +  	// If we got this far on a down-click, it wasn't handled.  	// Up-clicks, though, are always handled as far as the OS is concerned.  	BOOL default_rtn = !down; @@ -1061,7 +1082,8 @@ BOOL LLViewerWindow::handleMouseDown(LLWindow *window,  LLCoordGL pos, MASK mask          mMouseDownTimer.reset();      }          BOOL down = TRUE; -	return handleAnyMouseClick(window, pos, mask, CLICK_LEFT, down); +    //handleMouse() loops back to LLViewerWindow::handleAnyMouseClick +    return gViewerKeyboard.handleMouse(window, pos, mask, CLICK_LEFT, down);  }  BOOL LLViewerWindow::handleDoubleClick(LLWindow *window,  LLCoordGL pos, MASK mask) @@ -1069,7 +1091,7 @@ BOOL LLViewerWindow::handleDoubleClick(LLWindow *window,  LLCoordGL pos, MASK ma  	// try handling as a double-click first, then a single-click if that  	// wasn't handled.  	BOOL down = TRUE; -	if (handleAnyMouseClick(window, pos, mask, CLICK_DOUBLELEFT, down)) +	if (gViewerKeyboard.handleMouse(window, pos, mask, CLICK_DOUBLELEFT, down))  	{  		return TRUE;  	} @@ -1083,46 +1105,24 @@ BOOL LLViewerWindow::handleMouseUp(LLWindow *window,  LLCoordGL pos, MASK mask)          mMouseDownTimer.stop();      }      BOOL down = FALSE; -	return handleAnyMouseClick(window, pos, mask, CLICK_LEFT, down); +    return gViewerKeyboard.handleMouse(window, pos, mask, CLICK_LEFT, down);  } - -  BOOL LLViewerWindow::handleRightMouseDown(LLWindow *window,  LLCoordGL pos, MASK mask)  { -	S32 x = pos.mX; -	S32 y = pos.mY; -	x = ll_round((F32)x / mDisplayScale.mV[VX]); -	y = ll_round((F32)y / mDisplayScale.mV[VY]); -  	BOOL down = TRUE; -	BOOL handle = handleAnyMouseClick(window, pos, mask, CLICK_RIGHT, down); -	if (handle) -		return handle; - -	// *HACK: this should be rolled into the composite tool logic, not -	// hardcoded at the top level. -	if (CAMERA_MODE_CUSTOMIZE_AVATAR != gAgentCamera.getCameraMode() && LLToolMgr::getInstance()->getCurrentTool() != LLToolPie::getInstance() && gAgent.isInitialized()) -	{ -		// If the current tool didn't process the click, we should show -		// the pie menu.  This can be done by passing the event to the pie -		// menu tool. -		LLToolPie::getInstance()->handleRightMouseDown(x, y, mask); -		// show_context_menu( x, y, mask ); -	} - -	return TRUE; +	return gViewerKeyboard.handleMouse(window, pos, mask, CLICK_RIGHT, down);  }  BOOL LLViewerWindow::handleRightMouseUp(LLWindow *window,  LLCoordGL pos, MASK mask)  {  	BOOL down = FALSE; - 	return handleAnyMouseClick(window, pos, mask, CLICK_RIGHT, down); + 	return gViewerKeyboard.handleMouse(window, pos, mask, CLICK_RIGHT, down);  }  BOOL LLViewerWindow::handleMiddleMouseDown(LLWindow *window,  LLCoordGL pos, MASK mask)  {  	BOOL down = TRUE; - 	handleAnyMouseClick(window, pos, mask, CLICK_MIDDLE, down); + 	gViewerKeyboard.handleMouse(window, pos, mask, CLICK_MIDDLE, down);    	// Always handled as far as the OS is concerned.  	return TRUE; @@ -1277,7 +1277,7 @@ LLWindowCallbacks::DragNDropResult LLViewerWindow::handleDragNDrop( LLWindow *wi  BOOL LLViewerWindow::handleMiddleMouseUp(LLWindow *window,  LLCoordGL pos, MASK mask)  {  	BOOL down = FALSE; - 	handleAnyMouseClick(window, pos, mask, CLICK_MIDDLE, down); + 	gViewerKeyboard.handleMouse(window, pos, mask, CLICK_MIDDLE, down);    	// Always handled as far as the OS is concerned.  	return TRUE; @@ -1288,10 +1288,10 @@ BOOL LLViewerWindow::handleOtherMouse(LLWindow *window, LLCoordGL pos, MASK mask      switch (button)      {      case 4: -        handleAnyMouseClick(window, pos, mask, CLICK_BUTTON4, down); +        gViewerKeyboard.handleMouse(window, pos, mask, CLICK_BUTTON4, down);          break;      case 5: -        handleAnyMouseClick(window, pos, mask, CLICK_BUTTON5, down); +        gViewerKeyboard.handleMouse(window, pos, mask, CLICK_BUTTON5, down);          break;      default:          break; @@ -1458,7 +1458,8 @@ BOOL LLViewerWindow::handleTranslatedKeyDown(KEY key,  MASK mask, BOOL repeated)      		return FALSE;  	} -	return gViewerKeyboard.handleKey(key, mask, repeated); +    // remaps, handles ignored cases and returns back to viewer window. +    return gViewerKeyboard.handleKey(key, mask, repeated);  }  BOOL LLViewerWindow::handleTranslatedKeyUp(KEY key,  MASK mask) @@ -2936,6 +2937,7 @@ BOOL LLViewerWindow::handleUnicodeChar(llwchar uni_char, MASK mask)  	{  		if (mask != MASK_ALT)  		{ +			// remaps, handles ignored cases and returns back to viewer window.  			return gViewerKeyboard.handleKey(KEY_RETURN, mask, gKeyboard->getKeyRepeated(KEY_RETURN));  		}  	} diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h index 5f03685cee..a6365ab328 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -175,8 +175,9 @@ public:  	void			initWorldUI();  	void			setUIVisibility(bool);  	bool			getUIVisibility(); +	void			handlePieMenu(S32 x, S32 y, MASK mask); -	BOOL handleAnyMouseClick(LLWindow *window,  LLCoordGL pos, MASK mask, EMouseClickType clicktype, BOOL down); +	BOOL handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK mask, EMouseClickType clicktype, BOOL down);  	//  	// LLWindowCallback interface implementation diff --git a/indra/newview/skins/default/xui/en/floater_select_key.xml b/indra/newview/skins/default/xui/en/floater_select_key.xml index c00b805954..32f091938e 100644 --- a/indra/newview/skins/default/xui/en/floater_select_key.xml +++ b/indra/newview/skins/default/xui/en/floater_select_key.xml @@ -4,7 +4,7 @@   border="false"   can_close="false"   can_minimize="false" - height="90" + height="116"   layout="topleft"   name="modal container"   width="272"> @@ -31,13 +31,25 @@  Press a key to set your trigger.  Allowed input: [INPUT].      </text> +    <check_box +     follows="top|left" +     height="20" +     initial_value="false" +     label="Ignore accelerator keys" +     layout="topleft" +     left="8" +     name="ignore_masks" +     tool_tip="Ignore Shift, Alt and Ctrl keys. Example: This allows to hold W (forward, ignores shift) and Shift+A (slide left) simultaneously and agent will both move forward and slide left." +     top_pad="8" +     width="160" /> +        <button       height="23"       label="Set Empty"       layout="topleft"       left="8"       name="SetEmpty" -     top_pad="8" +     top_pad="6"       width="80" />      <button       height="23" diff --git a/indra/newview/skins/default/xui/en/panel_preferences_controls.xml b/indra/newview/skins/default/xui/en/panel_preferences_controls.xml index 1bfee20c81..0c652845f0 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_controls.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_controls.xml @@ -74,7 +74,7 @@      Move To    </panel.string>    <panel.string -   name="control_sit"> +   name="toggle_sit">      Sit/Stand    </panel.string>    <panel.string @@ -119,7 +119,7 @@      Run    </panel.string>    <panel.string -   name="control_toggle_run"> +   name="toggle_run">      Toggle Run    </panel.string>    <panel.string @@ -207,11 +207,11 @@      Sound and Media    </panel.string>    <panel.string -   name="control_parcel"> -    Play/Pause Parcel Media +   name="toggle_pause_media"> +    Play/Pause Media    </panel.string>    <panel.string -   name="control_media"> +   name="toggle_enable_media">      Play/Stop All Media    </panel.string>    <panel.string | 
