Compare commits
1 commit
master
...
keybroadca
Author | SHA1 | Date | |
---|---|---|---|
|
32daef9154 |
9 changed files with 522 additions and 19 deletions
8
include/core/keybroadcast.hpp
Normal file
8
include/core/keybroadcast.hpp
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
#ifndef _keybroadcast__hpp__included__
|
||||||
|
#define _keybroadcast__hpp__included__
|
||||||
|
|
||||||
|
void keybroadcast_notify_foreground(bool fg);
|
||||||
|
void keybroadcast_set_master(uint16_t port);
|
||||||
|
void keybroadcast_set_slave(uint16_t port);
|
||||||
|
|
||||||
|
#endif
|
|
@ -303,6 +303,11 @@ struct platform
|
||||||
* Parameter sync: If true, execute function call synchronously, else asynchronously.
|
* Parameter sync: If true, execute function call synchronously, else asynchronously.
|
||||||
*/
|
*/
|
||||||
static void queue(void (*f)(void* arg), void* arg, bool sync) throw(std::bad_alloc);
|
static void queue(void (*f)(void* arg), void* arg, bool sync) throw(std::bad_alloc);
|
||||||
|
/**
|
||||||
|
* Set handle to mirror all non-exclusive key events to.
|
||||||
|
*/
|
||||||
|
static void set_mirror_fn(std::function<void(keyboard::modifier_set& mods, keyboard::key& key,
|
||||||
|
keyboard::event& event)> fn);
|
||||||
/**
|
/**
|
||||||
* Run all queues.
|
* Run all queues.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -54,6 +54,7 @@ public:
|
||||||
void load(const JSON::node& state);
|
void load(const JSON::node& state);
|
||||||
JSON::node save();
|
JSON::node save();
|
||||||
std::string get_summary();
|
std::string get_summary();
|
||||||
|
void master_enable(bool state);
|
||||||
private:
|
private:
|
||||||
struct axis_info
|
struct axis_info
|
||||||
{
|
{
|
||||||
|
@ -109,6 +110,7 @@ private:
|
||||||
unsigned next_hat;
|
unsigned next_hat;
|
||||||
unsigned jid;
|
unsigned jid;
|
||||||
mutex_class mutex;
|
mutex_class mutex;
|
||||||
|
bool enabled;
|
||||||
};
|
};
|
||||||
|
|
||||||
class set
|
class set
|
||||||
|
@ -127,6 +129,7 @@ public:
|
||||||
void set_axismode_cb(std::function<void(unsigned jnum, unsigned num, int mode, double tolerance)> fn);
|
void set_axismode_cb(std::function<void(unsigned jnum, unsigned num, int mode, double tolerance)> fn);
|
||||||
void set_newitem_cb(std::function<void(unsigned jnum, unsigned num, int type)> fn);
|
void set_newitem_cb(std::function<void(unsigned jnum, unsigned num, int type)> fn);
|
||||||
std::string get_summary();
|
std::string get_summary();
|
||||||
|
void master_enable(bool state);
|
||||||
private:
|
private:
|
||||||
set(const set&);
|
set(const set&);
|
||||||
set& operator=(const set&);
|
set& operator=(const set&);
|
||||||
|
@ -137,6 +140,7 @@ private:
|
||||||
std::function<void(unsigned jnum, unsigned num, int type)> newitem_fn;
|
std::function<void(unsigned jnum, unsigned num, int type)> newitem_fn;
|
||||||
std::vector<pad*> _gamepads;
|
std::vector<pad*> _gamepads;
|
||||||
mutex_class mutex;
|
mutex_class mutex;
|
||||||
|
bool enabled;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -245,6 +245,10 @@ public:
|
||||||
* Stringify.
|
* Stringify.
|
||||||
*/
|
*/
|
||||||
operator std::string() const throw(std::bad_alloc);
|
operator std::string() const throw(std::bad_alloc);
|
||||||
|
/**
|
||||||
|
* Get internal set.
|
||||||
|
*/
|
||||||
|
std::set<modifier*> get_set() const throw(std::bad_alloc) { return set; }
|
||||||
/**
|
/**
|
||||||
* Equality check.
|
* Equality check.
|
||||||
*
|
*
|
||||||
|
@ -330,16 +334,22 @@ public:
|
||||||
*
|
*
|
||||||
* Parameter _chngmask: The change mask.
|
* Parameter _chngmask: The change mask.
|
||||||
* Parameter _type: Type of the event.
|
* Parameter _type: Type of the event.
|
||||||
|
* Parameter _raw: The raw event value.
|
||||||
*/
|
*/
|
||||||
event(uint32_t _chngmask, keytype _type) throw()
|
event(uint32_t _chngmask, keytype _type, int32_t _raw) throw()
|
||||||
{
|
{
|
||||||
chngmask = _chngmask;
|
chngmask = _chngmask;
|
||||||
type = _type;
|
type = _type;
|
||||||
|
raw = _raw;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Destructor.
|
* Destructor.
|
||||||
*/
|
*/
|
||||||
virtual ~event() throw();
|
virtual ~event() throw();
|
||||||
|
/**
|
||||||
|
* Get original raw state reported.
|
||||||
|
*/
|
||||||
|
int32_t get_raw() const throw() { return raw; }
|
||||||
/**
|
/**
|
||||||
* Get analog state. The format is dependent on key type.
|
* Get analog state. The format is dependent on key type.
|
||||||
*/
|
*/
|
||||||
|
@ -357,6 +367,7 @@ public:
|
||||||
private:
|
private:
|
||||||
uint32_t chngmask;
|
uint32_t chngmask;
|
||||||
keytype type;
|
keytype type;
|
||||||
|
int32_t raw;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -369,8 +380,9 @@ public:
|
||||||
* Construct a new key event.
|
* Construct a new key event.
|
||||||
*
|
*
|
||||||
* Parameter chngmask: The change mask.
|
* Parameter chngmask: The change mask.
|
||||||
|
* Parameter _raw: The raw event value.
|
||||||
*/
|
*/
|
||||||
event_key(uint32_t chngmask);
|
event_key(uint32_t chngmask, int32_t _raw);
|
||||||
/**
|
/**
|
||||||
* Destructor.
|
* Destructor.
|
||||||
*/
|
*/
|
||||||
|
@ -397,8 +409,9 @@ public:
|
||||||
* Parameter state: The analog state.
|
* Parameter state: The analog state.
|
||||||
* Parameter chngmask: The change mask.
|
* Parameter chngmask: The change mask.
|
||||||
* Parameter cal: The calibration structure.
|
* Parameter cal: The calibration structure.
|
||||||
|
* Parameter _raw: The raw event value.
|
||||||
*/
|
*/
|
||||||
event_axis(int32_t state, uint32_t chngmask);
|
event_axis(int32_t state, uint32_t chngmask, int32_t _raw);
|
||||||
/**
|
/**
|
||||||
* Destructor.
|
* Destructor.
|
||||||
*/
|
*/
|
||||||
|
@ -424,8 +437,9 @@ public:
|
||||||
* Construct a new hat event.
|
* Construct a new hat event.
|
||||||
*
|
*
|
||||||
* Parameter chngmask: The change mask to use.
|
* Parameter chngmask: The change mask to use.
|
||||||
|
* Parameter _raw: The raw event value.
|
||||||
*/
|
*/
|
||||||
event_hat(uint32_t chngmask);
|
event_hat(uint32_t chngmask, int32_t _raw);
|
||||||
/**
|
/**
|
||||||
* Destructor.
|
* Destructor.
|
||||||
*/
|
*/
|
||||||
|
@ -449,8 +463,9 @@ public:
|
||||||
*
|
*
|
||||||
* Parameter state: The game-relative position to use.
|
* Parameter state: The game-relative position to use.
|
||||||
* Parameter cal: The calibration structure.
|
* Parameter cal: The calibration structure.
|
||||||
|
* Parameter _raw: The raw event value.
|
||||||
*/
|
*/
|
||||||
event_mouse(int32_t state, const mouse_calibration& cal);
|
event_mouse(int32_t state, const mouse_calibration& cal, int32_t _raw);
|
||||||
/**
|
/**
|
||||||
* Destructor.
|
* Destructor.
|
||||||
*/
|
*/
|
||||||
|
|
393
src/core/keybroadcast.cpp
Normal file
393
src/core/keybroadcast.cpp
Normal file
|
@ -0,0 +1,393 @@
|
||||||
|
#include "core/window.hpp"
|
||||||
|
#include "core/keybroadcast.hpp"
|
||||||
|
#include "core/keymapper.hpp"
|
||||||
|
#include "library/string.hpp"
|
||||||
|
#include "library/minmax.hpp"
|
||||||
|
#include <sstream>
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
//Why the fuck does windows have nonstandard socket API???
|
||||||
|
#define _WIN32_WINNT 0x0501
|
||||||
|
#include <winsock2.h>
|
||||||
|
#include <ws2tcpip.h>
|
||||||
|
struct sockaddr_un { int sun_family; char sun_path[108]; };
|
||||||
|
#else
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
typedef SOCKET sock_handle_t;
|
||||||
|
sock_handle_t invalid_socket = INVALID_SOCKET;
|
||||||
|
#else
|
||||||
|
typedef int sock_handle_t;
|
||||||
|
sock_handle_t invalid_socket = -1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class k_link
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
k_link(sock_handle_t handle)
|
||||||
|
{
|
||||||
|
link_handle = handle;
|
||||||
|
dead_flag = true;
|
||||||
|
}
|
||||||
|
~k_link()
|
||||||
|
{
|
||||||
|
low_close();
|
||||||
|
}
|
||||||
|
//Returns true if link has something to transmit, else false.
|
||||||
|
bool can_tx()
|
||||||
|
{
|
||||||
|
umutex_class h(lock);
|
||||||
|
return !msg_tx_queue.empty();
|
||||||
|
}
|
||||||
|
//Write some data to link. If can_tx() returned true, this will try to transmit something.
|
||||||
|
void handle_tx()
|
||||||
|
{
|
||||||
|
umutex_class h(lock);
|
||||||
|
if(dead_flag)
|
||||||
|
return;
|
||||||
|
if(msg_tx_queue.empty())
|
||||||
|
return;
|
||||||
|
const std::string& txmsg = msg_tx_queue.front();
|
||||||
|
char buf[512];
|
||||||
|
size_t totransmit = txmsg.length() - first_msg_tx_count;
|
||||||
|
if(totransmit > sizeof(buf))
|
||||||
|
totransmit = sizeof(buf);
|
||||||
|
size_t tocopy = totransmit;
|
||||||
|
if(totransmit < sizeof(buf))
|
||||||
|
buf[totransmit++] = '\0';
|
||||||
|
if(tocopy > 0)
|
||||||
|
std::copy(txmsg.begin() + first_msg_tx_count, txmsg.begin() + first_msg_tx_count +
|
||||||
|
tocopy, buf);
|
||||||
|
//Actually try to transmit. If entiere message is transmitted, remove it.
|
||||||
|
first_msg_tx_count += low_write(buf, totransmit);
|
||||||
|
if(first_msg_tx_count >= txmsg.length() + 1)
|
||||||
|
msg_tx_queue.pop_front();
|
||||||
|
}
|
||||||
|
//Read some data from link.
|
||||||
|
void handle_rx()
|
||||||
|
{
|
||||||
|
umutex_class h(lock);
|
||||||
|
if(dead_flag)
|
||||||
|
return;
|
||||||
|
char buf[512];
|
||||||
|
size_t recvd = low_read(buf, sizeof(buf));
|
||||||
|
size_t off = 0;
|
||||||
|
for(unsigned i = 0; i < recvd; i++) {
|
||||||
|
if(buf[i] == '\0') {
|
||||||
|
//End of message.
|
||||||
|
size_t off2 = partial_rx_msg.size();
|
||||||
|
partial_rx_msg.resize(off2 + i - off);
|
||||||
|
std::copy(buf + off, buf + i, partial_rx_msg.begin() + off2);
|
||||||
|
msg_rx_queue.push_back(std::string(partial_rx_msg.begin(),
|
||||||
|
partial_rx_msg.end()));
|
||||||
|
off = i + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//Copy incomplete parts.
|
||||||
|
size_t off2 = partial_rx_msg.size();
|
||||||
|
partial_rx_msg.resize(off2 + recvd - off);
|
||||||
|
std::copy(buf + off, buf + recvd, partial_rx_msg.begin() + off2);
|
||||||
|
}
|
||||||
|
//Returns true if there is a pending message.
|
||||||
|
bool recv_ready()
|
||||||
|
{
|
||||||
|
umutex_class h(lock);
|
||||||
|
return !msg_rx_queue.empty();
|
||||||
|
}
|
||||||
|
//Read a pending message.
|
||||||
|
std::string recv()
|
||||||
|
{
|
||||||
|
umutex_class h(lock);
|
||||||
|
if(msg_rx_queue.empty())
|
||||||
|
return "";
|
||||||
|
std::string msg = msg_rx_queue.front();
|
||||||
|
msg_rx_queue.pop_front();
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
//Send a message to link.
|
||||||
|
void send(const std::string& str)
|
||||||
|
{
|
||||||
|
umutex_class h(lock);
|
||||||
|
msg_tx_queue.push_back(str);
|
||||||
|
}
|
||||||
|
//Is dead?
|
||||||
|
bool dead()
|
||||||
|
{
|
||||||
|
return dead_flag;
|
||||||
|
}
|
||||||
|
//Get link handle.
|
||||||
|
sock_handle_t handle()
|
||||||
|
{
|
||||||
|
return link_handle;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
size_t low_read(char* buf, size_t maxread);
|
||||||
|
size_t low_write(const char* buf, size_t maxwrite);
|
||||||
|
void low_close();
|
||||||
|
k_link(const k_link&);
|
||||||
|
k_link& operator=(const k_link&);
|
||||||
|
sock_handle_t link_handle;
|
||||||
|
std::list<std::string> msg_rx_queue;
|
||||||
|
std::list<std::string> msg_tx_queue;
|
||||||
|
size_t first_msg_tx_count;
|
||||||
|
std::vector<char> partial_rx_msg;
|
||||||
|
bool dead_flag;
|
||||||
|
mutex_class lock;
|
||||||
|
};
|
||||||
|
|
||||||
|
k_link* client_link;
|
||||||
|
mutex_class client_link_lock;
|
||||||
|
cv_class client_link_change;
|
||||||
|
bool client_link_exit;
|
||||||
|
bool client_link_exited;
|
||||||
|
|
||||||
|
void slave_thread()
|
||||||
|
{
|
||||||
|
client_link_exited = false;
|
||||||
|
while(!client_link_exit) {
|
||||||
|
{
|
||||||
|
umutex_class h(client_link_lock);
|
||||||
|
if(!client_link);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
client_link_exited = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
class k_server
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//Fill the sets with available socket handles.
|
||||||
|
void poll_readyness(std::set<sock_handle_t>& rx, std::set<sock_handle_t>& tx)
|
||||||
|
{
|
||||||
|
for(auto i : links) {
|
||||||
|
//Always ready for RX.
|
||||||
|
rx.insert(i->handle());
|
||||||
|
if(i->can_tx()) tx.insert(i->handle());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//Given sockets with activity, do RX/TX cycle.
|
||||||
|
void do_rx_tx(std::set<sock_handle_t>& rx, std::set<sock_handle_t>& tx)
|
||||||
|
{
|
||||||
|
//Read/write all available sockets.
|
||||||
|
for(auto i : links) {
|
||||||
|
if(rx.count(i->handle()))
|
||||||
|
i->handle_rx();
|
||||||
|
if(tx.count(i->handle()))
|
||||||
|
i->handle_tx();
|
||||||
|
}
|
||||||
|
//Check for dead connections and close those.
|
||||||
|
for(auto i = links.begin(); i != links.end();) {
|
||||||
|
if((*i)->dead()) {
|
||||||
|
delete *i;
|
||||||
|
i = links.erase(i);
|
||||||
|
} else
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
redistribute_messages();
|
||||||
|
}
|
||||||
|
//Receive from all connections, broadcast the message.
|
||||||
|
void redistribute_messages()
|
||||||
|
{
|
||||||
|
//Receive on all connections, send on all other connections.
|
||||||
|
for(auto i : links) {
|
||||||
|
//Loop over all received messages.
|
||||||
|
while(i->recv_ready()) {
|
||||||
|
std::string msg = i->recv();
|
||||||
|
if(!msg.length()) continue; //Skip empty messages.
|
||||||
|
//Send to all others.
|
||||||
|
for(auto j : links) {
|
||||||
|
if(i == j) continue; //Don't send back.
|
||||||
|
j->send(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//Accept a new connection.
|
||||||
|
void accept()
|
||||||
|
{
|
||||||
|
sock_handle_t h = low_accept();
|
||||||
|
if(h == invalid_socket)
|
||||||
|
return;
|
||||||
|
links.push_back(new k_link(h));
|
||||||
|
}
|
||||||
|
//Main poll loop.
|
||||||
|
void loop()
|
||||||
|
{
|
||||||
|
while(true) {
|
||||||
|
fd_set rset;
|
||||||
|
fd_set wset;
|
||||||
|
sock_handle_t bound = 0;
|
||||||
|
FD_ZERO(&rset);
|
||||||
|
FD_ZERO(&wset);
|
||||||
|
|
||||||
|
std::set<sock_handle_t> rx;
|
||||||
|
std::set<sock_handle_t> tx;
|
||||||
|
rx.insert(server_handle);
|
||||||
|
poll_readyness(rx, tx);
|
||||||
|
for(auto i : rx) FD_SET(i, &rset);
|
||||||
|
for(auto i : tx) FD_SET(i, &wset);
|
||||||
|
if(!rx.empty()) bound = max(bound, *rx.rbegin() + 1);
|
||||||
|
if(!tx.empty()) bound = max(bound, *tx.rbegin() + 1);
|
||||||
|
int r = select(bound, &rset, &wset, NULL, NULL);
|
||||||
|
for(auto i = rx.begin(); i != rx.end(); i++) {
|
||||||
|
if(FD_ISSET(*i, &rset))
|
||||||
|
i = rx.erase(i);
|
||||||
|
else
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
for(auto i = tx.begin(); i != tx.end(); i++) {
|
||||||
|
if(FD_ISSET(*i, &wset))
|
||||||
|
i = tx.erase(i);
|
||||||
|
else
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
do_rx_tx(rx, tx);
|
||||||
|
if(FD_ISSET(server_handle, &rset))
|
||||||
|
accept();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//Thread function for the server.
|
||||||
|
static int thread_main(void* x)
|
||||||
|
{
|
||||||
|
k_server* _x = reinterpret_cast<k_server*>(x);
|
||||||
|
_x->loop();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
sock_handle_t low_accept();
|
||||||
|
std::list<k_link*> links;
|
||||||
|
sock_handle_t server_handle;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct s_triple
|
||||||
|
{
|
||||||
|
s_triple();
|
||||||
|
s_triple(const std::string& r);
|
||||||
|
std::set<std::string> mods;
|
||||||
|
std::string key;
|
||||||
|
int32_t value;
|
||||||
|
bool ok;
|
||||||
|
operator std::string();
|
||||||
|
};
|
||||||
|
|
||||||
|
s_triple::s_triple() {}
|
||||||
|
s_triple::s_triple(const std::string& r)
|
||||||
|
{
|
||||||
|
ok = false;
|
||||||
|
size_t count;
|
||||||
|
size_t length;
|
||||||
|
char tmp;
|
||||||
|
std::vector<char> tmp3;
|
||||||
|
//size:{length:string}...length:string value
|
||||||
|
std::istringstream x(r);
|
||||||
|
x >> count;
|
||||||
|
if(!x) return; //Bad message.
|
||||||
|
x >> tmp;
|
||||||
|
for(size_t i = 0; i < count; i++) {
|
||||||
|
x >> length;
|
||||||
|
x >> tmp;
|
||||||
|
if(length > r.length())
|
||||||
|
return; //Bad message.
|
||||||
|
tmp3.resize(length);
|
||||||
|
x.read(&tmp3[0], length);
|
||||||
|
if(!x) return; //Bad message
|
||||||
|
std::string tmp2(tmp3.begin(), tmp3.end());
|
||||||
|
mods.insert(tmp2);
|
||||||
|
}
|
||||||
|
x >> length;
|
||||||
|
x >> tmp;
|
||||||
|
if(length > r.length())
|
||||||
|
return; //Bad message.
|
||||||
|
tmp3.resize(length);
|
||||||
|
x.read(&tmp3[0], length);
|
||||||
|
key = std::string(tmp3.begin(), tmp3.end());
|
||||||
|
if(!x) return; //Bad message
|
||||||
|
x >> value;
|
||||||
|
if(x) ok = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
s_triple::operator std::string()
|
||||||
|
{
|
||||||
|
std::ostringstream x;
|
||||||
|
x << mods.size() << ":";
|
||||||
|
for(auto& i : mods)
|
||||||
|
x << i.length() << ":" << i;
|
||||||
|
x << key.length() << ":" << key;
|
||||||
|
x << value;
|
||||||
|
return x.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
void event_handler(keyboard::modifier_set& mods, keyboard::key& key, keyboard::event& event)
|
||||||
|
{
|
||||||
|
if(!client_link)
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::set<keyboard::modifier*> tmp = mods.get_set();
|
||||||
|
std::string _key = key.get_name();
|
||||||
|
int32_t value = event.get_raw();
|
||||||
|
|
||||||
|
std::set<std::string> _mods;
|
||||||
|
for(auto i : tmp)
|
||||||
|
_mods.insert(i->get_name());
|
||||||
|
|
||||||
|
s_triple s;
|
||||||
|
s.mods = _mods;
|
||||||
|
s.key = _key;
|
||||||
|
s.value = value;
|
||||||
|
std::string rep = s;
|
||||||
|
client_link->send(rep);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Inject specified rep.
|
||||||
|
void inject_event(const std::string& rep)
|
||||||
|
{
|
||||||
|
s_triple s(rep);
|
||||||
|
if(!s.ok) {
|
||||||
|
messages << "Warning: inject_event: Skipping malformed message." << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
keyboard::modifier_set _mods;
|
||||||
|
for(auto& i : s.mods) {
|
||||||
|
keyboard::modifier* m = lsnes_kbd.try_lookup_modifier(i);
|
||||||
|
if(m)
|
||||||
|
_mods.add(*m);
|
||||||
|
else
|
||||||
|
messages << "Warning: inject_event: Ignoring unknown modifier '" << i << "'"
|
||||||
|
<< std::endl;
|
||||||
|
}
|
||||||
|
keyboard::key* _key = lsnes_kbd.try_lookup_key(s.key);
|
||||||
|
if(!_key) {
|
||||||
|
messages << "Warning: inject_event: Skipping unknown key '" << s.key << "'"
|
||||||
|
<< std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
platform::queue(keypress(_mods, *_key, s.value));
|
||||||
|
}
|
||||||
|
|
||||||
|
int slave_thread(void* arg)
|
||||||
|
{
|
||||||
|
//TODO.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void keybroadcast_notify_foreground(bool fg)
|
||||||
|
{
|
||||||
|
if(client_link)
|
||||||
|
lsnes_gamepads.master_enable(!fg);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void keybroadcast_set_master(uint16_t port)
|
||||||
|
{
|
||||||
|
//TODO.
|
||||||
|
}
|
||||||
|
|
||||||
|
void keybroadcast_set_slave(uint16_t port)
|
||||||
|
{
|
||||||
|
//TODO.
|
||||||
|
}
|
|
@ -135,6 +135,34 @@ namespace
|
||||||
std::vector<char> stream;
|
std::vector<char> stream;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class keyboard_monitor : public keyboard::event_listener
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
keyboard_monitor() throw()
|
||||||
|
{
|
||||||
|
active = false;
|
||||||
|
}
|
||||||
|
~keyboard_monitor() throw() {}
|
||||||
|
void on_key_event(keyboard::modifier_set& mods, keyboard::key& key, keyboard::event& event)
|
||||||
|
{
|
||||||
|
if(fn) fn(mods, key, event);
|
||||||
|
}
|
||||||
|
bool active;
|
||||||
|
std::function<void(keyboard::modifier_set& mods, keyboard::key& key, keyboard::event& event)> fn;
|
||||||
|
} keyboard_monitor_cb;
|
||||||
|
|
||||||
|
void monitor_all_keys()
|
||||||
|
{
|
||||||
|
for(auto i : lsnes_kbd.all_keys())
|
||||||
|
i->add_listener(keyboard_monitor_cb, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void unmonitor_all_keys()
|
||||||
|
{
|
||||||
|
for(auto i : lsnes_kbd.all_keys())
|
||||||
|
i->remove_listener(keyboard_monitor_cb);
|
||||||
|
}
|
||||||
|
|
||||||
class msgcallback : public messagebuffer::update_handler
|
class msgcallback : public messagebuffer::update_handler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -503,6 +531,24 @@ void platform::queue(void (*f)(void* arg), void* arg, bool sync) throw(std::bad_
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void platform::set_mirror_fn(std::function<void(keyboard::modifier_set& mods, keyboard::key& key,
|
||||||
|
keyboard::event& event)> fn)
|
||||||
|
{
|
||||||
|
if(fn) {
|
||||||
|
keyboard_monitor_cb.fn = fn;
|
||||||
|
if(!keyboard_monitor_cb.active)
|
||||||
|
for(auto i : lsnes_kbd.all_keys())
|
||||||
|
i->add_listener(keyboard_monitor_cb, true);
|
||||||
|
keyboard_monitor_cb.active = true;
|
||||||
|
} else {
|
||||||
|
if(keyboard_monitor_cb.active)
|
||||||
|
for(auto i : lsnes_kbd.all_keys())
|
||||||
|
i->remove_listener(keyboard_monitor_cb);
|
||||||
|
keyboard_monitor_cb.active = false;
|
||||||
|
keyboard_monitor_cb.fn = fn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void platform::run_queues() throw()
|
void platform::run_queues() throw()
|
||||||
{
|
{
|
||||||
internal_run_queues(false);
|
internal_run_queues(false);
|
||||||
|
|
|
@ -226,6 +226,10 @@ unsigned pad::add_hat(uint64_t idx, uint64_t idy, int64_t mindev, const std::str
|
||||||
void pad::report_axis(uint64_t id, int64_t val)
|
void pad::report_axis(uint64_t id, int64_t val)
|
||||||
{
|
{
|
||||||
mutex.lock();
|
mutex.lock();
|
||||||
|
if(!enabled) {
|
||||||
|
mutex.unlock();
|
||||||
|
return;
|
||||||
|
}
|
||||||
if(_axes.count(id)) {
|
if(_axes.count(id)) {
|
||||||
axis_info& i = _axes[id];
|
axis_info& i = _axes[id];
|
||||||
int16_t val2 = map_value(val, i.minus, i.zero, i.plus, i.neutral, i.pressure);
|
int16_t val2 = map_value(val, i.minus, i.zero, i.plus, i.neutral, i.pressure);
|
||||||
|
@ -258,6 +262,10 @@ void pad::report_axis(uint64_t id, int64_t val)
|
||||||
void pad::report_button(uint64_t id, bool val)
|
void pad::report_button(uint64_t id, bool val)
|
||||||
{
|
{
|
||||||
mutex.lock();
|
mutex.lock();
|
||||||
|
if(!enabled) {
|
||||||
|
mutex.unlock();
|
||||||
|
return;
|
||||||
|
}
|
||||||
if(!_buttons.count(id)) {
|
if(!_buttons.count(id)) {
|
||||||
mutex.unlock();
|
mutex.unlock();
|
||||||
return;
|
return;
|
||||||
|
@ -275,6 +283,10 @@ void pad::report_button(uint64_t id, bool val)
|
||||||
void pad::report_hat(uint64_t id, int angle)
|
void pad::report_hat(uint64_t id, int angle)
|
||||||
{
|
{
|
||||||
mutex.lock();
|
mutex.lock();
|
||||||
|
if(!enabled) {
|
||||||
|
mutex.unlock();
|
||||||
|
return;
|
||||||
|
}
|
||||||
unsigned h = angle_to_bitmask(angle);
|
unsigned h = angle_to_bitmask(angle);
|
||||||
if(!_hats.count(id)) {
|
if(!_hats.count(id)) {
|
||||||
mutex.unlock();
|
mutex.unlock();
|
||||||
|
@ -623,8 +635,15 @@ std::string pad::get_summary()
|
||||||
return x.str();
|
return x.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void pad::master_enable(bool state)
|
||||||
|
{
|
||||||
|
umutex_class H(mutex);
|
||||||
|
enabled = state;
|
||||||
|
}
|
||||||
|
|
||||||
set::set()
|
set::set()
|
||||||
{
|
{
|
||||||
|
enabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
set::~set()
|
set::~set()
|
||||||
|
@ -711,6 +730,7 @@ unsigned set::add(const std::string& name)
|
||||||
gp->set_axismode_cb(amode_fn);
|
gp->set_axismode_cb(amode_fn);
|
||||||
gp->set_newitem_cb(newitem_fn);
|
gp->set_newitem_cb(newitem_fn);
|
||||||
_gamepads.push_back(gp);
|
_gamepads.push_back(gp);
|
||||||
|
gp->master_enable(enabled);
|
||||||
return _gamepads.size() - 1;
|
return _gamepads.size() - 1;
|
||||||
} catch(...) {
|
} catch(...) {
|
||||||
delete gp;
|
delete gp;
|
||||||
|
@ -765,4 +785,13 @@ std::string set::get_summary()
|
||||||
x << i->get_summary();
|
x << i->get_summary();
|
||||||
return x.str();
|
return x.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void set::master_enable(bool state)
|
||||||
|
{
|
||||||
|
umutex_class h(mutex);
|
||||||
|
enabled = state;
|
||||||
|
for(auto i : _gamepads)
|
||||||
|
i->master_enable(state);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -259,24 +259,24 @@ key::~key() throw()
|
||||||
register_queue<keyboard, key>::do_unregister(kbd, name);
|
register_queue<keyboard, key>::do_unregister(kbd, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
event_key::event_key(uint32_t chngmask)
|
event_key::event_key(uint32_t chngmask, int32_t _raw)
|
||||||
: event(chngmask, keytype::KBD_KEYTYPE_KEY)
|
: event(chngmask, keytype::KBD_KEYTYPE_KEY, _raw)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
event_axis::event_axis(int32_t _state, uint32_t chngmask)
|
event_axis::event_axis(int32_t _state, uint32_t chngmask, int32_t _raw)
|
||||||
: event(chngmask, keytype::KBD_KEYTYPE_AXIS)
|
: event(chngmask, keytype::KBD_KEYTYPE_AXIS, _raw)
|
||||||
{
|
{
|
||||||
state = _state;
|
state = _state;
|
||||||
}
|
}
|
||||||
|
|
||||||
event_hat::event_hat(uint32_t chngmask)
|
event_hat::event_hat(uint32_t chngmask, int32_t _raw)
|
||||||
: event(chngmask, keytype::KBD_KEYTYPE_HAT)
|
: event(chngmask, keytype::KBD_KEYTYPE_HAT, _raw)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
event_mouse::event_mouse(int32_t _state, const mouse_calibration& _cal)
|
event_mouse::event_mouse(int32_t _state, const mouse_calibration& _cal, int32_t _raw)
|
||||||
: event(0, keytype::KBD_KEYTYPE_MOUSE)
|
: event(0, keytype::KBD_KEYTYPE_MOUSE, _raw)
|
||||||
{
|
{
|
||||||
state = _state;
|
state = _state;
|
||||||
cal = _cal;
|
cal = _cal;
|
||||||
|
@ -397,7 +397,7 @@ void key_key::set_state(modifier_set mods, int32_t _state) throw()
|
||||||
}
|
}
|
||||||
mutex.unlock();
|
mutex.unlock();
|
||||||
if(edge) {
|
if(edge) {
|
||||||
event_key e(change);
|
event_key e(change, _state);
|
||||||
call_listeners(mods, e);
|
call_listeners(mods, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -441,7 +441,7 @@ void key_hat::set_state(modifier_set mods, int32_t _state) throw()
|
||||||
}
|
}
|
||||||
mutex.unlock();
|
mutex.unlock();
|
||||||
if(edge) {
|
if(edge) {
|
||||||
event_hat e(change);
|
event_hat e(change, _state);
|
||||||
call_listeners(mods, e);
|
call_listeners(mods, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -534,7 +534,7 @@ void key_axis::set_state(modifier_set mods, int32_t _rawstate) throw()
|
||||||
}
|
}
|
||||||
mutex.unlock();
|
mutex.unlock();
|
||||||
if(edge) {
|
if(edge) {
|
||||||
event_axis e(state, change);
|
event_axis e(state, change, _rawstate);
|
||||||
call_listeners(mods, e);
|
call_listeners(mods, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -589,7 +589,7 @@ void key_mouse::set_state(modifier_set mods, int32_t _rawstate) throw()
|
||||||
}
|
}
|
||||||
mutex.unlock();
|
mutex.unlock();
|
||||||
if(edge) {
|
if(edge) {
|
||||||
event_mouse e(state, _cal);
|
event_mouse e(state, _cal, _rawstate);
|
||||||
call_listeners(mods, e);
|
call_listeners(mods, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -599,8 +599,9 @@ void key_mouse::set_calibration(mouse_calibration _cal) throw()
|
||||||
mutex.lock();
|
mutex.lock();
|
||||||
cal = _cal;
|
cal = _cal;
|
||||||
int32_t state = cal.get_calibrated_value(rawstate);
|
int32_t state = cal.get_calibrated_value(rawstate);
|
||||||
|
int32_t lraw = rawstate;
|
||||||
mutex.unlock();
|
mutex.unlock();
|
||||||
event_mouse e(state, _cal);
|
event_mouse e(state, _cal, lraw);
|
||||||
modifier_set mods;
|
modifier_set mods;
|
||||||
call_listeners(mods, e);
|
call_listeners(mods, e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include "core/dispatch.hpp"
|
#include "core/dispatch.hpp"
|
||||||
#include "core/framebuffer.hpp"
|
#include "core/framebuffer.hpp"
|
||||||
#include "core/framerate.hpp"
|
#include "core/framerate.hpp"
|
||||||
|
#include "core/keybroadcast.hpp"
|
||||||
#include "core/keymapper.hpp"
|
#include "core/keymapper.hpp"
|
||||||
#include "interface/romtype.hpp"
|
#include "interface/romtype.hpp"
|
||||||
#include "core/loadlib.hpp"
|
#include "core/loadlib.hpp"
|
||||||
|
@ -181,7 +182,7 @@ namespace
|
||||||
{
|
{
|
||||||
was_focused = (wxWindow::FindFocus() != NULL);
|
was_focused = (wxWindow::FindFocus() != NULL);
|
||||||
was_enabled = platform::is_sound_enabled();
|
was_enabled = platform::is_sound_enabled();
|
||||||
Start(500);
|
Start(100);
|
||||||
}
|
}
|
||||||
void Notify()
|
void Notify()
|
||||||
{
|
{
|
||||||
|
@ -196,6 +197,7 @@ namespace
|
||||||
if(!background_audio)
|
if(!background_audio)
|
||||||
platform::sound_enable(false);
|
platform::sound_enable(false);
|
||||||
}
|
}
|
||||||
|
keybroadcast_notify_foreground(is_focused);
|
||||||
was_focused = is_focused;
|
was_focused = is_focused;
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
|
|
Loading…
Add table
Reference in a new issue