WIP: Support keyboard input device

This commit is contained in:
Ilari Liusvaara 2014-09-14 12:08:44 +03:00
parent 425e1fc097
commit 6736ecc285
8 changed files with 260 additions and 38 deletions

View file

@ -191,6 +191,7 @@ struct port_controller_button
TYPE_RAXIS, //Relative Axis (mouse).
TYPE_TAXIS, //Throttle Axis (does not pair).
TYPE_LIGHTGUN, //Lightgun axis.
TYPE_KEYBOARD, //Keyboard. The names are translated via namemap.
};
enum _type type;
char32_t symbol;
@ -216,6 +217,8 @@ struct port_controller
std::string cclass; //Controller class.
std::string type; //Controller type.
std::vector<port_controller_button> buttons; //Buttons.
std::map<signed, std::u32string> namemap; //Button translation map.
unsigned reserved_idx; //Number of extra reserved indices.
/**
* Count number of analog actions on this controller.
*/
@ -233,6 +236,15 @@ struct port_controller
return NULL;
return &buttons[i];
}
/**
* Access specified entry in namemap. Returns '???' if unknown.
*/
std::u32string get_namemap_entry(short entry) const
{
if(!namemap.count(entry))
return U"???";
return namemap.find(entry)->second;
}
};
/**
@ -336,12 +348,12 @@ public:
* Get number of used control indices on controller.
*
* Parameter controller: Number of controller.
* Returns: Number of used control indices.
* Returns: Number of used control indices. First is number of actual indices, second is number of reserved ones.
*/
unsigned used_indices(unsigned controller)
std::pair<unsigned, unsigned> used_indices(unsigned controller) const
{
auto c = controller_info->get(controller);
return c ? c->buttons.size() : 0;
return c ? std::make_pair((unsigned)c->buttons.size(), c->reserved_idx) : std::make_pair(0U, 0U);
}
/**
* Human-readable name.
@ -519,6 +531,12 @@ public:
throw std::runtime_error("Bad legacy PCID");
return legacy_pcids[pcid];
}
/**
* Set pollcounters mask.
*
* Parameter mask: The mask to write.
*/
void set_pollcounter_mask(uint32_t* mask) const;
private:
port_type_set(std::vector<class port_type*> types, struct port_index_map control_map);
size_t* port_offsets;
@ -566,10 +584,14 @@ public:
* Assign the pollcounter_vector.
*/
pollcounter_vector& operator=(const pollcounter_vector& v) throw(std::bad_alloc);
/**
* Zero all unmasked poll counters and clear all DRDY bits. System flag is cleared.
*/
void clear_unmasked() throw();
/**
* Zero all poll counters and clear all DRDY bits. System flag is cleared.
*/
void clear() throw();
void clear_all() throw();
/**
* Set all DRDY bits.
*/
@ -707,8 +729,47 @@ public:
* Get raw pollcounter data.
*/
const uint32_t* rawdata() const throw() { return ctrs; }
/**
* Write reserved index for controller.
*
* Parameter port: The port.
* Parameter controller: The controller.
* Parameter _index: The reserved index (0-based).
* Parameter val: The value to write.
* Throws std::runtime_error: Specified reserved slot is not valid.
*/
void reserved(unsigned port, unsigned controller, unsigned _index, uint32_t val)
throw(std::runtime_error)
{
auto counts = (port < types->ports()) ? types->port_type(port).used_indices(controller) :
std::make_pair(0U, 0U);
unsigned pindex = types->triple_to_index(port, controller, _index + counts.first);
if(pindex == 0xFFFFFFFFU)
throw std::runtime_error("write_reserved: Invalid reserved index");
ctrs[pindex] = val;
}
/**
* Read reserved index for controller.
*
* Parameter port: The port.
* Parameter controller: The controller.
* Parameter _index: The reserved index (0-based).
* Returns: The value read.
* Throws std::runtime_error: Specified reserved slot is not valid.
*/
uint32_t reserved(unsigned port, unsigned controller, unsigned _index)
throw(std::runtime_error)
{
auto counts = (port < types->ports()) ? types->port_type(port).used_indices(controller) :
std::make_pair(0U, 0U);
unsigned pindex = types->triple_to_index(port, controller, _index + counts.first);
if(pindex == 0xFFFFFFFFU)
throw std::runtime_error("write_reserved: Invalid reserved index");
return ctrs[pindex];
}
private:
uint32_t* ctrs;
uint32_t* ctrs_valid_mask;
const port_type_set* types;
bool framepflag;
};

