Skip to content

Commit dcac427

Browse files
committed
bindinds: add support for alt/ctrl/shift modifiers and escape key
1 parent e7b1529 commit dcac427

10 files changed

Lines changed: 431 additions & 293 deletions

File tree

NEWS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ ncmpcpp-0.7 (????-??-??)
2121
* Shuffle function now shuffles only selected range if selection in playlist is active.
2222
* NCurses terminal sequence escaping is no longer used as it's not accurate enough.
2323
* Selecting items no longer depends on space mode and is bound by default to Insert key.
24+
* Support for Alt, Ctrl and Shift modifiers as well as Escape key was added.
2425

2526
ncmpcpp-0.6.4 (2015-05-02)
2627

doc/bindings

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,11 @@
5151
## picked by ncmpcpp upon next call to readKey function.
5252
## Accepted values: mouse, up, down, page_up, page_down,
5353
## home, end, space, enter, insert, delete, left, right,
54-
## tab, shift_tab, ctrl_a, ctrl_b, ..., ctrl_z, ctrl_[,
55-
## ctrl_\\, ctrl_], ctrl_^, ctrl__, f1, f2, ..., f12,
56-
## backspace.
54+
## tab, ctrl_a, ctrl_b, ..., ctrl_z, ctrl_[, ctrl_\\,
55+
## ctrl_], ctrl_^, ctrl__, f1, f2, ..., f12, backspace.
56+
## In addition, most of these names can be prefixed with
57+
## alt_/ctrl_/shift_ to be recognized with the appropriate
58+
## modifier key(s).
5759
##
5860
## - push_characters "string" - pushes given string into
5961
## input queue.

src/actions.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2626,7 +2626,7 @@ void seek()
26262626
? (Timer-t).total_seconds()/2+Config.seek_time
26272627
: Config.seek_time;
26282628

2629-
Key input = Key::read(*wFooter);
2629+
NC::Key::Type input = readKey(*wFooter);
26302630
auto k = Bindings.get(input);
26312631
if (k.first == k.second || !k.first->isSingle()) // no single action?
26322632
break;

src/bindings.cpp

Lines changed: 153 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -28,77 +28,83 @@
2828

2929
BindingsConfiguration Bindings;
3030

