Macros: Support ? modifier for macros (press at random)

This commit is contained in:
Ilari Liusvaara 2013-08-18 23:03:43 +03:00
parent a38ce6b99e
commit 4feb4b6290
2 changed files with 55 additions and 5 deletions

View file

@ -1199,7 +1199,7 @@ struct controller_macro_data
void write(controller_frame& frame, unsigned port, unsigned controller, int64_t nframe, apply_mode amode);
std::string dump(const port_controller& ctrl); //Mainly for debugging.
size_t get_frames() { return data.size() / get_stride(); }
size_t get_stride() { return (buttons + 7) / 8; }
size_t get_stride() { return (buttons + 3) / 4; }
size_t buttons;
std::vector<unsigned char> data;
std::vector<std::pair<unsigned, unsigned>> aaxes;

View file

@ -4,7 +4,9 @@
#include "globalwrap.hpp"
#include "serialization.hpp"
#include "string.hpp"
#include "sha256.hpp"
#include <iostream>
#include <sys/time.h>
#include <sstream>
#include <list>
#include <deque>
@ -43,6 +45,24 @@ namespace
controller_info = &simple_port;
}
};
unsigned macro_random_bit()
{
static unsigned char state[32];
static unsigned extracted = 256;
if(extracted == 256) {
timeval tv;
gettimeofday(&tv, NULL);
unsigned char buffer[48];
memcpy(buffer, state, 32);
write64ube(buffer + 32, tv.tv_sec);
write64ube(buffer + 40, tv.tv_usec);
sha256::hash(state, buffer, 48);
extracted = 0;
}
unsigned bit = extracted++;
return ((state[bit / 8] >> (bit % 8)) & 1);
}
}
port_type& get_default_system_port_type()
@ -669,12 +689,17 @@ controller_macro_data::controller_macro_data(const std::string& spec, const JSON
std::deque<size_t> stack;
bool in_sparen = false;
bool first = true;
bool btn_token = false;
bool btn_token_next = false;
size_t last_bit = 0;
size_t last_size = 0;
size_t astride = aaxes.size();
size_t stride = get_stride();
size_t idx = 0;
size_t len = spec.length();
while(idx < len) {
btn_token = btn_token_next;
btn_token_next = false;
unsigned char ch = spec[idx];
if(autoterminate)
throw std::runtime_error("Asterisk must be the last thing");
@ -692,6 +717,12 @@ controller_macro_data::controller_macro_data(const std::string& spec, const JSON
last_size = (data.size() - x) / stride;
} else if(ch == '*') {
autoterminate = true;
} else if(ch == '?') {
if(!btn_token)
throw std::runtime_error("? needs button to apply to");
if(!in_sparen)
throw std::runtime_error("? needs to be in brackets");
data[data.size() - stride + last_bit / 4] |= (2 << (2 * (last_bit % 4)));
} else if(ch == '[') {
if(in_sparen)
throw std::runtime_error("Nested square brackets not allowed");
@ -762,13 +793,15 @@ controller_macro_data::controller_macro_data(const std::string& spec, const JSON
data.resize(data.size() + stride);
adata.resize(adata.size() + astride);
}
data[data.size() - stride + k.second / 8] |= (1 << (k.second % 8));
last_bit = k.second;
data[data.size() - stride + k.second / 4] |= (1 << (2 * (k.second % 4)));
if(!in_sparen)
last_size = 1;
}
}
if(!found)
throw std::runtime_error("Unknown character or button");
btn_token_next = true;
}
idx++;
first = false;
@ -798,9 +831,13 @@ bool controller_macro_data::syntax_check(const std::string& spec, const JSON::no
size_t depth = 0;
bool in_sparen = false;
bool first = true;
bool btn_token = false;
bool btn_token_next = false;
size_t idx = 0;
size_t len = spec.length();
while(idx < len) {
btn_token = btn_token_next;
btn_token_next = false;
unsigned char ch = spec[idx];
if(autoterminate)
return false;
@ -816,6 +853,9 @@ bool controller_macro_data::syntax_check(const std::string& spec, const JSON::no
depth--;
} else if(ch == '*') {
autoterminate = true;
} else if(ch == '?') {
if(!btn_token || !in_sparen)
return false;
} else if(ch == '[') {
if(in_sparen)
return false;
@ -873,6 +913,7 @@ bool controller_macro_data::syntax_check(const std::string& spec, const JSON::no
}
if(!found)
return false;
btn_token_next = true;
}
idx++;
first = false;
@ -896,7 +937,10 @@ void controller_macro_data::write(controller_frame& frame, unsigned port, unsign
nframe %= get_frames();
for(size_t i = 0; i < buttons; i++) {
unsigned lb = btnmap[i];
if((data[nframe * get_stride() + i / 8] >> (i % 8)) & 1)
unsigned st = ((data[nframe * get_stride() + i / 4] >> (2 * (i % 4))) & 3);
if(st == 3)
st = macro_random_bit();
if(st == 1)
switch(amode) {
case AM_OVERWRITE:
case AM_OR:
@ -947,9 +991,15 @@ std::string controller_macro_data::dump(const port_controller& ctrl)
o << t.coeffs[0] << "," << t.coeffs[1] << "," << t.coeffs[2] << ",";
o << t.coeffs[3] << "," << t.coeffs[4] << "," << t.coeffs[5] << "@";
}
for(size_t j = 0; j < buttons && j < ctrl.buttons.size(); j++)
if(((data[i * get_stride() + j / 8] >> (j % 8)) & 1) && ctrl.buttons[j].macro)
for(size_t j = 0; j < buttons && j < ctrl.buttons.size(); j++) {
unsigned st = ((data[i * get_stride() + j / 4] >> (2 * (j % 4))) & 3);
if(!ctrl.buttons[j].macro)
continue;
if(st == 1)
o << ctrl.buttons[j].macro;
if(st == 3)
o << ctrl.buttons[j].macro << "?";
}
o << "]";
}
if(autoterminate)