View file

@ -161,6 +161,7 @@ controller_frame movie_logic::update_controls(bool subframe) throw(std::bad_allo
core.vi_prev_frame = false;
}
platform::flush_command_queue();
//TODO: Collapse keyboard symbols.
controller_frame tmp = core.controls->get(core.mlogic->get_movie().get_current_frame());
core.rom->pre_emulate_frame(tmp); //Preset controls, the lua will override if needed.
core.lua2->callback_do_input(tmp, subframe);

View file

@ -159,8 +159,10 @@ port_type_set::port_type_set(std::vector<class port_type*> types, struct port_in
//Count maximum number of controller indices to determine the controller multiplier.
controller_multiplier = 1;
for(size_t i = 0; i < port_count; i++)
for(unsigned j = 0; j < types[i]->controller_info->controllers.size(); j++)
controller_multiplier = max(controller_multiplier, (size_t)types[i]->used_indices(j));
for(unsigned j = 0; j < types[i]->controller_info->controllers.size(); j++) {
auto idxcnt = types[i]->used_indices(j);
controller_multiplier = max(controller_multiplier, (size_t)(idxcnt.first + idxcnt.second));
}
//Count maximum number of controllers to determine the port multiplier.
port_multiplier = 1;
for(size_t i = 0; i < port_count; i++)
@ -193,6 +195,28 @@ port_type_set::port_type_set(std::vector<class port_type*> types, struct port_in
}
}
void port_type_set::set_pollcounter_mask(uint32_t* mask) const
{
for(unsigned i = 0; i < indices_size; i++) {
unsigned v = indices_tab[i];
//i is the index into map (which decomposes into triple). v is the index in array (which may be
//invalid).
if(v == 0xFFFFFFFFUL)
continue;
unsigned _port = i / port_multiplier;
unsigned _controller = (i % port_multiplier) / controller_multiplier;
unsigned _button = i % controller_multiplier;
if(_port >= port_count)
continue;
//Determine if this is reserved or not (it is reserved if index is beyond limit) and set bit.
auto idxcnt = port_types[_port]->used_indices(_controller);
if(_button >= idxcnt.first)
mask[v >> 5] &= ~(1U << (v & 31));
else
mask[v >> 5] |= (1U << (v & 31));
}
}
short read_axis_value(const char* buf, size_t& idx) throw()
{
char ch;
@ -272,7 +296,6 @@ void controller_frame::display(unsigned port, unsigned controller, char32_t* buf
}
const port_controller& pc = ptype.controller_info->controllers[controller];
bool need_space = false;
short val;
for(unsigned i = 0; i < pc.buttons.size(); i++) {
const port_controller_button& pcb = pc.buttons[i];
if(need_space && pcb.type != port_controller_button::TYPE_NULL) {
@ -289,8 +312,14 @@ void controller_frame::display(unsigned port, unsigned controller, char32_t* buf
case port_controller_button::TYPE_RAXIS:
case port_controller_button::TYPE_TAXIS:
case port_controller_button::TYPE_LIGHTGUN:
val = ptype.read(&ptype, backingmem, controller, i);
buf += writeu32val(buf, val);
buf += writeu32val(buf, ptype.read(&ptype, backingmem, controller, i));
need_space = true;
break;
case port_controller_button::TYPE_KEYBOARD:
//Write name.
auto str = pc.get_namemap_entry(ptype.read(&ptype, backingmem, controller, i));
for(auto x : str)
*(buf++) = x;
need_space = true;
break;
}
@ -301,22 +330,34 @@ void controller_frame::display(unsigned port, unsigned controller, char32_t* buf
pollcounter_vector::pollcounter_vector() throw(std::bad_alloc)
{
types = &dummytypes();
ctrs = new uint32_t[types->indices()];
clear();
size_t elts_base = types->indices();
size_t elts_mask = (elts_base + 31) / 32;
size_t elts_all = elts_base + elts_mask;
ctrs = new uint32_t[elts_all];
memset(ctrs_valid_mask = ctrs + elts_base, 0xFF, sizeof(uint32_t) * elts_mask);
clear_all();
}
pollcounter_vector::pollcounter_vector(const port_type_set& p) throw(std::bad_alloc)
{
types = &p;
ctrs = new uint32_t[types->indices()];
clear();
size_t elts_base = types->indices();
size_t elts_mask = (elts_base + 31) / 32;
size_t elts_all = elts_base + elts_mask;
ctrs = new uint32_t[elts_all];
types->set_pollcounter_mask(ctrs_valid_mask = ctrs + elts_base);
clear_all();
}
pollcounter_vector::pollcounter_vector(const pollcounter_vector& p) throw(std::bad_alloc)
{
ctrs = new uint32_t[p.types->indices()];
size_t elts_base = p.types->indices();
size_t elts_mask = (elts_base + 31) / 32;
size_t elts_all = elts_base + elts_mask;
ctrs = new uint32_t[elts_all];
ctrs_valid_mask = ctrs + elts_base;
types = p.types;
memcpy(ctrs, p.ctrs, sizeof(uint32_t) * p.types->indices());
memcpy(ctrs, p.ctrs, sizeof(uint32_t) * elts_all);
framepflag = p.framepflag;
}
@ -324,21 +365,34 @@ pollcounter_vector& pollcounter_vector::operator=(const pollcounter_vector& p) t
{
if(this == &p)
return *this;
uint32_t* n = new uint32_t[p.types->indices()];
size_t elts_base = p.types->indices();
size_t elts_mask = (elts_base + 31) / 32;
size_t elts_all = elts_base + elts_mask;
uint32_t* n = new uint32_t[elts_all];
types = p.types;
memcpy(n, p.ctrs, sizeof(uint32_t) * p.types->indices());
memcpy(n, p.ctrs, sizeof(uint32_t) * elts_all);
delete[] ctrs;
ctrs = n;
ctrs_valid_mask = ctrs + elts_base;
framepflag = p.framepflag;
return *this;
}
pollcounter_vector::~pollcounter_vector() throw()
{
//ctrs_valid_mask is part of this.
delete[] ctrs;
}
void pollcounter_vector::clear() throw()
void pollcounter_vector::clear_unmasked() throw()
{
for(size_t i = 0; i < types->indices(); i++)
if((ctrs_valid_mask[i >> 5] >> (i & 31)) & 1)
ctrs[i] = 0;
framepflag = false;
}
void pollcounter_vector::clear_all() throw()
{
memset(ctrs, 0, sizeof(uint32_t) * types->indices());
framepflag = false;
@ -346,46 +400,65 @@ void pollcounter_vector::clear() throw()
void pollcounter_vector::set_all_DRDY() throw()
{
//Only manipulate valid pcounters.
for(size_t i = 0; i < types->indices(); i++)
ctrs[i] |= 0x80000000UL;
if((ctrs_valid_mask[i >> 5] >> (i & 31)) & 1)
ctrs[i] |= 0x80000000UL;
}
void pollcounter_vector::clear_DRDY(unsigned idx) throw()
{
ctrs[idx] &= 0x7FFFFFFFUL;
//Only manipulate valid pcounters.
if((ctrs_valid_mask[idx >> 5] >> (idx & 31)) & 1)
ctrs[idx] &= 0x7FFFFFFFUL;
}
bool pollcounter_vector::get_DRDY(unsigned idx) throw()
{
return ((ctrs[idx] & 0x80000000UL) != 0);
//For not valid pcounters, DRDY is permanently 1.
if((ctrs_valid_mask[idx >> 5] >> (idx & 31)) & 1)
return ((ctrs[idx] & 0x80000000UL) != 0);
else
return true;
}
bool pollcounter_vector::has_polled() throw()
{
uint32_t res = 0;
for(size_t i = 0; i < types->indices() ; i++)
res |= ctrs[i];
for(size_t i = 0; i < types->indices(); i++)
if((ctrs_valid_mask[i >> 5] >> (i & 31)) & 1)
res |= ctrs[i];
return ((res & 0x7FFFFFFFUL) != 0);
}
uint32_t pollcounter_vector::get_polls(unsigned idx) throw()
{
return ctrs[idx] & 0x7FFFFFFFUL;
//For not valid pcounters, polls is permanently 0.
if((ctrs_valid_mask[idx >> 5] >> (idx & 31)) & 1)
return ctrs[idx] & 0x7FFFFFFFUL;
else
return 0;
}
uint32_t pollcounter_vector::increment_polls(unsigned idx) throw()
{
uint32_t x = ctrs[idx] & 0x7FFFFFFFUL;
++ctrs[idx];
return x;
//Only manipulate valid pcounters, for others, permanently 0.
if((ctrs_valid_mask[idx >> 5] >> (idx & 31)) & 1) {
uint32_t x = ctrs[idx] & 0x7FFFFFFFUL;
++ctrs[idx];
return x;
} else
return 0;
}
uint32_t pollcounter_vector::max_polls() throw()
{
uint32_t max = 0;
for(unsigned i = 0; i < types->indices(); i++) {
uint32_t tmp = ctrs[i] & 0x7FFFFFFFUL;
max = (max < tmp) ? tmp : max;
if((ctrs_valid_mask[i >> 5] >> (i & 31)) & 1) {
uint32_t tmp = ctrs[i] & 0x7FFFFFFFUL;
max = (max < tmp) ? tmp : max;
}
}
return max;
}
@ -393,7 +466,6 @@ uint32_t pollcounter_vector::max_polls() throw()
void pollcounter_vector::save_state(std::vector<uint32_t>& mem) throw(std::bad_alloc)
{
mem.resize(types->indices());
//Compatiblity fun.
for(size_t i = 0; i < types->indices(); i++)
mem[i] = ctrs[i];
}
@ -824,6 +896,7 @@ unsigned port_controller::analog_actions() const
break;
case port_controller_button::TYPE_NULL:
case port_controller_button::TYPE_BUTTON:
case port_controller_button::TYPE_KEYBOARD:
;
};
}
@ -868,6 +941,7 @@ std::pair<unsigned, unsigned> port_controller::analog_action(unsigned k) const
break;
case port_controller_button::TYPE_NULL:
case port_controller_button::TYPE_BUTTON:
case port_controller_button::TYPE_KEYBOARD:
;
};
}

View file

@ -23,6 +23,22 @@ namespace
return y.str();
}
std::string quote(const std::u32string& _s)
{
auto s = utf8::to8(_s);
std::ostringstream y;
y << "U\"";
for(auto i : s)
if(i == '\"')
y << "\"";
else if(i == '\\')
y << "\\\\";
else
y << i;
y << "\"";
return y.str();
}
std::string read_str(const JSON::node& root, const JSON::pointer& ptr)
{
if(root.type_of(ptr) != JSON::string)
@ -117,6 +133,22 @@ namespace
return ret;
}
port_controller_button pcb_key(const JSON::node& root, const JSON::pointer& ptr)
{
auto pshadow = ptr.field("shadow");
auto pname = ptr.field("name");
struct port_controller_button ret;
ret.type = port_controller_button::TYPE_KEYBOARD;
ret.symbol = U'\0';
ret.shadow = (root.type_of(pshadow) != JSON::none) ? read_bool(root, pshadow) : false;
ret.rmin = 0;
ret.rmax = 0;
ret.centers = false;
ret.macro = "";
ret.msymbol = '\0';
return ret;
}
struct port_controller_button pcs_parse_button(const JSON::node& root, JSON::pointer ptr)
{
if(root.type_of_indirect(ptr) != JSON::object)
@ -129,6 +161,8 @@ namespace
return pcb_button(root, ptr);
else if(type == "axis" || type == "raxis" || type == "taxis" || type == "lightgun")
return pcb_axis(root, ptr, type);
else if(type == "key")
return pcb_key(root, ptr);
else
(stringfmt() << "Unknown type '" << type << "' for '" << ptr << "'").throwex();
return pcb_null(root, ptr); //NOTREACHED.
@ -153,6 +187,22 @@ namespace
ret.cclass = cclass;
ret.type = type;
ret.buttons = buttons;
JSON::pointer _buttonmap = ptr.field("buttonmap");
//Namemap is OPTIONAL. If present, it must be an array, giving the entries as strings (or nil)
//for not present.
if(root.type_of_indirect(_buttonmap) != JSON::none) {
if(root.type_of_indirect(_buttonmap) != JSON::array)
(stringfmt() << "Expected array or not present for '" << _buttonmap << "'").throwex();
for(auto i = root[_buttonmap].begin(); i != root[_buttonmap].end(); ++i) {
if(i->type() == JSON::string) {
ret.namemap[i.index()] = i->as_string();
} else if(i->type() != JSON::none) {
(stringfmt() << "Expected string or not present for '"
<< _buttonmap.index(i.index()) << "'").throwex();
}
}
}
ret.reserved_idx = (ret.namemap.size() + 31) / 32; //One bit per namemap entry.
return ret;
}
@ -202,6 +252,7 @@ namespace
case port_controller_button::TYPE_RAXIS: s << "RAXIS"; break;
case port_controller_button::TYPE_TAXIS: s << "TAXIS"; break;
case port_controller_button::TYPE_LIGHTGUN: s << "LIGHTGUN"; break;
case port_controller_button::TYPE_KEYBOARD: s << "KEYBOARD"; break;
}
s << "," << (int)b.symbol << ", " << quote(b.name) << ", " << b.shadow << ", " << b.rmin << ", "
<< b.rmax << ", " << b.centers << ", " << quote(b.macro) << ", " << (int)b.msymbol << "}";
@ -216,7 +267,10 @@ namespace
write_button(s, i);
s << ",\n";
}
s << "}};\n";
s << "},{";
for(auto i : c.namemap)
s << "\t{" << i.first << ", " << quote(i.second) << "},\n";
s << "}," << c.reserved_idx << "};\n";
}
void write_portdata(std::ostream& s, const port_controller_set& cs, unsigned& idx)
@ -249,6 +303,7 @@ namespace
case port_controller_button::TYPE_NULL: break;
case port_controller_button::TYPE_RAXIS: x+=16; break;
case port_controller_button::TYPE_TAXIS: x+=16; break;
case port_controller_button::TYPE_KEYBOARD: x+=16; break;
};
}
return (x + 7) / 8;
@ -266,6 +321,7 @@ namespace
case port_controller_button::TYPE_NULL: break;
case port_controller_button::TYPE_RAXIS: break;
case port_controller_button::TYPE_TAXIS: break;
case port_controller_button::TYPE_KEYBOARD: break;
};
}
return (x + 7) / 8;
@ -297,6 +353,7 @@ namespace
case port_controller_button::TYPE_RAXIS:
case port_controller_button::TYPE_TAXIS:
case port_controller_button::TYPE_LIGHTGUN:
case port_controller_button::TYPE_KEYBOARD:
ii.type = 2;
ii.offset = aoffset + 2 * axisidx2;
axisidx2++;
@ -343,6 +400,7 @@ namespace
case port_controller_button::TYPE_RAXIS:
case port_controller_button::TYPE_TAXIS:
case port_controller_button::TYPE_LIGHTGUN:
case port_controller_button::TYPE_KEYBOARD:
ins.type = 1;
ins.offset = aoffset + 2 * axisidx;
ret.push_back(ins);

