Moved CycleKeySequence into separate class instead of having it bundled with CycleKeyButtonEvent, removed CycleKeyRefButtonEvent, stuck issues when multiple buttons are pressed is still present

This commit is contained in:
Ingo Ruhnke 2011-07-07 18:09:58 +02:00
parent adf08a7fff
commit bf0ecd49a2
7 changed files with 138 additions and 278 deletions

9
TODO
View file

@ -70,6 +70,15 @@ Stuff to do before 0.8.1 release:
* cycle-key is incomplete, should have additional mode that allows
next/prev without sending events, also has issues with stuck buttons
when multiple keys are pressed
-> only one key should be allowed to be pressed, last one will always be released (still fishy)
-> separate last and curr key to allow toggle without press
-> have each ButtonEvent be responsible to release the keys it
pressed? -> tricky, as it doesn't know those right now
-> need a time delay before button is actually send for situations
where sending the key is expensive (weapon switching in game might be slow)
* don't compile tests by default

View file

@ -11,4 +11,8 @@ Y1=ABS_Y
RB=cycle-key-named:foo:JS_1:JS_2:JS_3:JS_4
LB=cycle-key-ref:foo:backward
X=cycle-key-ref:foo:backward:0
B=cycle-key-ref:foo:forward:0
A=cycle-key-ref:foo:none:1
# EOF #

View file

