mirror of https://github.com/bsnes-emu/bsnes.git
387 lines
12 KiB
C++
387 lines
12 KiB
C++
|
#ifndef NALL_INPUT_HPP
|
||
|
#define NALL_INPUT_HPP
|
||
|
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
|
||
|
#include <nall/stdint.hpp>
|
||
|
#include <nall/string.hpp>
|
||
|
|
||
|
namespace nall {
|
||
|
|
||
|
struct Keyboard;
|
||
|
Keyboard& keyboard(unsigned = 0);
|
||
|
|
||
|
static const char KeyboardScancodeName[][64] = {
|
||
|
"Escape", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12",
|
||
|
"PrintScreen", "ScrollLock", "Pause", "Tilde",
|
||
|
"Num1", "Num2", "Num3", "Num4", "Num5", "Num6", "Num7", "Num8", "Num9", "Num0",
|
||
|
"Dash", "Equal", "Backspace",
|
||
|
"Insert", "Delete", "Home", "End", "PageUp", "PageDown",
|
||
|
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M",
|
||
|
"N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
|
||
|
"LeftBracket", "RightBracket", "Backslash", "Semicolon", "Apostrophe", "Comma", "Period", "Slash",
|
||
|
"Keypad1", "Keypad2", "Keypad3", "Keypad4", "Keypad5", "Keypad6", "Keypad7", "Keypad8", "Keypad9", "Keypad0",
|
||
|
"Point", "Enter", "Add", "Subtract", "Multiply", "Divide",
|
||
|
"NumLock", "CapsLock",
|
||
|
"Up", "Down", "Left", "Right",
|
||
|
"Tab", "Return", "Spacebar", "Menu",
|
||
|
"Shift", "Control", "Alt", "Super",
|
||
|
};
|
||
|
|
||
|
struct Keyboard {
|
||
|
const unsigned ID;
|
||
|
enum { Base = 1 };
|
||
|
enum { Count = 8, Size = 128 };
|
||
|
|
||
|
enum Scancode {
|
||
|
Escape, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12,
|
||
|
PrintScreen, ScrollLock, Pause, Tilde,
|
||
|
Num1, Num2, Num3, Num4, Num5, Num6, Num7, Num8, Num9, Num0,
|
||
|
Dash, Equal, Backspace,
|
||
|
Insert, Delete, Home, End, PageUp, PageDown,
|
||
|
A, B, C, D, E, F, G, H, I, J, K, L, M,
|
||
|
N, O, P, Q, R, S, T, U, V, W, X, Y, Z,
|
||
|
LeftBracket, RightBracket, Backslash, Semicolon, Apostrophe, Comma, Period, Slash,
|
||
|
Keypad1, Keypad2, Keypad3, Keypad4, Keypad5, Keypad6, Keypad7, Keypad8, Keypad9, Keypad0,
|
||
|
Point, Enter, Add, Subtract, Multiply, Divide,
|
||
|
NumLock, CapsLock,
|
||
|
Up, Down, Left, Right,
|
||
|
Tab, Return, Spacebar, Menu,
|
||
|
Shift, Control, Alt, Super,
|
||
|
Limit,
|
||
|
};
|
||
|
|
||
|
static signed numberDecode(uint16_t scancode) {
|
||
|
for(unsigned i = 0; i < Count; i++) {
|
||
|
if(keyboard(i).belongsTo(scancode)) return i;
|
||
|
}
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
static signed keyDecode(uint16_t scancode) {
|
||
|
for(unsigned i = 0; i < Count; i++) {
|
||
|
if(keyboard(i).isKey(scancode)) return scancode - keyboard(i).key(Escape);
|
||
|
}
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
static signed modifierDecode(uint16_t scancode) {
|
||
|
for(unsigned i = 0; i < Count; i++) {
|
||
|
if(keyboard(i).isModifier(scancode)) return scancode - keyboard(i).key(Shift);
|
||
|
}
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
static bool isAnyKey(uint16_t scancode) {
|
||
|
for(unsigned i = 0; i < Count; i++) {
|
||
|
if(keyboard(i).isKey(scancode)) return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
static bool isAnyModifier(uint16_t scancode) {
|
||
|
for(unsigned i = 0; i < Count; i++) {
|
||
|
if(keyboard(i).isModifier(scancode)) return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
static uint16_t decode(const char *name) {
|
||
|
string s(name);
|
||
|
if(!strbegin(name, "KB")) return 0;
|
||
|
s.ltrim("KB");
|
||
|
unsigned id = decimal(s);
|
||
|
auto pos = strpos(s, "::");
|
||
|
if(!pos) return 0;
|
||
|
s = substr(s, pos() + 2);
|
||
|
for(unsigned i = 0; i < Limit; i++) {
|
||
|
if(s == KeyboardScancodeName[i]) return Base + Size * id + i;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
string encode(uint16_t code) const {
|
||
|
unsigned index = 0;
|
||
|
for(unsigned i = 0; i < Count; i++) {
|
||
|
if(code >= Base + Size * i && code < Base + Size * (i + 1)) {
|
||
|
index = code - (Base + Size * i);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
return string() << "KB" << ID << "::" << KeyboardScancodeName[index];
|
||
|
}
|
||
|
|
||
|
uint16_t operator[](Scancode code) const { return Base + ID * Size + code; }
|
||
|
uint16_t key(unsigned id) const { return Base + Size * ID + id; }
|
||
|
bool isKey(unsigned id) const { return id >= key(Escape) && id <= key(Menu); }
|
||
|
bool isModifier(unsigned id) const { return id >= key(Shift) && id <= key(Super); }
|
||
|
bool belongsTo(uint16_t scancode) const { return isKey(scancode) || isModifier(scancode); }
|
||
|
|
||
|
Keyboard(unsigned ID_) : ID(ID_) {}
|
||
|
};
|
||
|
|
||
|
inline Keyboard& keyboard(unsigned id) {
|
||
|
static Keyboard kb0(0), kb1(1), kb2(2), kb3(3), kb4(4), kb5(5), kb6(6), kb7(7);
|
||
|
switch(id) { default:
|
||
|
case 0: return kb0; case 1: return kb1; case 2: return kb2; case 3: return kb3;
|
||
|
case 4: return kb4; case 5: return kb5; case 6: return kb6; case 7: return kb7;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static const char MouseScancodeName[][64] = {
|
||
|
"Xaxis", "Yaxis", "Zaxis",
|
||
|
"Button0", "Button1", "Button2", "Button3", "Button4", "Button5", "Button6", "Button7",
|
||
|
};
|
||
|
|
||
|
struct Mouse;
|
||
|
Mouse& mouse(unsigned = 0);
|
||
|
|
||
|
struct Mouse {
|
||
|
const unsigned ID;
|
||
|
enum { Base = Keyboard::Base + Keyboard::Size * Keyboard::Count };
|
||
|
enum { Count = 8, Size = 16 };
|
||
|
enum { Axes = 3, Buttons = 8 };
|
||
|
|
||
|
enum Scancode {
|
||
|
Xaxis, Yaxis, Zaxis,
|
||
|
Button0, Button1, Button2, Button3, Button4, Button5, Button6, Button7,
|
||
|
Limit,
|
||
|
};
|
||
|
|
||
|
static signed numberDecode(uint16_t scancode) {
|
||
|
for(unsigned i = 0; i < Count; i++) {
|
||
|
if(mouse(i).belongsTo(scancode)) return i;
|
||
|
}
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
static signed axisDecode(uint16_t scancode) {
|
||
|
for(unsigned i = 0; i < Count; i++) {
|
||
|
if(mouse(i).isAxis(scancode)) return scancode - mouse(i).axis(0);
|
||
|
}
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
static signed buttonDecode(uint16_t scancode) {
|
||
|
for(unsigned i = 0; i < Count; i++) {
|
||
|
if(mouse(i).isButton(scancode)) return scancode - mouse(i).button(0);
|
||
|
}
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
static bool isAnyAxis(uint16_t scancode) {
|
||
|
for(unsigned i = 0; i < Count; i++) {
|
||
|
if(mouse(i).isAxis(scancode)) return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
static bool isAnyButton(uint16_t scancode) {
|
||
|
for(unsigned i = 0; i < Count; i++) {
|
||
|
if(mouse(i).isButton(scancode)) return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
static uint16_t decode(const char *name) {
|
||
|
string s(name);
|
||
|
if(!strbegin(name, "MS")) return 0;
|
||
|
s.ltrim("MS");
|
||
|
unsigned id = decimal(s);
|
||
|
auto pos = strpos(s, "::");
|
||
|
if(!pos) return 0;
|
||
|
s = substr(s, pos() + 2);
|
||
|
for(unsigned i = 0; i < Limit; i++) {
|
||
|
if(s == MouseScancodeName[i]) return Base + Size * id + i;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
string encode(uint16_t code) const {
|
||
|
unsigned index = 0;
|
||
|
for(unsigned i = 0; i < Count; i++) {
|
||
|
if(code >= Base + Size * i && code < Base + Size * (i + 1)) {
|
||
|
index = code - (Base + Size * i);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
return string() << "MS" << ID << "::" << MouseScancodeName[index];
|
||
|
}
|
||
|
|
||
|
uint16_t operator[](Scancode code) const { return Base + ID * Size + code; }
|
||
|
uint16_t axis(unsigned id) const { return Base + Size * ID + Xaxis + id; }
|
||
|
uint16_t button(unsigned id) const { return Base + Size * ID + Button0 + id; }
|
||
|
bool isAxis(unsigned id) const { return id >= axis(0) && id <= axis(2); }
|
||
|
bool isButton(unsigned id) const { return id >= button(0) && id <= button(7); }
|
||
|
bool belongsTo(uint16_t scancode) const { return isAxis(scancode) || isButton(scancode); }
|
||
|
|
||
|
Mouse(unsigned ID_) : ID(ID_) {}
|
||
|
};
|
||
|
|
||
|
inline Mouse& mouse(unsigned id) {
|
||
|
static Mouse ms0(0), ms1(1), ms2(2), ms3(3), ms4(4), ms5(5), ms6(6), ms7(7);
|
||
|
switch(id) { default:
|
||
|
case 0: return ms0; case 1: return ms1; case 2: return ms2; case 3: return ms3;
|
||
|
case 4: return ms4; case 5: return ms5; case 6: return ms6; case 7: return ms7;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static const char JoypadScancodeName[][64] = {
|
||
|
"Hat0", "Hat1", "Hat2", "Hat3", "Hat4", "Hat5", "Hat6", "Hat7",
|
||
|
"Axis0", "Axis1", "Axis2", "Axis3", "Axis4", "Axis5", "Axis6", "Axis7",
|
||
|
"Axis8", "Axis9", "Axis10", "Axis11", "Axis12", "Axis13", "Axis14", "Axis15",
|
||
|
"Button0", "Button1", "Button2", "Button3", "Button4", "Button5", "Button6", "Button7",
|
||
|
"Button8", "Button9", "Button10", "Button11", "Button12", "Button13", "Button14", "Button15",
|
||
|
"Button16", "Button17", "Button18", "Button19", "Button20", "Button21", "Button22", "Button23",
|
||
|
"Button24", "Button25", "Button26", "Button27", "Button28", "Button29", "Button30", "Button31",
|
||
|
};
|
||
|
|
||
|
struct Joypad;
|
||
|
Joypad& joypad(unsigned = 0);
|
||
|
|
||
|
struct Joypad {
|
||
|
const unsigned ID;
|
||
|
enum { Base = Mouse::Base + Mouse::Size * Mouse::Count };
|
||
|
enum { Count = 8, Size = 64 };
|
||
|
enum { Hats = 8, Axes = 16, Buttons = 32 };
|
||
|
|
||
|
enum Scancode {
|
||
|
Hat0, Hat1, Hat2, Hat3, Hat4, Hat5, Hat6, Hat7,
|
||
|
Axis0, Axis1, Axis2, Axis3, Axis4, Axis5, Axis6, Axis7,
|
||
|
Axis8, Axis9, Axis10, Axis11, Axis12, Axis13, Axis14, Axis15,
|
||
|
Button0, Button1, Button2, Button3, Button4, Button5, Button6, Button7,
|
||
|
Button8, Button9, Button10, Button11, Button12, Button13, Button14, Button15,
|
||
|
Button16, Button17, Button18, Button19, Button20, Button21, Button22, Button23,
|
||
|
Button24, Button25, Button26, Button27, Button28, Button29, Button30, Button31,
|
||
|
Limit,
|
||
|
};
|
||
|
|
||
|
enum Hat { HatCenter = 0, HatUp = 1, HatRight = 2, HatDown = 4, HatLeft = 8 };
|
||
|
|
||
|
static signed numberDecode(uint16_t scancode) {
|
||
|
for(unsigned i = 0; i < Count; i++) {
|
||
|
if(joypad(i).belongsTo(scancode)) return i;
|
||
|
}
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
static signed hatDecode(uint16_t scancode) {
|
||
|
for(unsigned i = 0; i < Count; i++) {
|
||
|
if(joypad(i).isHat(scancode)) return scancode - joypad(i).hat(0);
|
||
|
}
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
static signed axisDecode(uint16_t scancode) {
|
||
|
for(unsigned i = 0; i < Count; i++) {
|
||
|
if(joypad(i).isAxis(scancode)) return scancode - joypad(i).axis(0);
|
||
|
}
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
static signed buttonDecode(uint16_t scancode) {
|
||
|
for(unsigned i = 0; i < Count; i++) {
|
||
|
if(joypad(i).isButton(scancode)) return scancode - joypad(i).button(0);
|
||
|
}
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
static bool isAnyHat(uint16_t scancode) {
|
||
|
for(unsigned i = 0; i < Count; i++) {
|
||
|
if(joypad(i).isHat(scancode)) return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
static bool isAnyAxis(uint16_t scancode) {
|
||
|
for(unsigned i = 0; i < Count; i++) {
|
||
|
if(joypad(i).isAxis(scancode)) return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
static bool isAnyButton(uint16_t scancode) {
|
||
|
for(unsigned i = 0; i < Count; i++) {
|
||
|
if(joypad(i).isButton(scancode)) return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
static uint16_t decode(const char *name) {
|
||
|
string s(name);
|
||
|
if(!strbegin(name, "JP")) return 0;
|
||
|
s.ltrim("JP");
|
||
|
unsigned id = decimal(s);
|
||
|
auto pos = strpos(s, "::");
|
||
|
if(!pos) return 0;
|
||
|
s = substr(s, pos() + 2);
|
||
|
for(unsigned i = 0; i < Limit; i++) {
|
||
|
if(s == JoypadScancodeName[i]) return Base + Size * id + i;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
string encode(uint16_t code) const {
|
||
|
unsigned index = 0;
|
||
|
for(unsigned i = 0; i < Count; i++) {
|
||
|
if(code >= Base + Size * i && code < Base + Size * (i + 1)) {
|
||
|
index = code - (Base + Size * i);
|
||
|
}
|
||
|
}
|
||
|
return string() << "JP" << ID << "::" << JoypadScancodeName[index];
|
||
|
}
|
||
|
|
||
|
uint16_t operator[](Scancode code) const { return Base + ID * Size + code; }
|
||
|
uint16_t hat(unsigned id) const { return Base + Size * ID + Hat0 + id; }
|
||
|
uint16_t axis(unsigned id) const { return Base + Size * ID + Axis0 + id; }
|
||
|
uint16_t button(unsigned id) const { return Base + Size * ID + Button0 + id; }
|
||
|
bool isHat(unsigned id) const { return id >= hat(0) && id <= hat(7); }
|
||
|
bool isAxis(unsigned id) const { return id >= axis(0) && id <= axis(15); }
|
||
|
bool isButton(unsigned id) const { return id >= button(0) && id <= button(31); }
|
||
|
bool belongsTo(uint16_t scancode) const { return isHat(scancode) || isAxis(scancode) || isButton(scancode); }
|
||
|
|
||
|
Joypad(unsigned ID_) : ID(ID_) {}
|
||
|
};
|
||
|
|
||
|
inline Joypad& joypad(unsigned id) {
|
||
|
static Joypad jp0(0), jp1(1), jp2(2), jp3(3), jp4(4), jp5(5), jp6(6), jp7(7);
|
||
|
switch(id) { default:
|
||
|
case 0: return jp0; case 1: return jp1; case 2: return jp2; case 3: return jp3;
|
||
|
case 4: return jp4; case 5: return jp5; case 6: return jp6; case 7: return jp7;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
struct Scancode {
|
||
|
enum { None = 0, Limit = Joypad::Base + Joypad::Size * Joypad::Count };
|
||
|
|
||
|
static uint16_t decode(const char *name) {
|
||
|
uint16_t code;
|
||
|
code = Keyboard::decode(name);
|
||
|
if(code) return code;
|
||
|
code = Mouse::decode(name);
|
||
|
if(code) return code;
|
||
|
code = Joypad::decode(name);
|
||
|
if(code) return code;
|
||
|
return None;
|
||
|
}
|
||
|
|
||
|
static string encode(uint16_t code) {
|
||
|
for(unsigned i = 0; i < Keyboard::Count; i++) {
|
||
|
if(keyboard(i).belongsTo(code)) return keyboard(i).encode(code);
|
||
|
}
|
||
|
for(unsigned i = 0; i < Mouse::Count; i++) {
|
||
|
if(mouse(i).belongsTo(code)) return mouse(i).encode(code);
|
||
|
}
|
||
|
for(unsigned i = 0; i < Joypad::Count; i++) {
|
||
|
if(joypad(i).belongsTo(code)) return joypad(i).encode(code);
|
||
|
}
|
||
|
return "None";
|
||
|
}
|
||
|
};
|
||
|
|
||
|
}
|
||
|
|
||
|
#endif
|