31-
Key Key::noOp = Key(ERR, NCurses);
32-
3331
namespace {
3432

35-
Key stringToSpecialKey(const std::string &s)
33+
NC::Key::Type stringToKey(const std::string &s);
34+
35+
NC::Key::Type stringToSpecialKey(const std::string &s)
3636
{
37-
Key result = Key::noOp;
38-
if (!s.compare("mouse"))
39-
result = Key(NC::Key::Mouse, Key::NCurses);
37+
NC::Key::Type result = NC::Key::None;
38+
if (!s.compare(0, 5, "ctrl_") && s.length() == 6)
39+
{
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;
52+
}
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;
4063
else if (!s.compare("up"))
41-
result = Key(NC::Key::Up, Key::NCurses);
64+
result = NC::Key::Up;
4265
else if (!s.compare("down"))
43-
result = Key(NC::Key::Down, Key::NCurses);
66+
result = NC::Key::Down;
4467
else if (!s.compare("page_up"))
45-
result = Key(NC::Key::PageUp, Key::NCurses);
68+
result = NC::Key::PageUp;
4669
else if (!s.compare("page_down"))
47-
result = Key(NC::Key::PageDown, Key::NCurses);
70+
result = NC::Key::PageDown;
4871
else if (!s.compare("home"))
49-
result = Key(NC::Key::Home, Key::NCurses);
72+
result = NC::Key::Home;
5073
else if (!s.compare("end"))
51-
result = Key(NC::Key::End, Key::NCurses);
74+
result = NC::Key::End;
5275
else if (!s.compare("space"))
53-
result = Key(NC::Key::Space, Key::Standard);
76+
result = NC::Key::Space;
5477
else if (!s.compare("enter"))
55-
result = Key(NC::Key::Enter, Key::Standard);
78+
result = NC::Key::Enter;
5679
else if (!s.compare("insert"))
57-
result = Key(NC::Key::Insert, Key::NCurses);
80+
result = NC::Key::Insert;
5881
else if (!s.compare("delete"))
59-
result = Key(NC::Key::Delete, Key::NCurses);
82+
result = NC::Key::Delete;
6083
else if (!s.compare("left"))
61-
result = Key(NC::Key::Left, Key::NCurses);
84+
result = NC::Key::Left;
6285
else if (!s.compare("right"))
63-
result = Key(NC::Key::Right, Key::NCurses);
86+
result = NC::Key::Right;
6487
else if (!s.compare("tab"))
65-
result = Key(NC::Key::Tab, Key::Standard);
66-
else if (!s.compare("shift_tab"))
67-
result = Key(NC::Key::Shift | NC::Key::Tab, Key::NCurses);
68-
else if (!s.compare(0, 5, "ctrl_") && s.length() > 5)
69-
{
70-
if (s[5] >= 'a' && s[5] <= 'z')
71-
result = Key(NC::Key::Ctrl_A + (s[5] - 'a'), Key::Standard);
72-
else if (s[5] == '[')
73-
result = Key(NC::Key::Ctrl_LeftBracket, Key::Standard);
74-
else if (s[5] == '\\')
75-
result = Key(NC::Key::Ctrl_Backslash, Key::Standard);
76-
else if (s[5] == ']')
77-
result = Key(NC::Key::Ctrl_RightBracket, Key::Standard);
78-
else if (s[5] == '^')
79-
result = Key(NC::Key::Ctrl_Caret, Key::Standard);
80-
else if (s[5] == '_')
81-
result = Key(NC::Key::Ctrl_Underscore, Key::Standard);
82-
}
83-
else if (s.length() > 1 && s[0] == 'f')
88+
result = NC::Key::Tab;
89+
else if ((s.length() == 2 || s.length() == 3) && s[0] == 'f')
8490
{
8591
int n = atoi(s.c_str() + 1);
8692
if (n >= 1 && n <= 12)
87-
result = Key(NC::Key::F1 + n - 1, Key::NCurses);
93+
result = NC::Key::F1 + n - 1;
8894
}
8995
else if (!s.compare("backspace"))
90-
result = Key(NC::Key::Backspace, Key::Standard);
96+
result = NC::Key::Backspace;
9197
return result;
9298
}
9399

94-
Key stringToKey(const std::string &s)
100+
NC::Key::Type stringToKey(const std::string &s)
95101
{
96-
Key result = stringToSpecialKey(s);
97-
if (result == Key::noOp)
102+
NC::Key::Type result = stringToSpecialKey(s);
103+
if (result == NC::Key::None)
98104
{
99105
std::wstring ws = ToWString(s);
100106
if (ws.length() == 1)
101-
result = Key(ws[0], Key::Standard);
107+
result = ws[0];
102108
}
103109
return result;
104110
}
@@ -118,9 +124,9 @@ Actions::BaseAction *parseActionLine(const std::string &line, F error)
118124
{
119125
// push single character into input queue
120126
std::string arg = getEnclosedString(line, '"', '"', 0);
121-
Key k = stringToSpecialKey(arg);
122-
auto queue = std::vector<int>{ k.getChar() };
123-
if (k != Key::noOp)
127+
NC::Key::Type k = stringToSpecialKey(arg);
128+
auto queue = std::vector<NC::Key::Type>{ k };
129+
if (k != NC::Key::None)
124130
result = new Actions::PushCharacters(&Global::wFooter, std::move(queue));
125131
else
126132
error() << "invalid character passed to push_character: '" << arg << "'\n";
@@ -131,7 +137,7 @@ Actions::BaseAction *parseActionLine(const std::string &line, F error)
131137
std::string arg = getEnclosedString(line, '"', '"', 0);
132138
if (!arg.empty())
133139
{
134-
std::vector<int> queue(arg.begin(), arg.end());
140+
std::vector<NC::Key::Type> queue(arg.begin(), arg.end());
135141
// if char is signed, erase 1s from char -> int conversion
136142
for (auto it = arg.begin(); it != arg.end(); ++it)
137143
*it &= 0xff;
@@ -174,19 +180,26 @@ Actions::BaseAction *parseActionLine(const std::string &line, F error)
174180

175181
}
176182

177-
Key Key::read(NC::Window &w)
183+
NC::Key::Type readKey(NC::Window &w)
178184
{
179-
Key result = noOp;
185+
NC::Key::Type result = NC::Key::None;
180186
std::string tmp;
181-
int input;
187+
NC::Key::Type input;
188+
bool alt_pressed = false;
182189
while (true)
183190
{
184191
input = w.readKey();
185-
if (input == ERR)
192+
if (input == NC::Key::None)
186193
break;
187-
if (input > 255)
194+
if (input & NC::Key::Alt)
195+
{
196+
// Complete the key and reapply the mask at the end.
197+
alt_pressed = true;
198+
input &= ~NC::Key::Alt;
199+
}
200+
if (input > 255) // NC special character
188201
{
189-
result = Key(input, NCurses);
202+
result = input;
190203
break;
191204
}
192205
else
@@ -200,11 +213,93 @@ Key Key::read(NC::Window &w)
200213
break;
201214
else // character complete
202215
{
203-
result = Key(wc, Standard);
216+
result = wc;
204217
break;
205218
}
206219
}
207220
}
221+
if (alt_pressed)
222+
result |= NC::Key::Alt;
223+
return result;
224+
}
225+
226+
std::wstring keyToWString(const NC::Key::Type key)
227+
{
228+
std::wstring result;
229+
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)
237+
{
238+
result += L"Ctrl-";
239+
result += 'A' + (key - NC::Key::Ctrl_A);
240+
}
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)
252+
{
253+
result += L"Alt-";
254+
result += keyToWString(key & ~NC::Key::Alt);
255+
}
256+
else if (key & NC::Key::Ctrl)
257+
{
258+
result += L"Ctrl-";
259+
result += keyToWString(key & ~NC::Key::Ctrl);
260+
}
261+
else if (key & NC::Key::Shift)
262+
{
263+
result += L"Shift-";
264+
result += keyToWString(key & ~NC::Key::Shift);
265+
}
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)
291+
{
292+
result += L"F";
293+
result += '1' + (key - NC::Key::F1);
294+
}
295+
else if (key >= NC::Key::F10 && key <= NC::Key::F12)
296+
{
297+
result += L"F1";
298+
result += '0' + (key - NC::Key::F10);
299+
}
300+
else
301+
result += std::wstring(1, key);
302+
208303
return result;
209304
}
210305

