summaryrefslogtreecommitdiff
path: root/indra/newview/llkeyconflict.h
blob: 6c01ddb7a799fa3290e0a9ed6592611353929850 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
/**
 * @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 "llviewerinput.h"


class LLKeyConflict
{
public:
    LLKeyConflict() : mAssignable(true), mConflictMask(U32_MAX) {} //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 ESourceMode // partially repeats e_keyboard_mode
    {
        MODE_FIRST_PERSON,
        MODE_THIRD_PERSON,
        MODE_EDIT_AVATAR,
        MODE_SITTING,
        MODE_SAVED_SETTINGS, // for settings from saved settings
        MODE_COUNT
    };

    const U32 CONFLICT_NOTHING = 0;
    const U32 CONFLICT_LMOUSE = 0x1 << 1;
    // at the moment this just means that key will conflict with everything that is identical
    const U32 CONFLICT_ANY = U32_MAX;

    // Note: missed selection and edition commands (would be really nice to go through selection via MB4/5 or wheel)

    LLKeyConflictHandler();
    LLKeyConflictHandler(ESourceMode mode);
    ~LLKeyConflictHandler();

    bool canHandleControl(const std::string &control_name, EMouseClickType mouse_ind, KEY key, MASK mask);
    bool canHandleKey(const std::string &control_name, KEY key, MASK mask);
    bool canHandleMouse(const std::string &control_name, EMouseClickType mouse_ind, MASK mask);
    bool canHandleMouse(const std::string &control_name, S32 mouse_ind, MASK mask); //Just for convinience
    bool canAssignControl(const std::string &control_name);
    static bool isReservedByMenu(const KEY &key, const MASK &mask);
    static bool isReservedByMenu(const LLKeyData &data);

    // @control_name - see REGISTER_KEYBOARD_ACTION in llviewerinput for avaliable options,
    // usually this is just name of the function
    // @data_index - single control (function) can have multiple key combinations trigering
    // it, this index indicates combination function will change/add; Note that preferences
    // floater can only display up to 3 options, but data_index can be bigger than that
    // @mouse_ind - mouse action (middle click, MB5 etc)
    // @key - keyboard key action
    // @mask - shift/ctrl/alt flags
    // @ignore_mask - Either to expect exact match (ctrl+K will not trigger if ctrl+shift+K
    // is active) or ignore not expected masks as long as expected mask is present
    // (ctrl+K will be triggered if ctrl+shift+K is active)
    bool registerControl(const std::string &control_name, U32 data_index, EMouseClickType mouse_ind, KEY key, MASK mask, bool ignore_mask); //todo: return conflicts?
    bool clearControl(const std::string &control_name, U32 data_index);

    LLKeyData getControl(const std::string &control_name, U32 data_index);
    bool isControlEmpty(const std::string &control_name);

    // localized string
    static std::string getStringFromKeyData(const LLKeyData& keydata);
    std::string getControlString(const std::string &control_name, U32 data_index);

    // Load single control, overrides existing one if names match
    void loadFromControlSettings(const std::string &name);
    // Drops any changes loads controls with ones from 'saved settings' or from xml
    void loadFromSettings(ESourceMode load_mode);

    // Saves settings to 'saved settings' or to xml
    // If 'temporary' is set, function will save settings to temporary
    // file and reload input bindings from temporary file.
    // 'temporary' does not support gSavedSettings, those are handled
    // by preferences, so 'temporary' is such case will simply not
    // reset mHasUnsavedChanges
    //
    // 'temporary' exists to support ability of live-editing settings in
    // preferences: temporary for testing changes 'live' without saving them,
    // then hitting ok/cancel and save/discard values permanently.
    void saveToSettings(bool apply_temporary = false);

    LLKeyData getDefaultControl(const std::string &control_name, U32 data_index);
    // Resets keybinding to default variant from 'saved settings' or xml
    void resetToDefault(const std::string &control_name, U32 index);
    void resetToDefault(const std::string &control_name);
    // resets current mode to defaults
    void resetToDefaults();

    bool empty() const { return mControlsMap.empty(); }
    void clear();

    // reloads bindings from last valid user's xml or from default xml
    // to keyboard's handler
    static void resetKeyboardBindings();

    bool hasUnsavedChanges() const { return mHasUnsavedChanges; }
    void setLoadMode(ESourceMode mode) { mLoadMode = mode; }
    ESourceMode getLoadMode() const { return mLoadMode; }

private:
    void resetToDefaultAndResolve(const std::string &control_name, bool ignore_conflicts);
    void resetToDefaultsAndResolve();

    // at the moment these kind of control is not savable, but takes part in conflict resolution
    void registerTemporaryControl(const std::string &control_name, EMouseClickType mouse_ind, KEY key, MASK mask, U32 conflict_mask);
    // conflict mask 0 means that any conflicts will be ignored
    void registerTemporaryControl(const std::string &control_name, U32 conflict_mask = 0);

    typedef std::map<std::string, LLKeyConflict> control_map_t;
    void loadFromSettings(const LLViewerInput::KeyMode& keymode, control_map_t *destination);
    bool loadFromSettings(const ESourceMode &load_mode, const std::string &filename, control_map_t *destination);
    void generatePlaceholders(ESourceMode load_mode); //E.x. non-assignable values
    // returns false in case user is trying to reuse control that can't be reassigned
    bool removeConflicts(const LLKeyData &data, U32 conlict_mask);

    // removes flags and removes temporary file, returns 'true' if file was removed
    bool clearUnsavedChanges();
    // return true if there was a file to remove
    static bool clearTemporaryFile();

    control_map_t mControlsMap;
    control_map_t mDefaultsMap;
    bool mHasUnsavedChanges;
    ESourceMode mLoadMode;

    // To implement 'apply immediately'+revert on cancel, class applies changes to temporary file
    // but this only works for settings from keybndings files (key_bindings.xml)
    // saved setting rely onto external mechanism of preferences floater
    bool mUsesTemporaryFile;
    static S32 sTemporaryFileUseCount;
};


#endif  // LL_LLKEYCONFLICT_H