keys: implement support for a few macro utilities
This commit is contained in:
@@ -59,6 +59,8 @@ struct Action
|
|||||||
const char *Name() const { return itsName; }
|
const char *Name() const { return itsName; }
|
||||||
ActionType Type() const { return itsType; }
|
ActionType Type() const { return itsType; }
|
||||||
|
|
||||||
|
virtual bool canBeRun() const { return true; }
|
||||||
|
|
||||||
bool Execute()
|
bool Execute()
|
||||||
{
|
{
|
||||||
if (canBeRun())
|
if (canBeRun())
|
||||||
@@ -78,7 +80,7 @@ struct Action
|
|||||||
static bool AskYesNoQuestion(const std::string &question, void (*callback)());
|
static bool AskYesNoQuestion(const std::string &question, void (*callback)());
|
||||||
static bool isMPDMusicDirSet();
|
static bool isMPDMusicDirSet();
|
||||||
|
|
||||||
static Action *Get(ActionType);
|
static Action *Get(ActionType at);
|
||||||
static Action *Get(const std::string &name);
|
static Action *Get(const std::string &name);
|
||||||
|
|
||||||
static bool OriginalStatusbarVisibility;
|
static bool OriginalStatusbarVisibility;
|
||||||
@@ -91,7 +93,6 @@ struct Action
|
|||||||
static size_t FooterStartY;
|
static size_t FooterStartY;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual bool canBeRun() const { return true; }
|
|
||||||
virtual void Run() = 0;
|
virtual void Run() = 0;
|
||||||
|
|
||||||
static void Seek();
|
static void Seek();
|
||||||
|
|||||||
72
src/keys.cpp
72
src/keys.cpp
@@ -20,8 +20,8 @@
|
|||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include "global.h"
|
||||||
#include "keys.h"
|
#include "keys.h"
|
||||||
#include "utility/comparators.h"
|
|
||||||
#include "utility/string.h"
|
#include "utility/string.h"
|
||||||
|
|
||||||
KeyConfiguration Keys;
|
KeyConfiguration Keys;
|
||||||
@@ -30,7 +30,7 @@ Key Key::noOp = Key(ERR, NCurses);
|
|||||||
|
|
||||||
namespace {//
|
namespace {//
|
||||||
|
|
||||||
Key stringToKey(const std::string &s)
|
Key stringToSpecialKey(const std::string &s)
|
||||||
{
|
{
|
||||||
Key result = Key::noOp;
|
Key result = Key::noOp;
|
||||||
if (!s.compare("mouse"))
|
if (!s.compare("mouse"))
|
||||||
@@ -73,7 +73,13 @@ Key stringToKey(const std::string &s)
|
|||||||
result = Key(KEY_BACKSPACE, Key::NCurses);
|
result = Key(KEY_BACKSPACE, Key::NCurses);
|
||||||
else if (!s.compare("backspace_2"))
|
else if (!s.compare("backspace_2"))
|
||||||
result = Key(KEY_BACKSPACE_2, Key::Standard);
|
result = Key(KEY_BACKSPACE_2, Key::Standard);
|
||||||
else
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Key stringToKey(const std::string &s)
|
||||||
|
{
|
||||||
|
Key result = stringToSpecialKey(s);
|
||||||
|
if (result == Key::noOp)
|
||||||
{
|
{
|
||||||
std::wstring ws = ToWString(s);
|
std::wstring ws = ToWString(s);
|
||||||
if (ws.length() == 1)
|
if (ws.length() == 1)
|
||||||
@@ -82,6 +88,56 @@ Key stringToKey(const std::string &s)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename F>
|
||||||
|
Action *parseActionLine(const std::string &line, F error)
|
||||||
|
{
|
||||||
|
Action *result = 0;
|
||||||
|
size_t i = 0;
|
||||||
|
for (; i < line.size() && !isspace(line[i]); ++i) { }
|
||||||
|
if (i == line.size()) // only action name
|
||||||
|
result = Action::Get(line);
|
||||||
|
else // there is something else
|
||||||
|
{
|
||||||
|
std::string action_name = line.substr(0, i);
|
||||||
|
if (action_name == "push_character")
|
||||||
|
{
|
||||||
|
// push single character into input queue
|
||||||
|
std::string arg = getEnclosedString(line, '"', '"', 0);
|
||||||
|
Key k = stringToSpecialKey(arg);
|
||||||
|
if (k != Key::noOp)
|
||||||
|
result = new PushCharacters(&Global::wFooter, { k.getChar() });
|
||||||
|
else
|
||||||
|
error() << "invalid argument to function push_character: '" << arg << "'\n";
|
||||||
|
}
|
||||||
|
else if (action_name == "push_characters")
|
||||||
|
{
|
||||||
|
// push sequence of characters into input queue
|
||||||
|
std::string arg = getEnclosedString(line, '"', '"', 0);
|
||||||
|
if (!arg.empty())
|
||||||
|
{
|
||||||
|
std::vector<int> queue(arg.begin(), arg.end());
|
||||||
|
// if char is signed, cancel 1s from char -> int conversion
|
||||||
|
for (auto it = arg.begin(); it != arg.end(); ++it)
|
||||||
|
*it &= 0xff;
|
||||||
|
result = new PushCharacters(&Global::wFooter, std::move(queue));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
error() << "push_characters requires its argument to be non-empty";
|
||||||
|
}
|
||||||
|
else if (action_name == "require_runnable")
|
||||||
|
{
|
||||||
|
// require that given action is runnable
|
||||||
|
std::string arg = getEnclosedString(line, '"', '"', 0);
|
||||||
|
Action *action = Action::Get(arg);
|
||||||
|
if (action)
|
||||||
|
result = new RequireRunnable(action);
|
||||||
|
else
|
||||||
|
error() << "invalid action passed as argument to require_runnable: '" << arg << "'\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Key Key::read(NC::Window &w)
|
Key Key::read(NC::Window &w)
|
||||||
@@ -138,6 +194,7 @@ bool KeyConfiguration::read(const std::string &file)
|
|||||||
result = false;
|
result = false;
|
||||||
return std::cerr;
|
return std::cerr;
|
||||||
};
|
};
|
||||||
|
|
||||||
auto bind_key_def = [&]() -> bool {
|
auto bind_key_def = [&]() -> bool {
|
||||||
if (!actions.empty())
|
if (!actions.empty())
|
||||||
{
|
{
|
||||||
@@ -147,7 +204,7 @@ bool KeyConfiguration::read(const std::string &file)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
error() << "definition of key \"" << strkey << "\" cannot be empty.\n";
|
error() << "definition of key '" << strkey << "' cannot be empty.\n";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -170,19 +227,19 @@ bool KeyConfiguration::read(const std::string &file)
|
|||||||
key = stringToKey(strkey);
|
key = stringToKey(strkey);
|
||||||
if (key == Key::noOp)
|
if (key == Key::noOp)
|
||||||
{
|
{
|
||||||
error() << "invalid key: \"" << strkey << "\"\n";
|
error() << "invalid key: '" << strkey << "'\n";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (isspace(line[0])) // name of action to be bound
|
else if (isspace(line[0])) // name of action to be bound
|
||||||
{
|
{
|
||||||
trim(line);
|
trim(line);
|
||||||
Action *action = Action::Get(line);
|
Action *action = parseActionLine(line, error);
|
||||||
if (action)
|
if (action)
|
||||||
actions.push_back(action);
|
actions.push_back(action);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
error() << "unknown action: \"" << line << "\"\n";
|
error() << "unknown action: '" << line << "'\n";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -191,7 +248,6 @@ bool KeyConfiguration::read(const std::string &file)
|
|||||||
bind_key_def();
|
bind_key_def();
|
||||||
f.close();
|
f.close();
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void KeyConfiguration::generateBindings()
|
void KeyConfiguration::generateBindings()
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include "actions.h"
|
#include "actions.h"
|
||||||
|
#include "macro_utilities.h"
|
||||||
|
|
||||||
/// Key for binding actions to it. Supports non-ascii characters.
|
/// Key for binding actions to it. Supports non-ascii characters.
|
||||||
struct Key
|
struct Key
|
||||||
|
|||||||
@@ -18,34 +18,37 @@
|
|||||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
|
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _MACRO_UTILITIES
|
||||||
|
#define _MACRO_UTILITIES
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
#include "actions.h"
|
#include "actions.h"
|
||||||
|
|
||||||
struct PushCharacters : public Action
|
struct PushCharacters : public Action
|
||||||
{
|
{
|
||||||
template <typename Iterator> PushCharacters(Window **w, Iterator first, Iterator last) : Action(aMacroUtility, "")
|
PushCharacters(NC::Window **w, std::vector<int> &&queue)
|
||||||
{
|
: Action(aMacroUtility, ""), m_window(w), m_queue(queue) { }
|
||||||
construct(w, first, last);
|
|
||||||
|
virtual void Run() {
|
||||||
|
for (auto it = m_queue.begin(); it != m_queue.end(); ++it)
|
||||||
|
(*m_window)->pushChar(*it);
|
||||||
}
|
}
|
||||||
|
|
||||||
PushCharacters(Window **w, const std::initializer_list<int> &v) : Action(aMacroUtility, "")
|
private:
|
||||||
{
|
NC::Window **m_window;
|
||||||
construct(w, v.begin(), v.end());
|
std::vector<int> m_queue;
|
||||||
}
|
|
||||||
|
|
||||||
virtual void Run()
|
|
||||||
{
|
|
||||||
for (auto it = itsQueue.begin(); it != itsQueue.end(); ++it)
|
|
||||||
(*itsWindow)->PushChar(*it);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
template <typename Iterator> void construct(Window **w, Iterator first, Iterator last)
|
|
||||||
{
|
|
||||||
itsWindow = w;
|
|
||||||
for (; first != last; ++first)
|
|
||||||
itsQueue.push_back(*first);
|
|
||||||
}
|
|
||||||
|
|
||||||
Window **itsWindow;
|
|
||||||
std::vector<int> itsQueue;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct RequireRunnable : public Action
|
||||||
|
{
|
||||||
|
RequireRunnable(Action *action)
|
||||||
|
: Action(aMacroUtility, ""), m_action(action) { assert(action); }
|
||||||
|
|
||||||
|
virtual bool canBeRun() const { return m_action->canBeRun(); }
|
||||||
|
virtual void Run() { }
|
||||||
|
|
||||||
|
private:
|
||||||
|
Action *m_action;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // _MACRO_UTILITIES
|
||||||
|
|||||||
Reference in New Issue
Block a user