@@ -225,7 +320,7 @@ bool BindingsConfiguration::read(const std::string &file)
225320
Binding::ActionChain actions;
226321

227322
// def_key specific variables
228-
Key key = Key::noOp;
323+
NC::Key::Type key = NC::Key::None;
229324
std::string strkey;
230325

231326
// def_command specific variables
@@ -316,7 +411,7 @@ bool BindingsConfiguration::read(const std::string &file)
316411
in_progress = InProgress::Key;
317412
strkey = getEnclosedString(line, '"', '"', 0);
318413
key = stringToKey(strkey);
319-
if (key == Key::noOp)
414+
if (key == NC::Key::None)
320415
{
321416
error() << "invalid key: '" << strkey << "'\n";
322417
break;
@@ -347,7 +442,7 @@ bool BindingsConfiguration::read(const std::string &file)
347442

348443
void BindingsConfiguration::generateDefaults()
349444
{
350-
Key k = Key::noOp;
445+
NC::Key::Type k = NC::Key::None;
351446
if (notBound(k = stringToKey("mouse")))
352447
bind(k, Actions::Type::MouseEvent);
353448
if (notBound(k = stringToKey("up")))
@@ -608,7 +703,7 @@ const Command *BindingsConfiguration::findCommand(const std::string &name)
608703
return ptr;
609704
}
610705

611-
BindingsConfiguration::BindingIteratorPair BindingsConfiguration::get(const Key &k)
706+
BindingsConfiguration::BindingIteratorPair BindingsConfiguration::get(const NC::Key::Type &k)
612707
{
613708
std::pair<BindingIterator, BindingIterator> result;
614709
auto it = m_bindings.find(k);

0 commit comments

Comments
 (0)