View file

@ -120,7 +120,7 @@ void movie::next_frame() throw(std::bad_alloc)
}
//Reset the poll counters and DRDY flags.
pollcounters.clear();
pollcounters.clear_unmasked();
//Increment the current frame counter and subframe counter. Note that first subframe is undefined for
//frame 0 and 0 for frame 1.
@ -346,7 +346,7 @@ void movie::reset_state() throw()
readonly = true;
current_frame = 0;
current_frame_first_subframe = 0;
pollcounters.clear();
pollcounters.clear_all();
lag_frames = 0;
clear_caches();
}

View file

@ -465,6 +465,7 @@ namespace
case port_controller_button::TYPE_RAXIS: L.pushstring("raxis"); break;
case port_controller_button::TYPE_TAXIS: L.pushstring("axis"); break;
case port_controller_button::TYPE_LIGHTGUN: L.pushstring("lightgun"); break;
case port_controller_button::TYPE_KEYBOARD: L.pushstring("keyboard"); break;
};
L.rawset(-3);
if(cs.buttons[i].symbol) {

View file

@ -74,6 +74,16 @@ namespace
uint64_t divsl[] = {1000000, 100000, 10000, 1000, 100, 10, 0};
const unsigned divcnt = sizeof(divs)/sizeof(divs[0]);
bool is_ctype(int type)
{
return (type == 0 || type == 1 || type == 2);
}
bool is_wtype(int type)
{
return (type == -1 || type == 1 || type == 2);
}
class exp_imp_type
{
public:
@ -110,7 +120,7 @@ struct control_info
unsigned position_left;
unsigned reserved; //Must be at least 6 for axes.
unsigned index; //Index in poll vector.
int type; //-2 => Port, -1 => Fixed, 0 => Button, 1 => axis.
int type; //-2 => Port, -1 => Fixed, 0 => Button, 1 => axis, 2 => Key
char32_t ch;
std::u32string title;
unsigned port;
@ -124,6 +134,7 @@ struct control_info
unsigned port, unsigned controller);
static control_info axisinfo(unsigned& p, const std::u32string& title, unsigned idx,
unsigned port, unsigned controller, port_controller_button::_type _axistype, int _rmin, int _rmax);
//TODO: keyinfo().
};
control_info control_info::portinfo(unsigned& p, unsigned port, unsigned controller)
@ -261,6 +272,8 @@ void frame_controls::add_port(unsigned& c, unsigned pid, const port_type& p, con
controlinfo.push_back(control_info::axisinfo(c, utf8::to32(pcb.name), idx, pid, i,
pcb.type, pcb.rmin, pcb.rmax));
last_multibyte = true;
} else if(pcb.type == port_controller_button::TYPE_KEYBOARD) {
//TODO
}
}
if(nextp > c)
@ -322,7 +335,7 @@ void frame_controls::format_lines()
//Line2
for(auto i : controlinfo) {
auto _title = i.title;
if(i.type == -1 || i.type == 1)
if(is_wtype(i.type))
std::copy(_title.begin(), _title.end(), &cp2[i.position_left + off]);
if(i.type == 0)
cp2[i.position_left + off] = i.ch;
@ -389,6 +402,9 @@ namespace
first = false;
last_axis = true;
break;
case 2: //key
//TODO.
break;
}
}
return x.str();
@ -450,6 +466,9 @@ namespace
first = false;
last_axis = true;
break;
case 2: //Key.
//TODO.
break;
}
}
}
@ -496,7 +515,7 @@ namespace
{
std::set<unsigned> r;
for(auto i : info.get_controlinfo()) {
if(i.port == port && i.controller == controller && (i.type == 0 || i.type == 1))
if(i.port == port && i.controller == controller && is_ctype(i.type))
r.insert(i.index);
}
return r;
@ -1016,6 +1035,9 @@ void wxeditor_movie::_moviepanel::render_linen(text_framebuffer& fb, controller_
char c[7];
sprintf(c, "%6d", fcontrols.read_index(f, i.index));
fb.write(c, 0, divcnt + 1 + i.position_left, y, 0x000000, bgc);
} else if(i.type == 2) {
//Key.
//TODO.
}
}
}
@ -1416,6 +1438,8 @@ void wxeditor_movie::_moviepanel::on_mouse0(unsigned x, unsigned y, bool polarit
}
} else
do_alter_axis(idx, press_line, line);
} else if(i.type == 2) {
//TODO.
}
}
}
@ -1831,7 +1855,7 @@ void wxeditor_movie::_moviepanel::on_mouse2(unsigned x, unsigned y, bool polarit
} else {
for(auto i : fcontrols.get_controlinfo())
if(press_x >= i.position_left + off && press_x < i.position_left + i.reserved + off) {
if(i.type == 0 || i.type == 1) {
if(is_ctype(i.type)) {
clicked_button = true;
clicked = i;
controller_name = (stringfmt() << "controller " << i.port << "-"
@ -1847,7 +1871,7 @@ void wxeditor_movie::_moviepanel::on_mouse2(unsigned x, unsigned y, bool polarit
uint64_t ebutton_low = clicked_button ? first_editable(clicked.index) : std::numeric_limits<uint64_t>::max();
uint64_t econtroller_low = ebutton_low;
for(auto i : fcontrols.get_controlinfo())
if(i.port == clicked.port && i.controller == clicked.controller && (i.type == 0 || i.type == 1))
if(i.port == clicked.port && i.controller == clicked.controller && is_ctype(i.type))
econtroller_low = max(econtroller_low, first_editable(i.index));
bool click_zero = (clicked_button && !clicked.port && !clicked.controller);
@ -1876,6 +1900,7 @@ void wxeditor_movie::_moviepanel::on_mouse2(unsigned x, unsigned y, bool polarit
press_line < linecount) || (rpress_line >= ebutton_low && rpress_line < linecount)));
//Sweep axis is enabled if change axis is enabled and lines don't match.
enable_sweep_axis = (enable_change_axis && press_line != rpress_line);
//TODO: Handle clicked.type == 2.
//Insert frame is enabled if this frame is completely editable and press and release lines match.
enable_insert_frame = (!not_editable && press_line + 1 >= eframe_low && press_line < linecount &&
press_line == rpress_line);

View file

@ -522,6 +522,8 @@ void wxeditor_tasinput::update_controls()
current->Add(t.check);
t.check->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED,
wxCommandEventHandler(wxeditor_tasinput::on_control), NULL, this);
} else if(i.type == port_controller_button::TYPE_KEYBOARD) {
//TODO.
} else {
t.panel = new xypanel(current_p, inst, current, i, this,
wxCommandEventHandler(wxeditor_tasinput::on_control), next_id);