@ -29,7 +29,6 @@
#include "buttonevent/abs_button_event_handler.hpp"
#include "buttonevent/cycle_key_button_event_handler.hpp"
#include "buttonevent/cycle_key_ref_button_event_handler.hpp"
#include "buttonevent/exec_button_event_handler.hpp"
#include "buttonevent/key_button_event_handler.hpp"
#include "buttonevent/macro_button_event_handler.hpp"
@ -109,7 +108,7 @@ ButtonEvent::from_string(const std::string& str, const std::string& directory)
}
else if (token == "cycle-key-ref")
{
return ButtonEvent::create(CycleKeyRefButtonEventHandler::from_string(rest));
return ButtonEvent::create(CycleKeyButtonEventHandler::from_string_ref(rest));
}
else if (token == "exec")
{

View file

@ -20,12 +20,36 @@
#include <boost/tokenizer.hpp>
#include <stdexcept>
#include <memory>
#include "ui_event_sequence.hpp"
#include "raise_exception.hpp"
std::map<std::string, CycleKeyButtonEventHandler*> CycleKeyButtonEventHandler::s_lookup_table;
std::map<std::string, CycleKeySequencePtr> CycleKeyButtonEventHandler::s_lookup_table;
namespace {
CycleKeyButtonEventHandler::Direction
direction_from_string(const std::string& value)
{
if (value == "forward")
{
return CycleKeyButtonEventHandler::kForward;
}
else if (value == "backward")
{
return CycleKeyButtonEventHandler::kBackward;
}
else if (value == "none")
{
return CycleKeyButtonEventHandler::kNone;
}
else
{
raise_exception(std::runtime_error, "allowed values are 'forward', 'backward' and 'none'");
}
}
} // namespace
CycleKeyButtonEventHandler*
CycleKeyButtonEventHandler::from_string(const std::string& value)
@ -46,16 +70,9 @@ CycleKeyButtonEventHandler::from_string_named(const std::string& value)
}
else
{
Keys keys;
std::string name = args[0];
for(std::vector<std::string>::const_iterator i = args.begin()+1; i != args.end(); ++i)
{
keys.push_back(UIEventSequence::from_string(*i));
}
CycleKeySequencePtr sequence = CycleKeySequence::from_range(args.begin()+1, args.end());
std::auto_ptr<CycleKeyButtonEventHandler> cycle(new CycleKeyButtonEventHandler(keys));
// if name is empty, don't put it in the lookup table
if (!name.empty())
{
@ -63,21 +80,52 @@ CycleKeyButtonEventHandler::from_string_named(const std::string& value)
{
raise_exception(std::runtime_error, "duplicate name entry");
}
s_lookup_table.insert(std::pair<std::string, CycleKeyButtonEventHandler*>(name, cycle.get()));
else
{
s_lookup_table.insert(std::pair<std::string, CycleKeySequencePtr>(name, sequence));
}
}
return cycle.release();
return new CycleKeyButtonEventHandler(sequence, kForward, true);
}
}
CycleKeyButtonEventHandler*
CycleKeyButtonEventHandler::from_string_ref(const std::string& value)
{
typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
tokenizer tokens(value, boost::char_separator<char>(":", "", boost::keep_empty_tokens));
std::vector<std::string> args(tokens.begin(), tokens.end());
if (args.size() > 0)
{
std::string name = args[0];
Direction direction = (args.size() > 1) ? direction_from_string(args[1]) : kBackward;
bool press = (args.size() > 2) ? boost::lexical_cast<bool>(args[2]) : true;
CycleKeySequencePtr cycle_sequence = CycleKeyButtonEventHandler::lookup(name);
if (!cycle_sequence)
{
raise_exception(std::runtime_error, "unknown cycle sequence: " << name);
}
else
{
return new CycleKeyButtonEventHandler(cycle_sequence, direction, press);
}
}
else
{
raise_exception(std::runtime_error, "need at least one arguments");
}
}
CycleKeySequencePtr
CycleKeyButtonEventHandler::lookup(const std::string& name)
{
std::map<std::string, CycleKeyButtonEventHandler*>::iterator it = s_lookup_table.find(name);
std::map<std::string, CycleKeySequencePtr>::iterator it = s_lookup_table.find(name);
if (it == s_lookup_table.end())
{
return 0;
return CycleKeySequencePtr();
}
else
{
@ -85,20 +133,20 @@ CycleKeyButtonEventHandler::lookup(const std::string& name)
}
}
CycleKeyButtonEventHandler::CycleKeyButtonEventHandler(const Keys& keys) :
m_keys(keys),
m_current_key(keys.size()-1)
CycleKeyButtonEventHandler::CycleKeyButtonEventHandler(CycleKeySequencePtr sequence,
Direction direction,
bool send_press) :
m_sequence(sequence),
m_direction(direction),
m_send_press(send_press)
{
assert(!keys.empty());
}
void
CycleKeyButtonEventHandler::init(UInput& uinput, int slot, bool extra_devices)
{
for(Keys::iterator i = m_keys.begin(); i != m_keys.end(); ++i)
{
i->init(uinput, slot, extra_devices);
}
// CycleKeySequence will make sure that init() is only called once
m_sequence->init(uinput, slot, extra_devices);
}
void
@ -106,52 +154,46 @@ CycleKeyButtonEventHandler::send(UInput& uinput, bool value)
{
if (value)
{
next_key();
send_only(uinput, value);
if (m_send_press && m_sequence->has_current_key())
{
m_sequence->send(uinput, value);
}
else
{
switch(m_direction)
{
case kBackward:
m_sequence->prev_key();
break;
case kForward:
m_sequence->next_key();
break;
case kNone:
break;
}
if (m_send_press)
{
m_sequence->send(uinput, value);
}
}
}
else
{
send_only(uinput, value);
if (m_send_press)
{
m_sequence->send(uinput, value);
}
}
}
void
CycleKeyButtonEventHandler::send_only(UInput& uinput, bool value)
{
m_keys[m_current_key].send(uinput, value);
}
void
CycleKeyButtonEventHandler::update(UInput& uinput, int msec_delta)
{
}
void
CycleKeyButtonEventHandler::next_key()
{
if (m_current_key >= static_cast<int>(m_keys.size())-1)
{
m_current_key = 0;
}
else
{
m_current_key += 1;
}
}
void
CycleKeyButtonEventHandler::prev_key()
{
if (m_current_key <= 0)
{
m_current_key = m_keys.size()-1;
}
else
{
m_current_key -= 1;
}
}
std::string
CycleKeyButtonEventHandler::str() const
{

View file

@ -24,33 +24,47 @@
#include "button_event.hpp"
#include "ui_event_sequence.hpp"
#include "buttonevent/cycle_key_sequence.hpp"
class CycleKeyButtonEventHandler : public ButtonEventHandler
{
private:
static std::map<std::string, CycleKeyButtonEventHandler*> s_lookup_table;
static std::map<std::string, CycleKeySequencePtr> s_lookup_table;
public:
static CycleKeyButtonEventHandler* from_string(const std::string& str);
static CycleKeyButtonEventHandler* from_string_named(const std::string& str);
static CycleKeyButtonEventHandler* lookup(const std::string& name);
/**
Syntax: "{direction}:{press}"
direction: can either be 'forward', 'backward', 'none' or an
integer, in the case of an integer, the pointer is moved to that key
press: a bool, true if a keypress is send,
false when only the current key should change
*/
static CycleKeyButtonEventHandler* from_string_ref(const std::string& value);
static CycleKeySequencePtr lookup(const std::string& name);
public:
enum Direction { kForward, kBackward, kNone };
private:
typedef std::vector<UIEventSequence> Keys;
Keys m_keys;
int m_current_key;
CycleKeySequencePtr m_sequence;
Direction m_direction;
bool m_send_press;
private:
CycleKeyButtonEventHandler(const Keys& keys);
CycleKeyButtonEventHandler(CycleKeySequencePtr sequence, Direction direction, bool send_press);
public:
void init(UInput& uinput, int slot, bool extra_devices);
void send(UInput& uinput, bool value);
void send_only(UInput& uinput, bool value);
void update(UInput& uinput, int msec_delta);
void next_key();
void prev_key();
std::string str() const;
private:

View file

@ -1,142 +0,0 @@
/*
** Xbox360 USB Gamepad Userspace Driver
** Copyright (C) 2011 Ingo Ruhnke <grumbel@gmx.de>
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "buttonevent/cycle_key_ref_button_event_handler.hpp"
#include <boost/tokenizer.hpp>
#include "buttonevent/cycle_key_button_event_handler.hpp"
#include "raise_exception.hpp"
namespace {
CycleKeyRefButtonEventHandler::Direction
direction_from_string(const std::string& value)
{
if (value == "forward")
{
return CycleKeyRefButtonEventHandler::kForward;
}
else if (value == "backward")
{
return CycleKeyRefButtonEventHandler::kBackward;
}
else if (value == "none")
{
return CycleKeyRefButtonEventHandler::kNone;
}
else
{
raise_exception(std::runtime_error, "allowed values are 'forward', 'backward' and 'none'");
}
}
} // namespace
CycleKeyRefButtonEventHandler*
CycleKeyRefButtonEventHandler::from_string(const std::string& value)
{
typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
tokenizer tokens(value, boost::char_separator<char>(":", "", boost::keep_empty_tokens));
std::vector<std::string> args(tokens.begin(), tokens.end());
if (args.size() > 0)
{
std::string name = args[0];
Direction direction = (args.size() > 1) ? direction_from_string(args[1]) : kBackward;
bool press = (args.size() > 2) ? boost::lexical_cast<bool>(args[2]) : true;
CycleKeyButtonEventHandler* cycle = CycleKeyButtonEventHandler::lookup(name);
if (!cycle)
{
raise_exception(std::runtime_error, "need at least one arguments");
}
else
{
return new CycleKeyRefButtonEventHandler(cycle, direction, press);
}
}
else
{
raise_exception(std::runtime_error, "need at least one arguments");
}
}
CycleKeyRefButtonEventHandler::CycleKeyRefButtonEventHandler(CycleKeyButtonEventHandler* button_handler,
Direction direction,
bool press) :
m_button_handler(button_handler),
m_direction(direction),
m_send_press(press)
{
// FIXME: m_button_handler is just a raw pointer without a well
// defined scope, bad idea, should use a boost::weak_ref<> instead
// or something like that
}
void
CycleKeyRefButtonEventHandler::init(UInput& uinput, int slot, bool extra_devices)
{
// nothing to do, as m_button_handler is doing all the work
}
void
CycleKeyRefButtonEventHandler::send(UInput& uinput, bool value)
{
if (value)
{
switch(m_direction)
{
case kBackward:
m_button_handler->prev_key();
break;
case kForward:
m_button_handler->next_key();
break;
case kNone:
break;
}
if (m_send_press)
{
m_button_handler->send_only(uinput, value);
}
}
else
{
if (m_send_press)
{
m_button_handler->send_only(uinput, value);
}
}
}
void
CycleKeyRefButtonEventHandler::update(UInput& uinput, int msec_delta)
{
}
std::string
CycleKeyRefButtonEventHandler::str() const
{
return "cycle-key-ref";
}
/* EOF */

View file

@ -1,66 +0,0 @@
/*
** Xbox360 USB Gamepad Userspace Driver
** Copyright (C) 2011 Ingo Ruhnke <grumbel@gmx.de>
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef HEADER_XBOXDRV_BUTTONEVENT_CYCLE_KEY_REF_BUTTON_EVENT_HANDLER_HPP
#define HEADER_XBOXDRV_BUTTONEVENT_CYCLE_KEY_REF_BUTTON_EVENT_HANDLER_HPP
#include "button_event.hpp"
class CycleKeyButtonEventHandler;
class CycleKeyRefButtonEventHandler : public ButtonEventHandler
{
public:
/**
Syntax: "{direction}:{press}"
direction: can either be 'forward', 'backward', 'none' or an
integer, in the case of an integer, the pointer is moved to that key
press: a bool, true if a keypress is send,
false when only the current key should change
*/
static CycleKeyRefButtonEventHandler* from_string(const std::string& value);
public:
enum Direction { kForward, kBackward, kNone };
public:
CycleKeyRefButtonEventHandler(CycleKeyButtonEventHandler* button_handler,
Direction direction,
bool press);
void init(UInput& uinput, int slot, bool extra_devices);
void send(UInput& uinput, bool value);
void update(UInput& uinput, int msec_delta);
std::string str() const;
private:
CycleKeyButtonEventHandler* m_button_handler;
Direction m_direction;
bool m_send_press;
private:
CycleKeyRefButtonEventHandler(const CycleKeyRefButtonEventHandler&);
CycleKeyRefButtonEventHandler& operator=(const CycleKeyRefButtonEventHandler&);
};
#endif
/* EOF */