Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Joystick support! #23

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 76 additions & 22 deletions KeyConfig.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#include <string>
#include <map>
#include <set>
#include <fstream>

#include "KeyConfig.h"
Expand Down Expand Up @@ -86,9 +85,7 @@ string getKeyFromString(string line){
/* Returns a keymap consisting of the default
* keybinds specified with the -k option
*/
map<int, int> KeyConfig::buildDefaultKeymap(){
map<int,int> keymap;

void KeyConfig::buildDefaultKeymap(){
keymap['1'] = ACTION_DECREASE_SPEED;
keymap['2'] = ACTION_INCREASE_SPEED;
keymap['<'] = ACTION_REWIND;
Expand All @@ -106,28 +103,26 @@ map<int, int> KeyConfig::buildDefaultKeymap(){
keymap['d'] = ACTION_DECREASE_SUBTITLE_DELAY;
keymap['f'] = ACTION_INCREASE_SUBTITLE_DELAY;
keymap['q'] = ACTION_EXIT;
keymap[KEY_ESC] = ACTION_EXIT;
keymap[KEY_ESC_HEX] = ACTION_EXIT;
keymap['p'] = ACTION_PAUSE;
keymap[' '] = ACTION_PAUSE;
keymap['-'] = ACTION_DECREASE_VOLUME;
keymap['+'] = ACTION_INCREASE_VOLUME;
keymap['='] = ACTION_INCREASE_VOLUME;
keymap[KEY_LEFT] = ACTION_SEEK_BACK_SMALL;
keymap[KEY_RIGHT] = ACTION_SEEK_FORWARD_SMALL;
keymap[KEY_DOWN] = ACTION_SEEK_BACK_LARGE;
keymap[KEY_UP] = ACTION_SEEK_FORWARD_LARGE;
keymap[KEY_LEFT_HEX] = ACTION_SEEK_BACK_SMALL;
keymap[KEY_RIGHT_HEX] = ACTION_SEEK_FORWARD_SMALL;
keymap[KEY_DOWN_HEX] = ACTION_SEEK_BACK_LARGE;
keymap[KEY_UP_HEX] = ACTION_SEEK_FORWARD_LARGE;
keymap['v'] = ACTION_STEP;

return keymap;
}

/* Parses the supplied config file and turns it into a map object.
/* Parses the supplied config file and adds the values to the map objects.
* NOTE: Does not work with certain filepath shortcuts (e.g. ~ as user's home)
*/
map<int, int> KeyConfig::parseConfigFile(string filepath){
ifstream config_file(filepath.c_str());
map<int,int> keymap;
void KeyConfig::parseConfigFile(char* filepath){
ifstream config_file(filepath);
string line;
std::set<std::string> jsset;

while(getline(config_file, line)){
string str_action = getActionFromString(line);
Expand All @@ -136,27 +131,86 @@ map<int, int> KeyConfig::parseConfigFile(string filepath){
if(str_action != "" && key != "" && str_action[0] != '#'){
int key_action = convertStringToAction(str_action);
if(key.substr(0,4) == "left"){
keymap[KEY_LEFT] = key_action;
keymap[KEY_LEFT_HEX] = key_action;
}
else if(key.substr(0,5) == "right"){
keymap[KEY_RIGHT] = key_action;
keymap[KEY_RIGHT_HEX] = key_action;
}
else if(key.substr(0,2) == "up"){
keymap[KEY_UP] = key_action;
keymap[KEY_UP_HEX] = key_action;
}
else if(key.substr(0,4) == "down"){
keymap[KEY_DOWN] = key_action;
keymap[KEY_DOWN_HEX] = key_action;
}
else if(key.substr(0,3) == "esc"){
keymap[KEY_ESC] = key_action;
keymap[KEY_ESC_HEX] = key_action;
}
else if(key.substr(0,3) == "hex"){
const char *hex = key.substr(4).c_str();
if (hex)
keymap[strtoul(hex,0,0)] = key_action;
}
else if(key.substr(0,3) == "js "){
string js_key = key.substr(3);
jsmap[js_key] = key_action;
string js_path = js_key.substr(0, js_key.find(' '));
jsset.insert(js_path);
}
else keymap[key[0]] = key_action;
}
}
return keymap;

//Turn the set of joysticks into a vector because it is more convenient to work with later
joysticks.assign(jsset.begin(), jsset.end());
}

/* Default constructor that builds the default keymap */
KeyConfig::KeyConfig(){
buildDefaultKeymap();
num_joysticks = 0;
}

/* Constructor that takes a path to a config file. Falls back on the
* default keymap in case of trouble.
*/
KeyConfig::KeyConfig(char* filepath){
parseConfigFile(filepath);

// true if config file is empty or there was an error reading it
if(keymap.size() + jsmap.size() < 1){
buildDefaultKeymap();
num_joysticks = 0;
}
else if(jsmap.size() > 0){
num_joysticks = joysticks.size();
}
}

/* Finds the action associated with the provided keyboard event */
int KeyConfig::getAction(int key_pressed){
return keymap[key_pressed];
}

/* Finds the action associated with the provided joystick/joystick event */
int KeyConfig::getAction(std::string joystick, struct js_event *jse){
//value of 0 is either a button release or a dead joystick
if(jse->value == 0)
return -1;

std::string key_string = joystick;

if((jse->type & ~JS_EVENT_INIT) == JS_EVENT_BUTTON){
key_string.append(" b");
key_string.append(to_string(jse->number));
}
else if((jse->type & ~JS_EVENT_INIT) == JS_EVENT_AXIS){
key_string.append(" a");
key_string.append(to_string(jse->number));

if(jse->value > 0)
key_string.append("+");
else if(jse->value < 0)
key_string.append("-");
}
return jsmap[key_string];
}
32 changes: 25 additions & 7 deletions KeyConfig.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
#include <map>
#include <vector>
#include <string>
#include <sys/types.h>
#include <linux/joystick.h>

class KeyConfig{

Expand Down Expand Up @@ -30,12 +33,27 @@ class KeyConfig{
ACTION_STEP
};

#define KEY_LEFT 0x5b44
#define KEY_RIGHT 0x5b43
#define KEY_UP 0x5b41
#define KEY_DOWN 0x5b42
#define KEY_ESC 27
#define KEY_LEFT_HEX 0x5b44
#define KEY_RIGHT_HEX 0x5b43
#define KEY_UP_HEX 0x5b41
#define KEY_DOWN_HEX 0x5b42
#define KEY_ESC_HEX 27

static std::map<int, int> buildDefaultKeymap();
static std::map<int, int> parseConfigFile(std::string filepath);
KeyConfig();
KeyConfig(char*);

int getAction(int key);
int getAction(std::string joystick, struct js_event *jse);

std::vector<std::string> getJoysticks(){ return joysticks; }
int getNumJoysticks(){ return joysticks.size(); }

private:
std::map<int, int> keymap;
std::map<std::string, int> jsmap;
std::vector<std::string> joysticks;
int num_joysticks;

void buildDefaultKeymap();
void parseConfigFile(char* filepath);
};
24 changes: 23 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,8 @@ While playing you can use the following keys to control omxplayer:
Key Config Syntax
-----------------

A key config file is a series of rules of the form [action]:[key]. Multiple keys can be bound
A key config file is a series of rules of the form [action]:[key]. Keyboard input
is supported as well as input from multiple joysticks. Multiple keys can be bound
to the same action, and comments are supported by adding a # in front of the line.
The list of valid [action]s roughly corresponds to the list of default key bindings above and are:

Expand Down Expand Up @@ -146,19 +147,40 @@ The list of valid [action]s roughly corresponds to the list of default key bindi
STEP

Valid [key]s include all alpha-numeric characters and most symbols, as well as:

left
right
up
down
esc
hex [keycode]

Joystick inputs are defined of the form:

js /path/to/js a[number][+-]
js /path/to/js b[number]

Where /path/to/js is the path to the joystick (usually something like /dev/input/js0),
a denotes an axis is being bound, b denotes a button being bound, [number] is the
number of the joystick axis or button, and [+-] designates which direction (positive or
negative) of motion on the axis will trigger the event. Joystick axis and button
numbers can easily be discovered by using jstest. You do not need to declare the
joysticks anywhere in the file; the parser will build the list of joysticks
from the ones it finds that have buttons/axes bound.

For example:

#Keyboard bindings
EXIT:esc
PAUSE:p
#Note that this next line has a space after the :
PAUSE:
REWIND:left
SEEK_FORWARD_SMALL:hex 0x4f43
EXIT:q

#Joystick bindings
SEEK_FORWARD_SMALL:js /dev/input/js0 a0+
SEEK_BACK_SMALL:js /dev/input/js0 a0-
EXIT:js /dev/input/js0 b6
PAUSE:js /dev/input/js1 b0
43 changes: 40 additions & 3 deletions omxplayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -558,6 +558,8 @@ int main(int argc, char *argv[])
float video_queue_size = 0.0;
float m_threshold = 0.1f; // amount of audio/video required to come out of buffering
TV_DISPLAY_STATE_T tv_state;
int *joystick_fds = 0;
vector<std::string> joysticks;

const int font_opt = 0x100;
const int italic_font_opt = 0x201;
Expand Down Expand Up @@ -622,7 +624,7 @@ int main(int argc, char *argv[])
std::string mode;

//Build default keymap just in case the --key-config option isn't used
map<int,int> keymap = KeyConfig::buildDefaultKeymap();
KeyConfig * keymap = new KeyConfig;

while ((c = getopt_long(argc, argv, "wihvkn:l:o:cslbpd3:yzt:rg", longopts, NULL)) != -1)
{
Expand Down Expand Up @@ -747,7 +749,8 @@ int main(int argc, char *argv[])
m_blank_background = true;
break;
case key_config_opt:
keymap = KeyConfig::parseConfigFile(optarg);
keymap = new KeyConfig(optarg);
joysticks = keymap->getJoysticks();
break;
case 0:
break;
Expand Down Expand Up @@ -974,10 +977,27 @@ int main(int argc, char *argv[])

PrintSubtitleInfo();

// Open joystick file descriptors
if(keymap->getNumJoysticks() > 0){
joystick_fds = (int*) malloc(keymap->getNumJoysticks() * sizeof(int));
for(unsigned int i=0; i < joysticks.size(); i++){
joystick_fds[i] = open(joysticks[i].c_str(), O_RDONLY | O_NONBLOCK);
}
}

while(!m_stop)
{
int ch[8];
int chnum = 0;
struct js_event jse;
memset(&jse, 0, sizeof(struct js_event));

int num_actions = 1 + keymap->getNumJoysticks();
int current_actions[num_actions]; // 0 = stdin, 1-n are joysticks

for(int i = 0; i < num_actions; i++){
current_actions[i] = -1;
}

if(g_abort)
goto do_exit;
Expand All @@ -988,7 +1008,20 @@ int main(int argc, char *argv[])

if (chnum > 1) ch[0] = ch[chnum - 1] | (ch[chnum - 2] << 8);

switch(keymap[ch[0]])
current_actions[0] = keymap->getAction(ch[0]);

// skip stdin
for(int i=0; i < num_actions-1; i++){
if(joystick_fds[i] > 0){
int bytes = read(joystick_fds[i], &jse, sizeof(struct js_event));
if(bytes == sizeof(struct js_event)){
current_actions[i+1] = keymap->getAction(joysticks[i], &jse);
}
}
}

for(int i=0; i < num_actions; i++){
switch(current_actions[i])
{
case KeyConfig::ACTION_SHOW_INFO:
m_tv_show_info = !m_tv_show_info;
Expand Down Expand Up @@ -1187,6 +1220,7 @@ int main(int argc, char *argv[])
default:
break;
}
}

if(m_seek_flush || m_incr != 0)
{
Expand Down Expand Up @@ -1448,6 +1482,9 @@ int main(int argc, char *argv[])
g_OMX.Deinitialize();
g_RBP.Deinitialize();

free(joystick_fds);
delete keymap;

printf("have a nice day ;)\n");
return 1;
}