keys: implement parsing key configuration file
This commit is contained in:
@@ -69,7 +69,14 @@ size_t Action::HeaderHeight;
|
||||
size_t Action::FooterHeight;
|
||||
size_t Action::FooterStartY;
|
||||
|
||||
std::map<ActionType, Action *> Action::Actions;
|
||||
namespace {//
|
||||
|
||||
std::map<ActionType, Action *> Actions;
|
||||
|
||||
void insertAction(Action *a);
|
||||
void populateActions();
|
||||
|
||||
}
|
||||
|
||||
void Action::ValidateScreenSize()
|
||||
{
|
||||
@@ -418,6 +425,29 @@ bool Action::isMPDMusicDirSet()
|
||||
return true;
|
||||
}
|
||||
|
||||
Action *Action::Get(ActionType at)
|
||||
{
|
||||
if (Actions.empty())
|
||||
populateActions();
|
||||
return Actions[at];
|
||||
}
|
||||
|
||||
Action *Action::Get(const std::string &name)
|
||||
{
|
||||
Action *result = 0;
|
||||
if (Actions.empty())
|
||||
populateActions();
|
||||
for (auto it = Actions.begin(); it != Actions.end(); ++it)
|
||||
{
|
||||
if (it->second->Name() == name)
|
||||
{
|
||||
result = it->second;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool MouseEvent::canBeRun() const
|
||||
{
|
||||
return Config.mouse_support;
|
||||
@@ -2478,10 +2508,16 @@ void ShowServerInfo::Run()
|
||||
myServerInfo->SwitchTo();
|
||||
}
|
||||
|
||||
Action *Action::Get(ActionType at)
|
||||
namespace {//
|
||||
|
||||
void insertAction(Action *a)
|
||||
{
|
||||
if (Actions.empty())
|
||||
Actions[a->Type()] = a;
|
||||
}
|
||||
|
||||
void populateActions()
|
||||
{
|
||||
insertAction(new Dummy());
|
||||
insertAction(new MouseEvent());
|
||||
insertAction(new ScrollUp());
|
||||
insertAction(new ScrollDown());
|
||||
@@ -2593,5 +2629,5 @@ Action *Action::Get(ActionType at)
|
||||
insertAction(new ShowClock());
|
||||
insertAction(new ShowServerInfo());
|
||||
}
|
||||
return Actions[at];
|
||||
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
enum ActionType
|
||||
{
|
||||
aMacroUtility,
|
||||
aMouseEvent, aScrollUp, aScrollDown, aScrollUpArtist, aScrollUpAlbum, aScrollDownArtist,
|
||||
aDummy, aMouseEvent, aScrollUp, aScrollDown, aScrollUpArtist, aScrollUpAlbum, aScrollDownArtist,
|
||||
aScrollDownAlbum, aPageUp, aPageDown, aMoveHome, aMoveEnd, aToggleInterface, aJumpToParentDir,
|
||||
aPressEnter, aPressSpace, aPreviousColumn, aNextColumn, aMasterScreen, aSlaveScreen, aVolumeUp,
|
||||
aVolumeDown, aDelete, aReplaySong, aPreviousSong, aNextSong, aPause, aStop, aSavePlaylist,
|
||||
@@ -79,6 +79,7 @@ struct Action
|
||||
static bool isMPDMusicDirSet();
|
||||
|
||||
static Action *Get(ActionType);
|
||||
static Action *Get(const std::string &name);
|
||||
|
||||
static bool OriginalStatusbarVisibility;
|
||||
static bool DesignChanged;
|
||||
@@ -100,9 +101,12 @@ struct Action
|
||||
private:
|
||||
ActionType itsType;
|
||||
const char *itsName;
|
||||
};
|
||||
|
||||
static void insertAction(Action *a) { Actions[a->Type()] = a; }
|
||||
static std::map<ActionType, Action *> Actions;
|
||||
struct Dummy : public Action
|
||||
{
|
||||
Dummy() : Action(aDummy, "dummy") { }
|
||||
virtual void Run() { }
|
||||
};
|
||||
|
||||
struct MouseEvent : public Action
|
||||
|
||||
538
src/keys.cpp
538
src/keys.cpp
@@ -18,146 +18,70 @@
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include "keys.h"
|
||||
#include "utility/comparators.h"
|
||||
#include "utility/string.h"
|
||||
|
||||
KeyConfiguration Keys;
|
||||
|
||||
Key Key::noOp = Key(ERR, NCurses);
|
||||
|
||||
void KeyConfiguration::generateBindings()
|
||||
{
|
||||
bind_(KEY_MOUSE, Key::NCurses, aMouseEvent);
|
||||
bind_(KEY_UP, Key::NCurses, aScrollUp);
|
||||
bind_(KEY_DOWN, Key::NCurses, aScrollDown);
|
||||
bind_('[', Key::Standard, aScrollUpAlbum);
|
||||
bind_(']', Key::Standard, aScrollDownAlbum);
|
||||
bind_('{', Key::Standard, aScrollUpArtist);
|
||||
bind_('}', Key::Standard, aScrollDownArtist);
|
||||
bind_(KEY_PPAGE, Key::NCurses, aPageUp);
|
||||
bind_(KEY_NPAGE, Key::NCurses, aPageDown);
|
||||
bind_(KEY_HOME, Key::NCurses, aMoveHome);
|
||||
bind_(KEY_END, Key::NCurses, aMoveEnd);
|
||||
bind_(KEY_SPACE, Key::Standard, aPressSpace);
|
||||
bind_(KEY_ENTER, Key::Standard, aPressEnter);
|
||||
bind_(KEY_DC, Key::NCurses, aDelete);
|
||||
bind_(KEY_RIGHT, Key::NCurses, aNextColumn);
|
||||
bind_(KEY_RIGHT, Key::NCurses, aSlaveScreen);
|
||||
bind_(KEY_RIGHT, Key::NCurses, aVolumeUp);
|
||||
bind_(KEY_LEFT, Key::NCurses, aPreviousColumn);
|
||||
bind_(KEY_LEFT, Key::NCurses, aMasterScreen);
|
||||
bind_(KEY_LEFT, Key::NCurses, aVolumeDown);
|
||||
bind_(KEY_TAB, Key::Standard, aNextScreen);
|
||||
bind_(KEY_SHIFT_TAB, Key::NCurses, aPreviousScreen);
|
||||
bind_('1', Key::Standard, aShowHelp);
|
||||
bind_('2', Key::Standard, aShowPlaylist);
|
||||
bind_('3', Key::Standard, aShowBrowser);
|
||||
bind_('4', Key::Standard, aShowSearchEngine);
|
||||
bind_('5', Key::Standard, aShowMediaLibrary);
|
||||
bind_('6', Key::Standard, aShowPlaylistEditor);
|
||||
bind_('7', Key::Standard, aShowTagEditor);
|
||||
bind_('8', Key::Standard, aShowOutputs);
|
||||
bind_('9', Key::Standard, aShowVisualizer);
|
||||
bind_('0', Key::Standard, aShowClock);
|
||||
bind_('@', Key::Standard, aShowServerInfo);
|
||||
bind_('s', Key::Standard, aStop);
|
||||
bind_('P', Key::Standard, aPause);
|
||||
bind_('>', Key::Standard, aNextSong);
|
||||
bind_('<', Key::Standard, aPreviousSong);
|
||||
bind_(KEY_CTRL_H, Key::Standard, aJumpToParentDir);
|
||||
bind_(KEY_CTRL_H, Key::Standard, aReplaySong);
|
||||
bind_(KEY_BACKSPACE, Key::NCurses, aJumpToParentDir);
|
||||
bind_(KEY_BACKSPACE, Key::NCurses, aReplaySong);
|
||||
bind_(KEY_BACKSPACE_2, Key::Standard, aJumpToParentDir);
|
||||
bind_(KEY_BACKSPACE_2, Key::Standard, aReplaySong);
|
||||
bind_('f', Key::Standard, aSeekForward);
|
||||
bind_('b', Key::Standard, aSeekBackward);
|
||||
bind_('r', Key::Standard, aToggleRepeat);
|
||||
bind_('z', Key::Standard, aToggleRandom);
|
||||
bind_('y', Key::Standard, aSaveTagChanges);
|
||||
bind_('y', Key::Standard, aStartSearching);
|
||||
bind_('y', Key::Standard, aToggleSingle);
|
||||
bind_('R', Key::Standard, aToggleConsume);
|
||||
bind_('Y', Key::Standard, aToggleReplayGainMode);
|
||||
bind_('t', Key::Standard, aToggleSpaceMode);
|
||||
bind_('T', Key::Standard, aToggleAddMode);
|
||||
bind_('|', Key::Standard, aToggleMouse);
|
||||
bind_('#', Key::Standard, aToggleBitrateVisibility);
|
||||
bind_('Z', Key::Standard, aShuffle);
|
||||
bind_('x', Key::Standard, aToggleCrossfade);
|
||||
bind_('X', Key::Standard, aSetCrossfade);
|
||||
bind_('u', Key::Standard, aUpdateDatabase);
|
||||
bind_(KEY_CTRL_V, Key::Standard, aSortPlaylist);
|
||||
bind_(KEY_CTRL_R, Key::Standard, aReversePlaylist);
|
||||
bind_(KEY_CTRL_F, Key::Standard, aApplyFilter);
|
||||
bind_(KEY_CTRL_G, Key::Standard, aDisableFilter);
|
||||
bind_('/', Key::Standard, aFind);
|
||||
bind_('/', Key::Standard, aFindItemForward);
|
||||
bind_('?', Key::Standard, aFind);
|
||||
bind_('?', Key::Standard, aFindItemBackward);
|
||||
bind_('.', Key::Standard, aNextFoundItem);
|
||||
bind_(',', Key::Standard, aPreviousFoundItem);
|
||||
bind_('w', Key::Standard, aToggleFindMode);
|
||||
bind_('e', Key::Standard, aEditSong);
|
||||
bind_('e', Key::Standard, aEditLibraryTag);
|
||||
bind_('e', Key::Standard, aEditLibraryAlbum);
|
||||
bind_('e', Key::Standard, aEditDirectoryName);
|
||||
bind_('e', Key::Standard, aEditPlaylistName);
|
||||
bind_('e', Key::Standard, aEditLyrics);
|
||||
bind_('i', Key::Standard, aShowSongInfo);
|
||||
bind_('I', Key::Standard, aShowArtistInfo);
|
||||
bind_('g', Key::Standard, aJumpToPositionInSong);
|
||||
bind_('l', Key::Standard, aShowLyrics);
|
||||
bind_('v', Key::Standard, aReverseSelection);
|
||||
bind_('V', Key::Standard, aDeselectItems);
|
||||
bind_('B', Key::Standard, aSelectAlbum);
|
||||
bind_('a', Key::Standard, aAddSelectedItems);
|
||||
bind_('c', Key::Standard, aClearPlaylist);
|
||||
bind_('c', Key::Standard, aClearMainPlaylist);
|
||||
bind_('C', Key::Standard, aCropPlaylist);
|
||||
bind_('C', Key::Standard, aCropMainPlaylist);
|
||||
bind_('m', Key::Standard, aMoveSortOrderUp);
|
||||
bind_('m', Key::Standard, aMoveSelectedItemsUp);
|
||||
bind_('n', Key::Standard, aMoveSortOrderDown);
|
||||
bind_('n', Key::Standard, aMoveSelectedItemsDown);
|
||||
bind_('M', Key::Standard, aMoveSelectedItemsTo);
|
||||
bind_('A', Key::Standard, aAdd);
|
||||
bind_('S', Key::Standard, aSavePlaylist);
|
||||
bind_('o', Key::Standard, aJumpToPlayingSong);
|
||||
bind_('G', Key::Standard, aJumpToBrowser);
|
||||
bind_('G', Key::Standard, aJumpToPlaylistEditor);
|
||||
bind_('~', Key::Standard, aJumpToMediaLibrary);
|
||||
bind_('E', Key::Standard, aJumpToTagEditor);
|
||||
bind_('U', Key::Standard, aToggleAutoCenter);
|
||||
bind_('p', Key::Standard, aToggleDisplayMode);
|
||||
bind_('\\', Key::Standard, aToggleInterface);
|
||||
bind_('!', Key::Standard, aToggleSeparatorsInPlaylist);
|
||||
bind_('L', Key::Standard, aToggleLyricsFetcher);
|
||||
bind_('F', Key::Standard, aToggleFetchingLyricsInBackground);
|
||||
bind_(KEY_CTRL_L, Key::Standard, aToggleScreenLock);
|
||||
bind_('`', Key::Standard, aToggleBrowserSortMode);
|
||||
bind_('`', Key::Standard, aToggleLibraryTagType);
|
||||
bind_('`', Key::Standard, aRefetchLyrics);
|
||||
bind_('`', Key::Standard, aRefetchArtistInfo);
|
||||
bind_('`', Key::Standard, aAddRandomItems);
|
||||
bind_(KEY_CTRL_P, Key::Standard, aSetSelectedItemsPriority);
|
||||
bind_('q', Key::Standard, aQuit);
|
||||
namespace {//
|
||||
|
||||
Key stringToKey(const std::string &s)
|
||||
{
|
||||
Key result = Key::noOp;
|
||||
if (!s.compare("mouse"))
|
||||
result = Key(KEY_MOUSE, Key::NCurses);
|
||||
else if (!s.compare("up"))
|
||||
result = Key(KEY_UP, Key::NCurses);
|
||||
else if (!s.compare("down"))
|
||||
result = Key(KEY_DOWN, Key::NCurses);
|
||||
else if (!s.compare("page_up"))
|
||||
result = Key(KEY_PPAGE, Key::NCurses);
|
||||
else if (!s.compare("page_down"))
|
||||
result = Key(KEY_NPAGE, Key::NCurses);
|
||||
else if (!s.compare("home"))
|
||||
result = Key(KEY_HOME, Key::NCurses);
|
||||
else if (!s.compare("end"))
|
||||
result = Key(KEY_END, Key::NCurses);
|
||||
else if (!s.compare("space"))
|
||||
result = Key(KEY_SPACE, Key::Standard);
|
||||
else if (!s.compare("enter"))
|
||||
result = Key(KEY_ENTER, Key::Standard);
|
||||
else if (!s.compare("delete"))
|
||||
result = Key(KEY_DC, Key::NCurses);
|
||||
else if (!s.compare("left"))
|
||||
result = Key(KEY_LEFT, Key::NCurses);
|
||||
else if (!s.compare("right"))
|
||||
result = Key(KEY_RIGHT, Key::NCurses);
|
||||
else if (!s.compare("tab"))
|
||||
result = Key(KEY_TAB, Key::Standard);
|
||||
else if (!s.compare("shift_tab"))
|
||||
result = Key(KEY_SHIFT_TAB, Key::NCurses);
|
||||
else if (!s.compare(0, 5, "ctrl_") && s.length() > 5 && s[5] >= 'a' && s[5] <= 'z')
|
||||
result = Key(KEY_CTRL_A + (s[5] - 'a'), Key::Standard);
|
||||
else if (s.length() > 1 && s[0] == 'f')
|
||||
{
|
||||
int n = atoi(s.c_str() + 1);
|
||||
if (n >= 1 && n <= 12)
|
||||
result = Key(KEY_F1 + n - 1, Key::NCurses);
|
||||
}
|
||||
else if (!s.compare("backspace"))
|
||||
result = Key(KEY_BACKSPACE, Key::NCurses);
|
||||
else if (!s.compare("backspace_2"))
|
||||
result = Key(KEY_BACKSPACE_2, Key::Standard);
|
||||
else
|
||||
{
|
||||
std::wstring ws = ToWString(s);
|
||||
if (ws.length() == 1)
|
||||
result = Key(ws[0], Key::Standard);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bind_('k', Key::Standard, aScrollUp);
|
||||
bind_('j', Key::Standard, aScrollDown);
|
||||
bind_('d', Key::Standard, aDelete);
|
||||
bind_('+', Key::Standard, aVolumeUp);
|
||||
bind_('-', Key::Standard, aVolumeDown);
|
||||
bind_(KEY_F1, Key::NCurses, aShowHelp);
|
||||
bind_(KEY_F2, Key::NCurses, aShowPlaylist);
|
||||
bind_(KEY_F3, Key::NCurses, aShowBrowser);
|
||||
bind_(KEY_F4, Key::NCurses, aShowSearchEngine);
|
||||
bind_(KEY_F5, Key::NCurses, aShowMediaLibrary);
|
||||
bind_(KEY_F6, Key::NCurses, aShowPlaylistEditor);
|
||||
bind_(KEY_F7, Key::NCurses, aShowTagEditor);
|
||||
bind_(KEY_F8, Key::NCurses, aShowOutputs);
|
||||
bind_(KEY_F9, Key::NCurses, aShowVisualizer);
|
||||
bind_(KEY_F10, Key::NCurses, aShowClock);
|
||||
bind_('Q', Key::Standard, aQuit);
|
||||
}
|
||||
|
||||
Key Key::read(NC::Window &w)
|
||||
@@ -193,3 +117,351 @@ Key Key::read(NC::Window &w)
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool KeyConfiguration::read(const std::string &file)
|
||||
{
|
||||
bool result = true;
|
||||
|
||||
std::ifstream f(file);
|
||||
if (!f.is_open())
|
||||
return result;
|
||||
|
||||
size_t line_no = 0;
|
||||
bool key_def_in_progress = false;
|
||||
Key key = Key::noOp;
|
||||
Binding::ActionChain actions;
|
||||
std::string line, strkey;
|
||||
|
||||
auto error = [&]() -> std::ostream & {
|
||||
std::cerr << file << ":" << line_no << ": ";
|
||||
key_def_in_progress = false;
|
||||
result = false;
|
||||
return std::cerr;
|
||||
};
|
||||
auto bind_key_def = [&]() -> bool {
|
||||
if (!actions.empty())
|
||||
{
|
||||
bind(key, actions);
|
||||
actions.clear();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
error() << "definition of key \"" << strkey << "\" cannot be empty.\n";
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
while (!f.eof() && ++line_no)
|
||||
{
|
||||
getline(f, line);
|
||||
if (line.empty() || line[0] == '#')
|
||||
continue;
|
||||
|
||||
if (!line.compare(0, 7, "def_key")) // beginning of key definition
|
||||
{
|
||||
if (key_def_in_progress)
|
||||
{
|
||||
if (!bind_key_def())
|
||||
break;
|
||||
}
|
||||
key_def_in_progress = true;
|
||||
strkey = getEnclosedString(line, '"', '"', 0);
|
||||
key = stringToKey(strkey);
|
||||
if (key == Key::noOp)
|
||||
{
|
||||
error() << "invalid key: \"" << strkey << "\"\n";
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (isspace(line[0])) // name of action to be bound
|
||||
{
|
||||
trim(line);
|
||||
Action *action = Action::Get(line);
|
||||
if (action)
|
||||
actions.push_back(action);
|
||||
else
|
||||
{
|
||||
error() << "unknown action: \"" << line << "\"\n";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (key_def_in_progress)
|
||||
bind_key_def();
|
||||
f.close();
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
void KeyConfiguration::generateBindings()
|
||||
{
|
||||
Key k = Key::noOp;
|
||||
if (notBound(k = stringToKey("mouse")))
|
||||
bind(k, aMouseEvent);
|
||||
if (notBound(k = stringToKey("up")))
|
||||
bind(k, aScrollUp);
|
||||
if (notBound(k = stringToKey("down")))
|
||||
bind(k, aScrollDown);
|
||||
if (notBound(k = stringToKey("[")))
|
||||
bind(k, aScrollUpAlbum);
|
||||
if (notBound(k = stringToKey("]")))
|
||||
bind(k, aScrollDownAlbum);
|
||||
if (notBound(k = stringToKey("{")))
|
||||
bind(k, aScrollUpArtist);
|
||||
if (notBound(k = stringToKey("}")))
|
||||
bind(k, aScrollDownArtist);
|
||||
if (notBound(k = stringToKey("page_up")))
|
||||
bind(k, aPageUp);
|
||||
if (notBound(k = stringToKey("page_down")))
|
||||
bind(k, aPageDown);
|
||||
if (notBound(k = stringToKey("home")))
|
||||
bind(k, aMoveHome);
|
||||
if (notBound(k = stringToKey("end")))
|
||||
bind(k, aMoveEnd);
|
||||
if (notBound(k = stringToKey("space")))
|
||||
bind(k, aPressSpace);
|
||||
if (notBound(k = stringToKey("enter")))
|
||||
bind(k, aPressEnter);
|
||||
if (notBound(k = stringToKey("delete")))
|
||||
bind(k, aDelete);
|
||||
if (notBound(k = stringToKey("right")))
|
||||
{
|
||||
bind(k, aNextColumn);
|
||||
bind(k, aSlaveScreen);
|
||||
bind(k, aVolumeUp);
|
||||
}
|
||||
if (notBound(k = stringToKey("left")))
|
||||
{
|
||||
bind(k, aPreviousColumn);
|
||||
bind(k, aMasterScreen);
|
||||
bind(k, aVolumeDown);
|
||||
}
|
||||
if (notBound(k = stringToKey("tab")))
|
||||
bind(k, aNextScreen);
|
||||
if (notBound(k = stringToKey("shift_tab")))
|
||||
bind(k, aPreviousScreen);
|
||||
if (notBound(k = stringToKey("1")))
|
||||
bind(k, aShowHelp);
|
||||
if (notBound(k = stringToKey("2")))
|
||||
bind(k, aShowPlaylist);
|
||||
if (notBound(k = stringToKey("3")))
|
||||
bind(k, aShowBrowser);
|
||||
if (notBound(k = stringToKey("4")))
|
||||
bind(k, aShowSearchEngine);
|
||||
if (notBound(k = stringToKey("5")))
|
||||
bind(k, aShowMediaLibrary);
|
||||
if (notBound(k = stringToKey("6")))
|
||||
bind(k, aShowPlaylistEditor);
|
||||
if (notBound(k = stringToKey("7")))
|
||||
bind(k, aShowTagEditor);
|
||||
if (notBound(k = stringToKey("8")))
|
||||
bind(k, aShowOutputs);
|
||||
if (notBound(k = stringToKey("9")))
|
||||
bind(k, aShowVisualizer);
|
||||
if (notBound(k = stringToKey("0")))
|
||||
bind(k, aShowClock);
|
||||
if (notBound(k = stringToKey("@")))
|
||||
bind(k, aShowServerInfo);
|
||||
if (notBound(k = stringToKey("s")))
|
||||
bind(k, aStop);
|
||||
if (notBound(k = stringToKey("P")))
|
||||
bind(k, aPause);
|
||||
if (notBound(k = stringToKey(">")))
|
||||
bind(k, aNextSong);
|
||||
if (notBound(k = stringToKey("<")))
|
||||
bind(k, aPreviousSong);
|
||||
if (notBound(k = stringToKey("ctrl_h")))
|
||||
{
|
||||
bind(k, aJumpToParentDir);
|
||||
bind(k, aReplaySong);
|
||||
}
|
||||
if (notBound(k = stringToKey("backspace")))
|
||||
{
|
||||
bind(k, aJumpToParentDir);
|
||||
bind(k, aReplaySong);
|
||||
}
|
||||
if (notBound(k = stringToKey("backspace_2")))
|
||||
{
|
||||
bind(k, aJumpToParentDir);
|
||||
bind(k, aReplaySong);
|
||||
}
|
||||
if (notBound(k = stringToKey("f")))
|
||||
bind(k, aSeekForward);
|
||||
if (notBound(k = stringToKey("b")))
|
||||
bind(k, aSeekBackward);
|
||||
if (notBound(k = stringToKey("r")))
|
||||
bind(k, aToggleRepeat);
|
||||
if (notBound(k = stringToKey("z")))
|
||||
bind(k, aToggleRandom);
|
||||
if (notBound(k = stringToKey("y")))
|
||||
{
|
||||
bind(k, aSaveTagChanges);
|
||||
bind(k, aStartSearching);
|
||||
bind(k, aToggleSingle);
|
||||
}
|
||||
if (notBound(k = stringToKey("R")))
|
||||
bind(k, aToggleConsume);
|
||||
if (notBound(k = stringToKey("Y")))
|
||||
bind(k, aToggleReplayGainMode);
|
||||
if (notBound(k = stringToKey("t")))
|
||||
bind(k, aToggleSpaceMode);
|
||||
if (notBound(k = stringToKey("T")))
|
||||
bind(k, aToggleAddMode);
|
||||
if (notBound(k = stringToKey("|")))
|
||||
bind(k, aToggleMouse);
|
||||
if (notBound(k = stringToKey("#")))
|
||||
bind(k, aToggleBitrateVisibility);
|
||||
if (notBound(k = stringToKey("Z")))
|
||||
bind(k, aShuffle);
|
||||
if (notBound(k = stringToKey("x")))
|
||||
bind(k, aToggleCrossfade);
|
||||
if (notBound(k = stringToKey("X")))
|
||||
bind(k, aSetCrossfade);
|
||||
if (notBound(k = stringToKey("u")))
|
||||
bind(k, aUpdateDatabase);
|
||||
if (notBound(k = stringToKey("ctrl_v")))
|
||||
bind(k, aSortPlaylist);
|
||||
if (notBound(k = stringToKey("ctrl_r")))
|
||||
bind(k, aReversePlaylist);
|
||||
if (notBound(k = stringToKey("ctrl_f")))
|
||||
bind(k, aApplyFilter);
|
||||
if (notBound(k = stringToKey("ctrl_g")))
|
||||
bind(k, aDisableFilter);
|
||||
if (notBound(k = stringToKey("/")))
|
||||
{
|
||||
bind(k, aFind);
|
||||
bind(k, aFindItemForward);
|
||||
}
|
||||
if (notBound(k = stringToKey("/")))
|
||||
{
|
||||
bind(k, aFind);
|
||||
bind(k, aFindItemBackward);
|
||||
}
|
||||
if (notBound(k = stringToKey(".")))
|
||||
bind(k, aNextFoundItem);
|
||||
if (notBound(k = stringToKey(",")))
|
||||
bind(k, aPreviousFoundItem);
|
||||
if (notBound(k = stringToKey("w")))
|
||||
bind(k, aToggleFindMode);
|
||||
if (notBound(k = stringToKey("e")))
|
||||
{
|
||||
bind(k, aEditSong);
|
||||
bind(k, aEditLibraryTag);
|
||||
bind(k, aEditLibraryAlbum);
|
||||
bind(k, aEditDirectoryName);
|
||||
bind(k, aEditPlaylistName);
|
||||
bind(k, aEditLyrics);
|
||||
}
|
||||
if (notBound(k = stringToKey("i")))
|
||||
bind(k, aShowSongInfo);
|
||||
if (notBound(k = stringToKey("I")))
|
||||
bind(k, aShowArtistInfo);
|
||||
if (notBound(k = stringToKey("g")))
|
||||
bind(k, aJumpToPositionInSong);
|
||||
if (notBound(k = stringToKey("l")))
|
||||
bind(k, aShowLyrics);
|
||||
if (notBound(k = stringToKey("v")))
|
||||
bind(k, aReverseSelection);
|
||||
if (notBound(k = stringToKey("B")))
|
||||
bind(k, aSelectAlbum);
|
||||
if (notBound(k = stringToKey("a")))
|
||||
bind(k, aAddSelectedItems);
|
||||
if (notBound(k = stringToKey("c")))
|
||||
{
|
||||
bind(k, aClearPlaylist);
|
||||
bind(k, aClearMainPlaylist);
|
||||
}
|
||||
if (notBound(k = stringToKey("C")))
|
||||
{
|
||||
bind(k, aCropPlaylist);
|
||||
bind(k, aCropMainPlaylist);
|
||||
}
|
||||
if (notBound(k = stringToKey("m")))
|
||||
{
|
||||
bind(k, aMoveSortOrderUp);
|
||||
bind(k, aMoveSelectedItemsUp);
|
||||
}
|
||||
if (notBound(k = stringToKey("n")))
|
||||
{
|
||||
bind(k, aMoveSortOrderDown);
|
||||
bind(k, aMoveSelectedItemsDown);
|
||||
}
|
||||
if (notBound(k = stringToKey("M")))
|
||||
bind(k, aMoveSelectedItemsTo);
|
||||
if (notBound(k = stringToKey("A")))
|
||||
bind(k, aAdd);
|
||||
if (notBound(k = stringToKey("S")))
|
||||
bind(k, aSavePlaylist);
|
||||
if (notBound(k = stringToKey("o")))
|
||||
bind(k, aJumpToPlayingSong);
|
||||
if (notBound(k = stringToKey("G")))
|
||||
{
|
||||
bind(k, aJumpToBrowser);
|
||||
bind(k, aJumpToPlaylistEditor);
|
||||
}
|
||||
if (notBound(k = stringToKey("~")))
|
||||
bind(k, aJumpToMediaLibrary);
|
||||
if (notBound(k = stringToKey("E")))
|
||||
bind(k, aJumpToTagEditor);
|
||||
if (notBound(k = stringToKey("U")))
|
||||
bind(k, aToggleAutoCenter);
|
||||
if (notBound(k = stringToKey("p")))
|
||||
bind(k, aToggleDisplayMode);
|
||||
if (notBound(k = stringToKey("\\")))
|
||||
bind(k, aToggleInterface);
|
||||
if (notBound(k = stringToKey("!")))
|
||||
bind(k, aToggleSeparatorsInPlaylist);
|
||||
if (notBound(k = stringToKey("L")))
|
||||
bind(k, aToggleLyricsFetcher);
|
||||
if (notBound(k = stringToKey("F")))
|
||||
bind(k, aToggleFetchingLyricsInBackground);
|
||||
if (notBound(k = stringToKey("ctrl_l")))
|
||||
bind(k, aToggleScreenLock);
|
||||
if (notBound(k = stringToKey("`")))
|
||||
{
|
||||
bind(k, aToggleBrowserSortMode);
|
||||
bind(k, aToggleLibraryTagType);
|
||||
bind(k, aRefetchLyrics);
|
||||
bind(k, aRefetchArtistInfo);
|
||||
bind(k, aAddRandomItems);
|
||||
}
|
||||
if (notBound(k = stringToKey("ctrl_p")))
|
||||
bind(k, aSetSelectedItemsPriority);
|
||||
if (notBound(k = stringToKey("q")))
|
||||
bind(k, aQuit);
|
||||
|
||||
if (notBound(k = stringToKey("k")))
|
||||
bind(k, aScrollUp);
|
||||
if (notBound(k = stringToKey("j")))
|
||||
bind(k, aScrollDown);
|
||||
if (notBound(k = stringToKey("d")))
|
||||
bind(k, aDelete);
|
||||
if (notBound(k = stringToKey("+")))
|
||||
bind(k, aVolumeUp);
|
||||
if (notBound(k = stringToKey("-")))
|
||||
bind(k, aVolumeDown);
|
||||
|
||||
if (notBound(k = stringToKey("f1")))
|
||||
bind(k, aShowHelp);
|
||||
if (notBound(k = stringToKey("f2")))
|
||||
bind(k, aShowPlaylist);
|
||||
if (notBound(k = stringToKey("f3")))
|
||||
bind(k, aShowBrowser);
|
||||
if (notBound(k = stringToKey("f4")))
|
||||
bind(k, aShowSearchEngine);
|
||||
if (notBound(k = stringToKey("f5")))
|
||||
bind(k, aShowMediaLibrary);
|
||||
if (notBound(k = stringToKey("f6")))
|
||||
bind(k, aShowPlaylistEditor);
|
||||
if (notBound(k = stringToKey("f7")))
|
||||
bind(k, aShowTagEditor);
|
||||
if (notBound(k = stringToKey("f8")))
|
||||
bind(k, aShowOutputs);
|
||||
if (notBound(k = stringToKey("f9")))
|
||||
bind(k, aShowVisualizer);
|
||||
if (notBound(k = stringToKey("f10")))
|
||||
bind(k, aShowClock);
|
||||
if (notBound(k = stringToKey("Q")))
|
||||
bind(k, aQuit);
|
||||
}
|
||||
|
||||
53
src/keys.h
53
src/keys.h
@@ -31,12 +31,15 @@ struct Key
|
||||
|
||||
Key(wchar_t ch, Type ct) : m_char(ch), m_type(ct) { }
|
||||
|
||||
wchar_t getChar() const { return m_char; }
|
||||
Type getType() const { return m_type; }
|
||||
wchar_t getChar() const {
|
||||
return m_char;
|
||||
}
|
||||
Type getType() const {
|
||||
return m_type;
|
||||
}
|
||||
|
||||
# define KEYS_DEFINE_OPERATOR(CMP) \
|
||||
bool operator CMP (const Key &k) const \
|
||||
{ \
|
||||
bool operator CMP (const Key &k) const { \
|
||||
if (m_char CMP k.m_char) \
|
||||
return true; \
|
||||
if (m_char != k.m_char) \
|
||||
@@ -49,8 +52,12 @@ struct Key
|
||||
KEYS_DEFINE_OPERATOR(>=);
|
||||
# undef KEYS_DEFINE_OPERATOR
|
||||
|
||||
bool operator==(const Key &k) const { return m_char == k.m_char && m_type == k.m_type; }
|
||||
bool operator!=(const Key &k) const { return !(*this == k); }
|
||||
bool operator==(const Key &k) const {
|
||||
return m_char == k.m_char && m_type == k.m_type;
|
||||
}
|
||||
bool operator!=(const Key &k) const {
|
||||
return !(*this == k);
|
||||
}
|
||||
|
||||
static Key read(NC::Window &w);
|
||||
static Key noOp;
|
||||
@@ -66,11 +73,28 @@ struct Binding
|
||||
typedef std::vector<Action *> ActionChain;
|
||||
|
||||
Binding(ActionType at) : m_is_single(true), m_action(Action::Get(at)) { }
|
||||
Binding(ActionChain *chain_) : m_is_single(false), m_chain(chain_) { }
|
||||
Binding(const ActionChain &actions) {
|
||||
assert(actions.size() > 0);
|
||||
if (actions.size() == 1) {
|
||||
m_is_single = true;
|
||||
m_action = actions[0];
|
||||
} else {
|
||||
m_is_single = false;
|
||||
m_chain = new ActionChain(actions);
|
||||
}
|
||||
}
|
||||
|
||||
bool isSingle() const { return m_is_single; }
|
||||
ActionChain *chain() const { assert(!m_is_single); return m_chain; }
|
||||
Action *action() const { assert(m_is_single); return m_action; }
|
||||
bool isSingle() const {
|
||||
return m_is_single;
|
||||
}
|
||||
ActionChain *chain() const {
|
||||
assert(!m_is_single);
|
||||
return m_chain;
|
||||
}
|
||||
Action *action() const {
|
||||
assert(m_is_single);
|
||||
return m_action;
|
||||
}
|
||||
|
||||
private:
|
||||
bool m_is_single;
|
||||
@@ -83,13 +107,18 @@ private:
|
||||
/// Key configuration
|
||||
struct KeyConfiguration
|
||||
{
|
||||
bool read(const std::string &file);
|
||||
void generateBindings();
|
||||
|
||||
std::multimap<Key, Binding> Bindings;
|
||||
|
||||
private:
|
||||
template <typename T> void bind_(wchar_t c, Key::Type ct, T t) {
|
||||
Bindings.insert(std::make_pair(Key(c, ct), Binding(t)));
|
||||
bool notBound(const Key &k) const {
|
||||
return k != Key::noOp && Bindings.find(k) == Bindings.end();
|
||||
}
|
||||
|
||||
template <typename T> void bind(Key k, T t) {
|
||||
Bindings.insert(std::make_pair(k, Binding(t)));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -922,7 +922,7 @@ bool SortAllTracks(const MPD::Song &a, const MPD::Song &b)
|
||||
&MPD::Song::getAlbum,
|
||||
&MPD::Song::getDisc
|
||||
}};
|
||||
CaseInsensitiveStringComparison cmp;
|
||||
CaseInsensitiveStringComparison cmp(Config.ignore_leading_the);
|
||||
for (auto get = gets.begin(); get != gets.end(); ++get)
|
||||
{
|
||||
int ret = cmp(a.getTags(*get), b.getTags(*get));
|
||||
@@ -935,7 +935,7 @@ bool SortAllTracks(const MPD::Song &a, const MPD::Song &b)
|
||||
bool SortSearchConstraints(const SearchConstraints &a, const SearchConstraints &b)
|
||||
{
|
||||
int result;
|
||||
CaseInsensitiveStringComparison cmp;
|
||||
CaseInsensitiveStringComparison cmp(Config.ignore_leading_the);
|
||||
result = cmp(a.PrimaryTag, b.PrimaryTag);
|
||||
if (result != 0)
|
||||
return result < 0;
|
||||
|
||||
@@ -96,8 +96,11 @@ int main(int argc, char **argv)
|
||||
|
||||
Config.SetDefaults();
|
||||
Config.Read();
|
||||
|
||||
Config.GenerateColumns();
|
||||
|
||||
if (!Keys.read(Config.ncmpcpp_directory + "keys"))
|
||||
return 1;
|
||||
|
||||
Keys.generateBindings();
|
||||
|
||||
if (getenv("MPD_HOST"))
|
||||
|
||||
@@ -199,7 +199,7 @@ void Playlist::EnterPressed()
|
||||
|
||||
std::function<void(MPD::SongList::iterator, MPD::SongList::iterator)> iter_swap, quick_sort;
|
||||
auto song_cmp = [](const MPD::Song &a, const MPD::Song &b) -> bool {
|
||||
CaseInsensitiveStringComparison cmp;
|
||||
CaseInsensitiveStringComparison cmp(Config.ignore_leading_the);
|
||||
for (size_t i = 0; i < SortOptions; ++i)
|
||||
if (int ret = cmp(a.getTags((*SortDialog)[i].value().second), b.getTags((*SortDialog)[i].value().second)))
|
||||
return ret < 0;
|
||||
|
||||
@@ -536,7 +536,7 @@ void SearchEngine::Search()
|
||||
}
|
||||
else // match only if values are equal
|
||||
{
|
||||
CaseInsensitiveStringComparison cmp;
|
||||
CaseInsensitiveStringComparison cmp(Config.ignore_leading_the);
|
||||
|
||||
if (!itsConstraints[0].empty())
|
||||
any_found =
|
||||
|
||||
@@ -21,24 +21,32 @@
|
||||
#include "comparators.h"
|
||||
#include "settings.h"
|
||||
|
||||
int CaseInsensitiveStringComparison::operator()(const std::string &a, const std::string &b)
|
||||
bool CaseInsensitiveStringComparison::hasTheWord(const char *s) const
|
||||
{
|
||||
const char *i = a.c_str();
|
||||
const char *j = b.c_str();
|
||||
if (Config.ignore_leading_the)
|
||||
return (s[0] == 't' || s[0] == 'T')
|
||||
&& (s[1] == 'h' || s[1] == 'H')
|
||||
&& (s[2] == 'e' || s[2] == 'E')
|
||||
&& (s[3] == ' ');
|
||||
}
|
||||
|
||||
int CaseInsensitiveStringComparison::operator()(const char *a, const char *b) const
|
||||
{
|
||||
if (m_ignore_the)
|
||||
{
|
||||
if (hasTheWord(a))
|
||||
i += 4;
|
||||
a += 4;
|
||||
if (hasTheWord(b))
|
||||
j += 4;
|
||||
b += 4;
|
||||
}
|
||||
int dist;
|
||||
while (!(dist = tolower(*i)-tolower(*j)) && *j)
|
||||
++i, ++j;
|
||||
while (!(dist = tolower(*a)-tolower(*b)) && *b)
|
||||
++a, ++b;
|
||||
return dist;
|
||||
}
|
||||
|
||||
bool CaseInsensitiveSorting::operator()(const MPD::Item &a, const MPD::Item &b)
|
||||
CaseInsensitiveSorting::CaseInsensitiveSorting(): cmp(Config.ignore_leading_the) { }
|
||||
|
||||
bool CaseInsensitiveSorting::operator()(const MPD::Item &a, const MPD::Item &b) const
|
||||
{
|
||||
bool result = false;
|
||||
if (a.type == b.type)
|
||||
@@ -65,8 +73,6 @@ bool CaseInsensitiveSorting::operator()(const MPD::Item &a, const MPD::Item &b)
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default: // there is no other option, silence compiler
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -26,17 +26,24 @@
|
||||
|
||||
class CaseInsensitiveStringComparison
|
||||
{
|
||||
bool hasTheWord(const std::string &s)
|
||||
{
|
||||
return (s.length() > 3)
|
||||
&& (s[0] == 't' || s[0] == 'T')
|
||||
&& (s[1] == 'h' || s[1] == 'H')
|
||||
&& (s[2] == 'e' || s[2] == 'E')
|
||||
&& (s[3] == ' ');
|
||||
}
|
||||
bool m_ignore_the;
|
||||
|
||||
bool hasTheWord(const char *s) const;
|
||||
|
||||
public:
|
||||
int operator()(const std::string &a, const std::string &b);
|
||||
CaseInsensitiveStringComparison(bool ignore_the) : m_ignore_the(ignore_the) { }
|
||||
|
||||
int operator()(const char *a, const char *b) const;
|
||||
|
||||
int operator()(const char *a, const std::string &b) const {
|
||||
return (*this)(a, b.c_str());
|
||||
}
|
||||
int operator()(const std::string &a, const char *b) const {
|
||||
return (*this)(a.c_str(), b);
|
||||
}
|
||||
int operator()(const std::string &a, const std::string &b) const {
|
||||
return (*this)(a.c_str(), b.c_str());
|
||||
}
|
||||
};
|
||||
|
||||
class CaseInsensitiveSorting
|
||||
@@ -44,22 +51,22 @@ class CaseInsensitiveSorting
|
||||
CaseInsensitiveStringComparison cmp;
|
||||
|
||||
public:
|
||||
bool operator()(const std::string &a, const std::string &b)
|
||||
{
|
||||
CaseInsensitiveSorting();
|
||||
|
||||
bool operator()(const std::string &a, const std::string &b) const {
|
||||
return cmp(a, b) < 0;
|
||||
}
|
||||
|
||||
bool operator()(const MPD::Song &a, const MPD::Song &b)
|
||||
{
|
||||
bool operator()(const MPD::Song &a, const MPD::Song &b) const {
|
||||
return cmp(a.getName(), b.getName()) < 0;
|
||||
}
|
||||
|
||||
template <typename A, typename B> bool operator()(const std::pair<A, B> &a, const std::pair<A, B> &b)
|
||||
{
|
||||
template <typename A, typename B>
|
||||
bool operator()(const std::pair<A, B> &a, const std::pair<A, B> &b) const {
|
||||
return cmp(a.first, b.first) < 0;
|
||||
}
|
||||
|
||||
bool operator()(const MPD::Item &a, const MPD::Item &b);
|
||||
bool operator()(const MPD::Item &a, const MPD::Item &b) const;
|
||||
};
|
||||
|
||||
#endif // _UTILITY_COMPARATORS
|
||||
Reference in New Issue
Block a user