bindinds: add support for alt/ctrl/shift modifiers and escape key
[ncmpcpp.git] / src / bindings.cpp
blobebc42a322c737e95858bff2cd721aad6b67e24c8
1 /***************************************************************************
2 * Copyright (C) 2008-2014 by Andrzej Rybczak *
3 * electricityispower@gmail.com *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
19 ***************************************************************************/
21 #include <boost/algorithm/string/trim.hpp>
22 #include <fstream>
23 #include <iostream>
24 #include "global.h"
25 #include "bindings.h"
26 #include "utility/string.h"
27 #include "utility/wide_string.h"
29 BindingsConfiguration Bindings;
31 namespace {
33 NC::Key::Type stringToKey(const std::string &s);
35 NC::Key::Type stringToSpecialKey(const std::string &s)
37 NC::Key::Type result = NC::Key::None;
38 if (!s.compare(0, 5, "ctrl_") && s.length() == 6)
40 if (s[5] >= 'a' && s[5] <= 'z')
41 result = NC::Key::Ctrl_A + (s[5] - 'a');
42 else if (s[5] == '[')
43 result = NC::Key::Ctrl_LeftBracket;
44 else if (s[5] == '\\')
45 result = NC::Key::Ctrl_Backslash;
46 else if (s[5] == ']')
47 result = NC::Key::Ctrl_RightBracket;
48 else if (s[5] == '^')
49 result = NC::Key::Ctrl_Caret;
50 else if (s[5] == '_')
51 result = NC::Key::Ctrl_Underscore;
53 else if (!s.compare(0, 4, "alt_"))
54 result = NC::Key::Alt | stringToKey(s.substr(4));
55 else if (!s.compare(0, 5, "ctrl_"))
56 result = NC::Key::Ctrl | stringToKey(s.substr(5));
57 else if (!s.compare(0, 6, "shift_"))
58 result = NC::Key::Shift | stringToKey(s.substr(6));
59 else if (!s.compare("escape"))
60 result = NC::Key::Escape;
61 else if (!s.compare("mouse"))
62 result = NC::Key::Mouse;
63 else if (!s.compare("up"))
64 result = NC::Key::Up;
65 else if (!s.compare("down"))
66 result = NC::Key::Down;
67 else if (!s.compare("page_up"))
68 result = NC::Key::PageUp;
69 else if (!s.compare("page_down"))
70 result = NC::Key::PageDown;
71 else if (!s.compare("home"))
72 result = NC::Key::Home;
73 else if (!s.compare("end"))
74 result = NC::Key::End;
75 else if (!s.compare("space"))
76 result = NC::Key::Space;
77 else if (!s.compare("enter"))
78 result = NC::Key::Enter;
79 else if (!s.compare("insert"))
80 result = NC::Key::Insert;
81 else if (!s.compare("delete"))
82 result = NC::Key::Delete;
83 else if (!s.compare("left"))
84 result = NC::Key::Left;
85 else if (!s.compare("right"))
86 result = NC::Key::Right;
87 else if (!s.compare("tab"))
88 result = NC::Key::Tab;
89 else if ((s.length() == 2 || s.length() == 3) && s[0] == 'f')
91 int n = atoi(s.c_str() + 1);
92 if (n >= 1 && n <= 12)
93 result = NC::Key::F1 + n - 1;
95 else if (!s.compare("backspace"))
96 result = NC::Key::Backspace;
97 return result;
100 NC::Key::Type stringToKey(const std::string &s)
102 NC::Key::Type result = stringToSpecialKey(s);
103 if (result == NC::Key::None)
105 std::wstring ws = ToWString(s);
106 if (ws.length() == 1)
107 result = ws[0];
109 return result;
112 template <typename F>
113 Actions::BaseAction *parseActionLine(const std::string &line, F error)
115 Actions::BaseAction *result = 0;
116 size_t i = 0;
117 for (; i < line.size() && !isspace(line[i]); ++i) { }
118 if (i == line.size()) // only action name
119 result = Actions::get(line);
120 else // there is something else
122 std::string action_name = line.substr(0, i);
123 if (action_name == "push_character")
125 // push single character into input queue
126 std::string arg = getEnclosedString(line, '"', '"', 0);
127 NC::Key::Type k = stringToSpecialKey(arg);
128 auto queue = std::vector<NC::Key::Type>{ k };
129 if (k != NC::Key::None)
130 result = new Actions::PushCharacters(&Global::wFooter, std::move(queue));
131 else
132 error() << "invalid character passed to push_character: '" << arg << "'\n";
134 else if (action_name == "push_characters")
136 // push sequence of characters into input queue
137 std::string arg = getEnclosedString(line, '"', '"', 0);
138 if (!arg.empty())
140 std::vector<NC::Key::Type> queue(arg.begin(), arg.end());
141 // if char is signed, erase 1s from char -> int conversion
142 for (auto it = arg.begin(); it != arg.end(); ++it)
143 *it &= 0xff;
144 result = new Actions::PushCharacters(&Global::wFooter, std::move(queue));
146 else
147 error() << "empty argument passed to push_characters\n";
149 else if (action_name == "require_screen")
151 // require screen of given type
152 std::string arg = getEnclosedString(line, '"', '"', 0);
153 ScreenType screen_type = stringToScreenType(arg);
154 if (screen_type != ScreenType::Unknown)
155 result = new Actions::RequireScreen(screen_type);
156 else
157 error() << "unknown screen passed to require_screen: '" << arg << "'\n";
159 else if (action_name == "require_runnable")
161 // require that given action is runnable
162 std::string arg = getEnclosedString(line, '"', '"', 0);
163 auto action = Actions::get(arg);
164 if (action)
165 result = new Actions::RequireRunnable(action);
166 else
167 error() << "unknown action passed to require_runnable: '" << arg << "'\n";
169 else if (action_name == "run_external_command")
171 std::string command = getEnclosedString(line, '"', '"', 0);
172 if (!command.empty())
173 result = new Actions::RunExternalCommand(std::move(command));
174 else
175 error() << "empty command passed to run_external_command\n";
178 return result;
183 NC::Key::Type readKey(NC::Window &w)
185 NC::Key::Type result = NC::Key::None;
186 std::string tmp;
187 NC::Key::Type input;
188 bool alt_pressed = false;
189 while (true)
191 input = w.readKey();
192 if (input == NC::Key::None)
193 break;
194 if (input & NC::Key::Alt)
196 // Complete the key and reapply the mask at the end.
197 alt_pressed = true;
198 input &= ~NC::Key::Alt;
200 if (input > 255) // NC special character
202 result = input;
203 break;
205 else
207 wchar_t wc;
208 tmp += input;
209 size_t conv_res = mbrtowc(&wc, tmp.c_str(), MB_CUR_MAX, 0);
210 if (conv_res == size_t(-1)) // incomplete multibyte character
211 continue;
212 else if (conv_res == size_t(-2)) // garbage character sequence
213 break;
214 else // character complete
216 result = wc;
217 break;
221 if (alt_pressed)
222 result |= NC::Key::Alt;
223 return result;
226 std::wstring keyToWString(const NC::Key::Type key)
228 std::wstring result;
230 if (key == NC::Key::Tab)
231 result += L"Tab";
232 else if (key == NC::Key::Enter)
233 result += L"Enter";
234 else if (key == NC::Key::Escape)
235 result += L"Escape";
236 else if (key >= NC::Key::Ctrl_A && key <= NC::Key::Ctrl_Z)
238 result += L"Ctrl-";
239 result += 'A' + (key - NC::Key::Ctrl_A);
241 else if (key == NC::Key::Ctrl_LeftBracket)
242 result += L"Ctrl-[";
243 else if (key == NC::Key::Ctrl_Backslash)
244 result += L"Ctrl-\\";
245 else if (key == NC::Key::Ctrl_RightBracket)
246 result += L"Ctrl-]";
247 else if (key == NC::Key::Ctrl_Caret)
248 result += L"Ctrl-^";
249 else if (key == NC::Key::Ctrl_Underscore)
250 result += L"Ctrl-_";
251 else if (key & NC::Key::Alt)
253 result += L"Alt-";
254 result += keyToWString(key & ~NC::Key::Alt);
256 else if (key & NC::Key::Ctrl)
258 result += L"Ctrl-";
259 result += keyToWString(key & ~NC::Key::Ctrl);
261 else if (key & NC::Key::Shift)
263 result += L"Shift-";
264 result += keyToWString(key & ~NC::Key::Shift);
266 else if (key == NC::Key::Space)
267 result += L"Space";
268 else if (key == NC::Key::Backspace)
269 result += L"Backspace";
270 else if (key == NC::Key::Insert)
271 result += L"Insert";
272 else if (key == NC::Key::Delete)
273 result += L"Delete";
274 else if (key == NC::Key::Home)
275 result += L"Home";
276 else if (key == NC::Key::End)
277 result += L"End";
278 else if (key == NC::Key::PageUp)
279 result += L"PageUp";
280 else if (key == NC::Key::PageDown)
281 result += L"PageDown";
282 else if (key == NC::Key::Up)
283 result += L"Up";
284 else if (key == NC::Key::Down)
285 result += L"Down";
286 else if (key == NC::Key::Left)
287 result += L"Left";
288 else if (key == NC::Key::Right)
289 result += L"Right";
290 else if (key >= NC::Key::F1 && key <= NC::Key::F9)
292 result += L"F";
293 result += '1' + (key - NC::Key::F1);
295 else if (key >= NC::Key::F10 && key <= NC::Key::F12)
297 result += L"F1";
298 result += '0' + (key - NC::Key::F10);
300 else
301 result += std::wstring(1, key);
303 return result;
306 bool BindingsConfiguration::read(const std::string &file)
308 enum class InProgress { None, Command, Key };
310 bool result = true;
312 std::ifstream f(file);
313 if (!f.is_open())
314 return result;
316 // shared variables
317 InProgress in_progress = InProgress::None;
318 size_t line_no = 0;
319 std::string line;
320 Binding::ActionChain actions;
322 // def_key specific variables
323 NC::Key::Type key = NC::Key::None;
324 std::string strkey;
326 // def_command specific variables
327 bool cmd_immediate = false;
328 std::string cmd_name;
330 auto error = [&]() -> std::ostream & {
331 std::cerr << file << ":" << line_no << ": error: ";
332 in_progress = InProgress::None;
333 result = false;
334 return std::cerr;
337 auto bind_in_progress = [&]() -> bool {
338 if (in_progress == InProgress::Command)
340 if (!actions.empty())
342 m_commands.insert(std::make_pair(cmd_name, Command(std::move(actions), cmd_immediate)));
343 actions.clear();
344 return true;
346 else
348 error() << "definition of command '" << cmd_name << "' cannot be empty\n";
349 return false;
352 else if (in_progress == InProgress::Key)
354 if (!actions.empty())
356 bind(key, actions);
357 actions.clear();
358 return true;
360 else
362 error() << "definition of key '" << strkey << "' cannot be empty\n";
363 return false;
366 return true;
369 const char def_command[] = "def_command";
370 const char def_key[] = "def_key";
372 while (!f.eof() && ++line_no)
374 getline(f, line);
375 if (line.empty() || line[0] == '#')
376 continue;
378 // beginning of command definition
379 if (!line.compare(0, const_strlen(def_command), def_command))
381 if (!bind_in_progress())
382 break;
383 in_progress = InProgress::Command;
384 cmd_name = getEnclosedString(line, '"', '"', 0);
385 if (cmd_name.empty())
387 error() << "command must have non-empty name\n";
388 break;
390 if (m_commands.find(cmd_name) != m_commands.end())
392 error() << "redefinition of command '" << cmd_name << "'\n";
393 break;
395 std::string cmd_type = getEnclosedString(line, '[', ']', 0);
396 if (cmd_type == "immediate")
397 cmd_immediate = true;
398 else if (cmd_type == "deferred")
399 cmd_immediate = false;
400 else
402 error() << "invalid type of command: '" << cmd_type << "'\n";
403 break;
406 // beginning of key definition
407 else if (!line.compare(0, const_strlen(def_key), def_key))
409 if (!bind_in_progress())
410 break;
411 in_progress = InProgress::Key;
412 strkey = getEnclosedString(line, '"', '"', 0);
413 key = stringToKey(strkey);
414 if (key == NC::Key::None)
416 error() << "invalid key: '" << strkey << "'\n";
417 break;
420 else if (isspace(line[0])) // name of action to be bound
422 boost::trim(line);
423 auto action = parseActionLine(line, error);
424 if (action)
425 actions.push_back(action);
426 else
428 error() << "unknown action: '" << line << "'\n";
429 break;
432 else
434 error() << "invalid line: '" << line << "'\n";
435 break;
438 bind_in_progress();
439 f.close();
440 return result;
443 void BindingsConfiguration::generateDefaults()
445 NC::Key::Type k = NC::Key::None;
446 if (notBound(k = stringToKey("mouse")))
447 bind(k, Actions::Type::MouseEvent);
448 if (notBound(k = stringToKey("up")))
449 bind(k, Actions::Type::ScrollUp);
450 if (notBound(k = stringToKey("down")))
451 bind(k, Actions::Type::ScrollDown);
452 if (notBound(k = stringToKey("[")))
453 bind(k, Actions::Type::ScrollUpAlbum);
454 if (notBound(k = stringToKey("]")))
455 bind(k, Actions::Type::ScrollDownAlbum);
456 if (notBound(k = stringToKey("{")))
457 bind(k, Actions::Type::ScrollUpArtist);
458 if (notBound(k = stringToKey("}")))
459 bind(k, Actions::Type::ScrollDownArtist);
460 if (notBound(k = stringToKey("page_up")))
461 bind(k, Actions::Type::PageUp);
462 if (notBound(k = stringToKey("page_down")))
463 bind(k, Actions::Type::PageDown);
464 if (notBound(k = stringToKey("home")))
465 bind(k, Actions::Type::MoveHome);
466 if (notBound(k = stringToKey("end")))
467 bind(k, Actions::Type::MoveEnd);
468 if (notBound(k = stringToKey("insert")))
469 bind(k, Actions::Type::SelectItem);
470 if (notBound(k = stringToKey("space")))
471 bind(k, Actions::Type::PressSpace);
472 if (notBound(k = stringToKey("enter")))
473 bind(k, Actions::Type::PressEnter);
474 if (notBound(k = stringToKey("delete")))
476 bind(k, Actions::Type::DeletePlaylistItems);
477 bind(k, Actions::Type::DeleteBrowserItems);
478 bind(k, Actions::Type::DeleteStoredPlaylist);
480 if (notBound(k = stringToKey("right")))
482 bind(k, Actions::Type::NextColumn);
483 bind(k, Actions::Type::SlaveScreen);
484 bind(k, Actions::Type::VolumeUp);
486 if (notBound(k = stringToKey("+")))
487 bind(k, Actions::Type::VolumeUp);
488 if (notBound(k = stringToKey("left")))
490 bind(k, Actions::Type::PreviousColumn);
491 bind(k, Actions::Type::MasterScreen);
492 bind(k, Actions::Type::VolumeDown);
494 if (notBound(k = stringToKey("-")))
495 bind(k, Actions::Type::VolumeDown);
496 if (notBound(k = stringToKey(":")))
497 bind(k, Actions::Type::ExecuteCommand);
498 if (notBound(k = stringToKey("tab")))
499 bind(k, Actions::Type::NextScreen);
500 if (notBound(k = stringToKey("shift_tab")))
501 bind(k, Actions::Type::PreviousScreen);
502 if (notBound(k = stringToKey("f1")))
503 bind(k, Actions::Type::ShowHelp);
504 if (notBound(k = stringToKey("1")))
505 bind(k, Actions::Type::ShowPlaylist);
506 if (notBound(k = stringToKey("2")))
508 bind(k, Actions::Type::ShowBrowser);
509 bind(k, Actions::Type::ChangeBrowseMode);
511 if (notBound(k = stringToKey("3")))
513 bind(k, Actions::Type::ShowSearchEngine);
514 bind(k, Actions::Type::ResetSearchEngine);
516 if (notBound(k = stringToKey("4")))
518 bind(k, Actions::Type::ShowMediaLibrary);
519 bind(k, Actions::Type::ToggleMediaLibraryColumnsMode);
521 if (notBound(k = stringToKey("5")))
522 bind(k, Actions::Type::ShowPlaylistEditor);
523 if (notBound(k = stringToKey("6")))
524 bind(k, Actions::Type::ShowTagEditor);
525 if (notBound(k = stringToKey("7")))
526 bind(k, Actions::Type::ShowOutputs);
527 if (notBound(k = stringToKey("8")))
528 bind(k, Actions::Type::ShowVisualizer);
529 if (notBound(k = stringToKey("=")))
530 bind(k, Actions::Type::ShowClock);
531 if (notBound(k = stringToKey("@")))
532 bind(k, Actions::Type::ShowServerInfo);
533 if (notBound(k = stringToKey("s")))
534 bind(k, Actions::Type::Stop);
535 if (notBound(k = stringToKey("p")))
536 bind(k, Actions::Type::Pause);
537 if (notBound(k = stringToKey(">")))
538 bind(k, Actions::Type::Next);
539 if (notBound(k = stringToKey("<")))
540 bind(k, Actions::Type::Previous);
541 if (notBound(k = stringToKey("ctrl_h")))
543 bind(k, Actions::Type::JumpToParentDirectory);
544 bind(k, Actions::Type::ReplaySong);
546 if (notBound(k = stringToKey("backspace")))
548 bind(k, Actions::Type::JumpToParentDirectory);
549 bind(k, Actions::Type::ReplaySong);
551 if (notBound(k = stringToKey("f")))
552 bind(k, Actions::Type::SeekForward);
553 if (notBound(k = stringToKey("b")))
554 bind(k, Actions::Type::SeekBackward);
555 if (notBound(k = stringToKey("r")))
556 bind(k, Actions::Type::ToggleRepeat);
557 if (notBound(k = stringToKey("z")))
558 bind(k, Actions::Type::ToggleRandom);
559 if (notBound(k = stringToKey("y")))
561 bind(k, Actions::Type::SaveTagChanges);
562 bind(k, Actions::Type::StartSearching);
563 bind(k, Actions::Type::ToggleSingle);
565 if (notBound(k = stringToKey("R")))
566 bind(k, Actions::Type::ToggleConsume);
567 if (notBound(k = stringToKey("Y")))
568 bind(k, Actions::Type::ToggleReplayGainMode);
569 if (notBound(k = stringToKey("T")))
570 bind(k, Actions::Type::ToggleAddMode);
571 if (notBound(k = stringToKey("|")))
572 bind(k, Actions::Type::ToggleMouse);
573 if (notBound(k = stringToKey("#")))
574 bind(k, Actions::Type::ToggleBitrateVisibility);
575 if (notBound(k = stringToKey("Z")))
576 bind(k, Actions::Type::Shuffle);
577 if (notBound(k = stringToKey("x")))
578 bind(k, Actions::Type::ToggleCrossfade);
579 if (notBound(k = stringToKey("X")))
580 bind(k, Actions::Type::SetCrossfade);
581 if (notBound(k = stringToKey("u")))
582 bind(k, Actions::Type::UpdateDatabase);
583 if (notBound(k = stringToKey("ctrl_v")))
584 bind(k, Actions::Type::SortPlaylist);
585 if (notBound(k = stringToKey("ctrl_r")))
586 bind(k, Actions::Type::ReversePlaylist);
587 if (notBound(k = stringToKey("/")))
589 bind(k, Actions::Type::Find);
590 bind(k, Actions::Type::FindItemForward);
592 if (notBound(k = stringToKey("?")))
594 bind(k, Actions::Type::Find);
595 bind(k, Actions::Type::FindItemBackward);
597 if (notBound(k = stringToKey(".")))
598 bind(k, Actions::Type::NextFoundItem);
599 if (notBound(k = stringToKey(",")))
600 bind(k, Actions::Type::PreviousFoundItem);
601 if (notBound(k = stringToKey("w")))
602 bind(k, Actions::Type::ToggleFindMode);
603 if (notBound(k = stringToKey("e")))
605 bind(k, Actions::Type::EditSong);
606 bind(k, Actions::Type::EditLibraryTag);
607 bind(k, Actions::Type::EditLibraryAlbum);
608 bind(k, Actions::Type::EditDirectoryName);
609 bind(k, Actions::Type::EditPlaylistName);
610 bind(k, Actions::Type::EditLyrics);
612 if (notBound(k = stringToKey("i")))
613 bind(k, Actions::Type::ShowSongInfo);
614 if (notBound(k = stringToKey("I")))
615 bind(k, Actions::Type::ShowArtistInfo);
616 if (notBound(k = stringToKey("g")))
617 bind(k, Actions::Type::JumpToPositionInSong);
618 if (notBound(k = stringToKey("l")))
619 bind(k, Actions::Type::ShowLyrics);
620 if (notBound(k = stringToKey("v")))
621 bind(k, Actions::Type::ReverseSelection);
622 if (notBound(k = stringToKey("V")))
623 bind(k, Actions::Type::RemoveSelection);
624 if (notBound(k = stringToKey("B")))
625 bind(k, Actions::Type::SelectAlbum);
626 if (notBound(k = stringToKey("a")))
627 bind(k, Actions::Type::AddSelectedItems);
628 if (notBound(k = stringToKey("c")))
630 bind(k, Actions::Type::ClearPlaylist);
631 bind(k, Actions::Type::ClearMainPlaylist);
633 if (notBound(k = stringToKey("C")))
635 bind(k, Actions::Type::CropPlaylist);
636 bind(k, Actions::Type::CropMainPlaylist);
638 if (notBound(k = stringToKey("m")))
640 bind(k, Actions::Type::MoveSortOrderUp);
641 bind(k, Actions::Type::MoveSelectedItemsUp);
642 bind(k, Actions::Type::ToggleMediaLibrarySortMode);
643 bind(k, Actions::Type::SetVisualizerSampleMultiplier);
645 if (notBound(k = stringToKey("n")))
647 bind(k, Actions::Type::MoveSortOrderDown);
648 bind(k, Actions::Type::MoveSelectedItemsDown);
650 if (notBound(k = stringToKey("M")))
651 bind(k, Actions::Type::MoveSelectedItemsTo);
652 if (notBound(k = stringToKey("A")))
653 bind(k, Actions::Type::Add);
654 if (notBound(k = stringToKey("S")))
655 bind(k, Actions::Type::SavePlaylist);
656 if (notBound(k = stringToKey("o")))
657 bind(k, Actions::Type::JumpToPlayingSong);
658 if (notBound(k = stringToKey("G")))
660 bind(k, Actions::Type::JumpToBrowser);
661 bind(k, Actions::Type::JumpToPlaylistEditor);
663 if (notBound(k = stringToKey("~")))
664 bind(k, Actions::Type::JumpToMediaLibrary);
665 if (notBound(k = stringToKey("E")))
666 bind(k, Actions::Type::JumpToTagEditor);
667 if (notBound(k = stringToKey("U")))
668 bind(k, Actions::Type::TogglePlayingSongCentering);
669 if (notBound(k = stringToKey("P")))
670 bind(k, Actions::Type::ToggleDisplayMode);
671 if (notBound(k = stringToKey("\\")))
672 bind(k, Actions::Type::ToggleInterface);
673 if (notBound(k = stringToKey("!")))
674 bind(k, Actions::Type::ToggleSeparatorsBetweenAlbums);
675 if (notBound(k = stringToKey("L")))
676 bind(k, Actions::Type::ToggleLyricsFetcher);
677 if (notBound(k = stringToKey("F")))
678 bind(k, Actions::Type::ToggleFetchingLyricsInBackground);
679 if (notBound(k = stringToKey("ctrl_l")))
680 bind(k, Actions::Type::ToggleScreenLock);
681 if (notBound(k = stringToKey("`")))
683 bind(k, Actions::Type::ToggleBrowserSortMode);
684 bind(k, Actions::Type::ToggleLibraryTagType);
685 bind(k, Actions::Type::RefetchLyrics);
686 bind(k, Actions::Type::AddRandomItems);
688 if (notBound(k = stringToKey("ctrl_p")))
689 bind(k, Actions::Type::SetSelectedItemsPriority);
690 if (notBound(k = stringToKey("q")))
691 bind(k, Actions::Type::Quit);
693 if (notBound(k = stringToKey("-")))
694 bind(k, Actions::Type::VolumeDown);
697 const Command *BindingsConfiguration::findCommand(const std::string &name)
699 const Command *ptr = nullptr;
700 auto it = m_commands.find(name);
701 if (it != m_commands.end())
702 ptr = &it->second;
703 return ptr;
706 BindingsConfiguration::BindingIteratorPair BindingsConfiguration::get(const NC::Key::Type &k)
708 std::pair<BindingIterator, BindingIterator> result;
709 auto it = m_bindings.find(k);
710 if (it != m_bindings.end()) {
711 result.first = it->second.begin();
712 result.second = it->second.end();
713 } else {
714 auto list_end = m_bindings.begin()->second.end();
715 result.first = list_end;
716 result.second = list_end;
718 return result;