Compare commits
2 Commits
c6e4d17ffb
...
7e191d0bab
Author | SHA1 | Date |
---|---|---|
Sascha Nitsch | 7e191d0bab | |
Sascha Nitsch | a239af8d0a |
|
@ -7,3 +7,9 @@
|
||||||
/electronics/cimdit.kicad_prl
|
/electronics/cimdit.kicad_prl
|
||||||
/electronics/fp-info-cache
|
/electronics/fp-info-cache
|
||||||
/spec.d
|
/spec.d
|
||||||
|
/html
|
||||||
|
profilegenerator/.tscache
|
||||||
|
profilegenerator/node_modules
|
||||||
|
profilegenerator/tmp
|
||||||
|
profilegenerator/package-lock.json
|
||||||
|
profilegenerator/ts/.baseDir.ts
|
||||||
|
|
148
cimdit.ino
148
cimdit.ino
|
@ -6,34 +6,18 @@
|
||||||
* Licensed under MIT license
|
* Licensed under MIT license
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
// defines
|
||||||
/// use a custom keyboard layout
|
#include "defines.h"
|
||||||
#define HID_CUSTOM_LAYOUT
|
|
||||||
/// use german keyboard layout
|
|
||||||
#define LAYOUT_GERMAN
|
|
||||||
#define HAVE_DISPLAY
|
|
||||||
#ifdef HAVE_DISPLAY
|
|
||||||
/// no splash screen on OLED
|
|
||||||
#define SSD1306_NO_SPLASH
|
|
||||||
/// OLED display width, in pixels
|
|
||||||
#define SCREEN_WIDTH 128
|
|
||||||
/// OLED display height, in pixels
|
|
||||||
#define SCREEN_HEIGHT 32
|
|
||||||
/// OLED screen address
|
|
||||||
#define SCREEN_ADDRESS 0x3C
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// library includes
|
// library includes
|
||||||
#include <HID-Project.h>
|
#include <HID-Project.h>
|
||||||
#ifdef HAVE_DISPLAY
|
#ifdef HAVE_DISPLAY
|
||||||
#include <Adafruit_SSD1306.h>
|
#include "cimditssd1306.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// own includes
|
// own includes
|
||||||
#include "cimdithal.h"
|
#include "cimdithal.h"
|
||||||
|
#include "cimditprofile.h"
|
||||||
/// update usb devices every x ms if needed
|
|
||||||
#define UPDATE_INTERVAL 100
|
|
||||||
|
|
||||||
/// our hardware abstraction layer
|
/// our hardware abstraction layer
|
||||||
CimditHAL hal;
|
CimditHAL hal;
|
||||||
|
@ -48,29 +32,44 @@ void rotInt() {
|
||||||
|
|
||||||
/// next update time in ms
|
/// next update time in ms
|
||||||
uint32_t nextUpdate = 0;
|
uint32_t nextUpdate = 0;
|
||||||
|
|
||||||
#ifdef HAVE_DISPLAY
|
#ifdef HAVE_DISPLAY
|
||||||
/// our display
|
/// our display
|
||||||
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
|
CimditSSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_ADDRESS);
|
||||||
#endif
|
#endif
|
||||||
/// display
|
|
||||||
///
|
// our profile handling class
|
||||||
|
CimditProfile profile;
|
||||||
|
|
||||||
/// initial setup
|
/// initial setup
|
||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
hal.begin();
|
hal.begin();
|
||||||
attachInterrupt(digitalPinToInterrupt(7), rotInt, RISING);
|
attachInterrupt(digitalPinToInterrupt(7), rotInt, RISING);
|
||||||
// initialize USB related things
|
// initialize USB related things
|
||||||
Keyboard.begin();
|
Keyboard.begin();
|
||||||
Mouse.begin();
|
Mouse.begin();
|
||||||
Gamepad.begin();
|
Gamepad.begin();
|
||||||
|
Wire.begin();
|
||||||
|
Wire.setClock(400000);
|
||||||
#ifdef HAVE_DISPLAY
|
#ifdef HAVE_DISPLAY
|
||||||
// init display
|
// init display
|
||||||
display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS);
|
display.begin();
|
||||||
display.clearDisplay();
|
display.clearDisplay();
|
||||||
|
display.setTextSize(2,2);
|
||||||
|
display.setCursor(28, 8);
|
||||||
|
display.write("cimdit");
|
||||||
display.display();
|
display.display();
|
||||||
#endif
|
#endif
|
||||||
|
profile.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// protection string
|
||||||
|
const char protectString[] = "cimdit:";
|
||||||
|
|
||||||
|
/// current position in protection string
|
||||||
|
uint8_t protectPos = 0;
|
||||||
|
|
||||||
/// main loop
|
/// main loop
|
||||||
void loop() {
|
void loop() {
|
||||||
hal.readFromHardware(outstandingRotInterrupt);
|
hal.readFromHardware(outstandingRotInterrupt);
|
||||||
|
@ -78,18 +77,62 @@ void loop() {
|
||||||
outstandingRotInterrupt = false;
|
outstandingRotInterrupt = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
profile.tick();
|
||||||
|
if (Serial.available()) {
|
||||||
|
// incoming message
|
||||||
|
uint8_t in;
|
||||||
|
while ((in = Serial.read()) != 255) {
|
||||||
|
if (protectString[protectPos++] != in) {
|
||||||
|
protectPos = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (protectPos == sizeof(protectString) - 1) { // good, something for us
|
||||||
|
protectPos = 0;
|
||||||
|
// every line has to start with cimdit: or it will be ignored
|
||||||
|
uint8_t cmd = Serial.read();
|
||||||
|
switch (cmd) {
|
||||||
|
case 'd':
|
||||||
|
profile.userDisplay();
|
||||||
|
break;
|
||||||
|
case 'p': { // print something on display
|
||||||
|
uint8_t timeout = 0;
|
||||||
|
// read number for time to display
|
||||||
|
do {
|
||||||
|
cmd = Serial.read();
|
||||||
|
if (cmd != ',') {
|
||||||
|
timeout = timeout * 10 + cmd - '0';
|
||||||
|
}
|
||||||
|
} while (cmd != ',');
|
||||||
|
char tmp[43] = {0};
|
||||||
|
uint8_t pos = 0;
|
||||||
|
// now we expect the string, terminated by \n
|
||||||
|
do {
|
||||||
|
cmd = Serial.read();
|
||||||
|
if (cmd != '\n') {
|
||||||
|
tmp[pos++] = cmd;
|
||||||
|
}
|
||||||
|
} while (cmd != '\n' && pos < 43 && cmd != 255);
|
||||||
|
profile.setUserString(timeout, tmp);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'f': // read flash
|
||||||
|
profile.printFlash();
|
||||||
|
break;
|
||||||
|
case 'F': // write flash
|
||||||
|
profile.writeFlash();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if (hal.m_millis < nextUpdate && hal.m_millis > ROLLOVER_INTERVAL) return;
|
if (hal.m_millis < nextUpdate && hal.m_millis > ROLLOVER_INTERVAL) return;
|
||||||
nextUpdate = hal.m_millis + UPDATE_INTERVAL;
|
nextUpdate = hal.m_millis + UPDATE_INTERVAL;
|
||||||
uint8_t rotaryChanged = hal.rotaryChanged();
|
uint8_t rotaryChanged = hal.rotaryChanged();
|
||||||
if (rotaryChanged) {
|
if (rotaryChanged) {
|
||||||
for (uint8_t i = 0; i < 7; ++i) {
|
for (uint8_t i = 0; i < 8; ++i) {
|
||||||
if (rotaryChanged & 1) {
|
if (rotaryChanged & 1) {
|
||||||
// temporary debug output
|
int8_t delta = hal.getEncoder(i);
|
||||||
Serial.print(F("rot "));
|
profile.rotaryAction(i, delta);
|
||||||
Serial.print(i);
|
|
||||||
Serial.print(F(" => "));
|
|
||||||
Serial.println(hal.getEncoder(i));
|
|
||||||
// end of temporary debug output
|
|
||||||
}
|
}
|
||||||
rotaryChanged >>= 1;
|
rotaryChanged >>= 1;
|
||||||
}
|
}
|
||||||
|
@ -99,59 +142,24 @@ void loop() {
|
||||||
for (uint8_t i = 0; i < 4; ++i) {
|
for (uint8_t i = 0; i < 4; ++i) {
|
||||||
if (analogChanged & 1) {
|
if (analogChanged & 1) {
|
||||||
uint16_t analog = hal.getAnalog(i);
|
uint16_t analog = hal.getAnalog(i);
|
||||||
// temporary debug output
|
profile.axisAction(i, analog);
|
||||||
int16_t analogMapped16 = map(analog, 0, 1024, -32767, 32768);
|
|
||||||
int8_t analogMapped8 = map(analog, 0, 1024, -127, 127);
|
|
||||||
switch(i) {
|
|
||||||
case 0:
|
|
||||||
Gamepad.xAxis(analogMapped16);
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
Gamepad.yAxis(analogMapped16);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
Gamepad.zAxis(analogMapped8);
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
Gamepad.rxAxis(analogMapped16);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
Serial.print(F("analog "));
|
|
||||||
Serial.print(i);
|
|
||||||
Serial.print(F(": "));
|
|
||||||
Serial.println(analogMapped16);
|
|
||||||
// end of temporary debug output
|
|
||||||
}
|
}
|
||||||
analogChanged >>= 1;
|
analogChanged >>= 1;
|
||||||
}
|
}
|
||||||
Gamepad.write();
|
Gamepad.write();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t buttonsChanged = hal.buttonsChanged();
|
uint64_t buttonsChanged = hal.buttonsChanged();
|
||||||
if (buttonsChanged) {
|
if (buttonsChanged) {
|
||||||
for (uint8_t i = 0; i < 64; ++i) {
|
for (uint8_t i = 0; i < 64; ++i) {
|
||||||
if (buttonsChanged & 0xFF) { // quickcheck for 8 bits at a time
|
if (buttonsChanged & 0xFF) { // quickcheck for 8 bits at a time
|
||||||
if (buttonsChanged & 1) {
|
if (buttonsChanged & 1) {
|
||||||
// temporary debug output
|
|
||||||
Serial.print(F("button "));
|
|
||||||
Serial.print(i);
|
|
||||||
Serial.print(F(" "));
|
|
||||||
bool pressed = hal.getButton(i);
|
bool pressed = hal.getButton(i);
|
||||||
Serial.println(pressed);
|
profile.buttonAction(i, pressed);
|
||||||
if (i<32) {
|
|
||||||
if (pressed)
|
|
||||||
Gamepad.press(i+1);
|
|
||||||
else
|
|
||||||
Gamepad.release(i+1);
|
|
||||||
}
|
|
||||||
// end of temporary debug output
|
|
||||||
}
|
}
|
||||||
buttonsChanged >>= 1;
|
buttonsChanged >>= 1;
|
||||||
} else {
|
} else {
|
||||||
buttonsChanged >>= 8;
|
buttonsChanged >>= 8;
|
||||||
i += 8;
|
i += 7;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,23 +6,9 @@
|
||||||
* Licensed under MIT license
|
* Licensed under MIT license
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
/// pin for analog mux bit 0
|
// our defines
|
||||||
#define ANALOG_MUX0 6
|
#include "defines.h"
|
||||||
/// pin for analog mux bit 1
|
|
||||||
#define ANALOG_MUX1 8
|
|
||||||
/// pin for analog mux bit 2
|
|
||||||
#define ANALOG_MUX2 9
|
|
||||||
/// pin for analog mux bit 3
|
|
||||||
#define ANALOG_MUX3 10
|
|
||||||
/// analog input pin
|
|
||||||
#define ANALOG_IN A1
|
|
||||||
/// rotary encoder interrupt pin
|
|
||||||
#define ROT_INT 7
|
|
||||||
/// scan analog every 12 milliseconds
|
|
||||||
#define ANALOG_INTERVAL 12
|
|
||||||
/// scan keys every 24 milliseconds
|
|
||||||
#define KEYSCAN_INTERVAL 24
|
|
||||||
|
|
||||||
// library includes
|
// library includes
|
||||||
#include <Adafruit_MCP23X17.h>
|
#include <Adafruit_MCP23X17.h>
|
||||||
|
|
||||||
|
@ -38,7 +24,7 @@ CimditHAL::CimditHAL() {
|
||||||
m_analogNum = 0;
|
m_analogNum = 0;
|
||||||
m_analogChanged = 0;
|
m_analogChanged = 0;
|
||||||
for (uint8_t i = 0; i < 8; ++i) {
|
for (uint8_t i = 0; i < 8; ++i) {
|
||||||
m_currentButtons[i] = 0;
|
m_currentButtons[i] = 0xff;
|
||||||
m_buttonsChanged[i] = 0;
|
m_buttonsChanged[i] = 0;
|
||||||
}
|
}
|
||||||
m_rotChanged = 0;
|
m_rotChanged = 0;
|
||||||
|
@ -51,7 +37,7 @@ void CimditHAL::begin() {
|
||||||
pinMode(ANALOG_MUX2, OUTPUT);
|
pinMode(ANALOG_MUX2, OUTPUT);
|
||||||
pinMode(ANALOG_MUX3, OUTPUT);
|
pinMode(ANALOG_MUX3, OUTPUT);
|
||||||
m_keyMatrix.begin_I2C(0x20);
|
m_keyMatrix.begin_I2C(0x20);
|
||||||
Serial.println(m_rotEncoders.begin_I2C(0x21));
|
m_rotEncoders.begin_I2C(0x21);
|
||||||
// combine the inputs to a single interrupt pin
|
// combine the inputs to a single interrupt pin
|
||||||
m_rotEncoders.setupInterrupts(true, false, HIGH);
|
m_rotEncoders.setupInterrupts(true, false, HIGH);
|
||||||
for (uint8_t i = 0; i < 8; ++i) {
|
for (uint8_t i = 0; i < 8; ++i) {
|
||||||
|
@ -61,9 +47,8 @@ void CimditHAL::begin() {
|
||||||
m_rotEncoders.pinMode(i, INPUT_PULLUP);
|
m_rotEncoders.pinMode(i, INPUT_PULLUP);
|
||||||
m_rotEncoders.setupInterruptPin(i, CHANGE);
|
m_rotEncoders.setupInterruptPin(i, CHANGE);
|
||||||
m_currentButtons[i] = 0xff;
|
m_currentButtons[i] = 0xff;
|
||||||
m_rotaryEncoders[i].begin();
|
|
||||||
}
|
}
|
||||||
for (uint8_t i = 8; i < 15; ++i) {
|
for (uint8_t i = 8; i < 16; ++i) {
|
||||||
// set key matrix rows to input
|
// set key matrix rows to input
|
||||||
m_keyMatrix.pinMode(i, INPUT_PULLUP);
|
m_keyMatrix.pinMode(i, INPUT_PULLUP);
|
||||||
// set encoders to input and setup interrupt to fire on change
|
// set encoders to input and setup interrupt to fire on change
|
||||||
|
@ -126,6 +111,7 @@ void CimditHAL::readFromHardware(bool interrupt) {
|
||||||
m_currentAnalogValues[m_analogNum] = analogRead(ANALOG_IN);
|
m_currentAnalogValues[m_analogNum] = analogRead(ANALOG_IN);
|
||||||
// set changed bits
|
// set changed bits
|
||||||
if (lastAnalogValue != m_currentAnalogValues[m_analogNum]) {
|
if (lastAnalogValue != m_currentAnalogValues[m_analogNum]) {
|
||||||
|
//if (abs(lastAnalogValue - m_currentAnalogValues[m_analogNum]) > 1) {
|
||||||
m_analogChanged |= 1 << m_analogNum;
|
m_analogChanged |= 1 << m_analogNum;
|
||||||
}
|
}
|
||||||
// set mux value for next round, wrap to 0 at 16
|
// set mux value for next round, wrap to 0 at 16
|
||||||
|
@ -151,6 +137,7 @@ void CimditHAL::readFromHardware(bool interrupt) {
|
||||||
m_keyMatrix.writeGPIO(0xff ^ (1 << m_keyRow), 0);
|
m_keyMatrix.writeGPIO(0xff ^ (1 << m_keyRow), 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t CimditHAL::rotaryChanged() {
|
uint8_t CimditHAL::rotaryChanged() {
|
||||||
uint8_t ret = m_rotChanged;
|
uint8_t ret = m_rotChanged;
|
||||||
m_rotChanged = 0;
|
m_rotChanged = 0;
|
||||||
|
|
|
@ -0,0 +1,791 @@
|
||||||
|
/**
|
||||||
|
* \file cimditprofile.h
|
||||||
|
* \brief Declaration of the CimditProfile class
|
||||||
|
* \author GrumpyDeveloper (Sascha Nitsch)
|
||||||
|
* \copyright 2022 Sascha Nitsch
|
||||||
|
* Licensed under MIT license
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include "defines.h"
|
||||||
|
|
||||||
|
// system includes
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#ifndef EXTERNAL_EEPROM
|
||||||
|
#include <EEPROM.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_DISPLAY
|
||||||
|
#include "cimditssd1306.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// own includes
|
||||||
|
#include "cimditprofile.h"
|
||||||
|
|
||||||
|
extern CimditSSD1306 display;
|
||||||
|
extern CimditHAL hal;
|
||||||
|
|
||||||
|
/*
|
||||||
|
structure of profile in eeprom
|
||||||
|
uint16_t total size (including length bytes)
|
||||||
|
uint8_t number of profiles
|
||||||
|
for each profile:
|
||||||
|
uint16_t length length of profile in bytes (including length bytes)
|
||||||
|
char profile[] 0-terminated profile name
|
||||||
|
uint8_t custom image (0/1)
|
||||||
|
if custom image
|
||||||
|
uint8_t[512] image data
|
||||||
|
uint8_t button_mapping number
|
||||||
|
repeat for each mapped button
|
||||||
|
uint8_t button number
|
||||||
|
<mapping enum> uint8_t mapping type
|
||||||
|
int8_t value depending on mapping
|
||||||
|
uint8_t axis mapping number
|
||||||
|
repeated for each mapped axis
|
||||||
|
uint8_t axis number
|
||||||
|
<mapping enum> uint8_t mapping type
|
||||||
|
int8_t value depending on mapping
|
||||||
|
uint8_t rotary mapping number
|
||||||
|
repeated for each rotary encoder
|
||||||
|
uint8_t encoder number (note, each encoder has 2 buttons: counter-clockwise and clockwise)
|
||||||
|
<mapping enum> uint8_t mapping type
|
||||||
|
int8_t value depending on mapping
|
||||||
|
uint8_t number of macro sequences
|
||||||
|
repeated for every macro sequence
|
||||||
|
const char[] macro sequence, 0-terminated
|
||||||
|
*/
|
||||||
|
|
||||||
|
CimditProfile::CimditProfile() {
|
||||||
|
m_numProfiles = 0;
|
||||||
|
for (uint8_t i = 0; i < NUMBER_OF_PROFILES; ++i) {
|
||||||
|
m_profiles[i][0] = 0;
|
||||||
|
m_mappedRotary[i].m_number = -1;
|
||||||
|
}
|
||||||
|
m_numMappedButtons = 0;
|
||||||
|
m_numMappedAxis = 0;
|
||||||
|
m_numMappedRotary = 0;
|
||||||
|
m_activeProfile = 0;
|
||||||
|
m_selectingProfile = 0;
|
||||||
|
m_mouseMoveX = 0;
|
||||||
|
m_mouseMoveY = 0;
|
||||||
|
m_eepromPosition = 0;
|
||||||
|
m_stateTimeout = 0;
|
||||||
|
m_numMacros = 0;
|
||||||
|
m_macroStart = nullptr;
|
||||||
|
m_nextBarUpdate = 0;
|
||||||
|
m_dotX = 0;
|
||||||
|
m_dotY = 0;
|
||||||
|
m_relMouseX = 0;
|
||||||
|
m_relMouseY = 0;
|
||||||
|
m_displayState = DISPLAY_BLANK;
|
||||||
|
m_userTimeout = 0;
|
||||||
|
m_stateStarted = 0;
|
||||||
|
m_customImage = 0;
|
||||||
|
memset(m_userString, 0, sizeof(m_userString));
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t CimditProfile::nextUInt8() {
|
||||||
|
uint8_t ret;
|
||||||
|
#ifdef EXTERNAL_EEPROM
|
||||||
|
Wire.beginTransmission(EXTERNAL_EEPROM);
|
||||||
|
Wire.write((uint8_t)(m_eepromPosition >> 8)); // MSB
|
||||||
|
Wire.write((uint8_t)(m_eepromPosition & 0xFF)); // LSB
|
||||||
|
Wire.endTransmission();
|
||||||
|
Wire.requestFrom(EXTERNAL_EEPROM, 1);
|
||||||
|
ret = Wire.read();
|
||||||
|
++m_eepromPosition;
|
||||||
|
return ret;
|
||||||
|
#else
|
||||||
|
return EEPROM.read(m_eepromPosition++);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t CimditProfile::nextUInt16() {
|
||||||
|
return ((uint16_t)(nextUInt8()) << 8) + nextUInt8();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CimditProfile::nextString(unsigned char* destination) {
|
||||||
|
uint8_t next = nextUInt8();
|
||||||
|
while (next != 0) {
|
||||||
|
*destination = next;
|
||||||
|
next = nextUInt8();
|
||||||
|
++destination;
|
||||||
|
}
|
||||||
|
*destination = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CimditProfile::begin() {
|
||||||
|
initProfiles();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CimditProfile::initProfiles() {
|
||||||
|
m_eepromPosition = 2;
|
||||||
|
// number of profiles
|
||||||
|
m_numProfiles = nextUInt8();
|
||||||
|
if (m_numProfiles > NUMBER_OF_PROFILES) m_numProfiles = 0;
|
||||||
|
for (uint8_t i = 0; i < m_numProfiles; ++i) {
|
||||||
|
uint16_t position = m_eepromPosition;
|
||||||
|
uint16_t size = nextUInt16();
|
||||||
|
nextString((unsigned char*)(m_profiles[i]));
|
||||||
|
m_eepromPosition = position + size; // we only scan the names here
|
||||||
|
}
|
||||||
|
if (m_numProfiles>0) {
|
||||||
|
load(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CimditProfile::load(uint8_t num) {
|
||||||
|
m_activeProfile = num;
|
||||||
|
m_selectingProfile = num;
|
||||||
|
// skip number of profiles
|
||||||
|
m_eepromPosition = 3;
|
||||||
|
// seek to right profile
|
||||||
|
for (uint8_t i = 0; i < num; ++i) {
|
||||||
|
// get profile length
|
||||||
|
uint16_t size = nextUInt16();
|
||||||
|
m_eepromPosition += size - 2;
|
||||||
|
}
|
||||||
|
// ignore 2 bytes size
|
||||||
|
m_eepromPosition += 2;
|
||||||
|
// m_eepromPosition points to our profile to parse
|
||||||
|
// name is already saved, skip it
|
||||||
|
while (nextUInt8() != 0) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// do we have a custom image?
|
||||||
|
m_customImage = nextUInt8() > 0 ? m_eepromPosition : 0;
|
||||||
|
if (m_customImage) {
|
||||||
|
// skip 512 bytes
|
||||||
|
m_eepromPosition += 512;
|
||||||
|
}
|
||||||
|
// mapped buttons
|
||||||
|
// number of mapped buttons
|
||||||
|
m_numMappedButtons = nextUInt8();
|
||||||
|
if (m_numMappedButtons) {
|
||||||
|
for (uint8_t i = 0; i < m_numMappedButtons ; ++i) {
|
||||||
|
m_mappedButtons[i].m_number = nextUInt8();
|
||||||
|
m_mappedButtons[i].m_type = (MappingType)(nextUInt8());
|
||||||
|
m_mappedButtons[i].m_value = nextUInt8();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// end of mapped buttons
|
||||||
|
|
||||||
|
// mapped axis
|
||||||
|
// number of mapped axis
|
||||||
|
m_numMappedAxis = nextUInt8();
|
||||||
|
if (m_numMappedAxis) {
|
||||||
|
for (uint8_t i = 0; i < m_numMappedAxis ; ++i) {
|
||||||
|
m_mappedAxis[i].m_number = nextUInt8();
|
||||||
|
m_mappedAxis[i].m_type = (MappingType)(nextUInt8());
|
||||||
|
m_mappedAxis[i].m_value = nextUInt8();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// end of mapped axis
|
||||||
|
|
||||||
|
// mapped rotary
|
||||||
|
// number of mapped rotary
|
||||||
|
m_numMappedRotary = nextUInt8();
|
||||||
|
if (m_numMappedRotary) {
|
||||||
|
for (uint8_t i = 0; i < m_numMappedRotary ; ++i) {
|
||||||
|
m_mappedRotary[i].m_number = nextUInt8();
|
||||||
|
m_mappedRotary[i].m_type = (MappingType)(nextUInt8());
|
||||||
|
m_mappedRotary[i].m_value = nextUInt8();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// end of mapped rotary
|
||||||
|
m_mouseMoveX = 0;
|
||||||
|
m_mouseMoveY = 0;
|
||||||
|
// parse macro
|
||||||
|
m_numMacros = nextUInt8();
|
||||||
|
if (m_macroStart) {
|
||||||
|
free(m_macroStart);
|
||||||
|
}
|
||||||
|
m_macroStart = reinterpret_cast<uint16_t*>(malloc(m_numMacros * sizeof(uint16_t)));
|
||||||
|
for (uint8_t macroNum = 0; macroNum < m_numMacros; ++macroNum) {
|
||||||
|
m_macroStart[macroNum] = m_eepromPosition;
|
||||||
|
scanOrExecuteMacro(macroNum, false);
|
||||||
|
}
|
||||||
|
showActiveProfile();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CimditProfile::scanOrExecuteMacro(uint8_t macroNum, bool execute) {
|
||||||
|
m_eepromPosition = m_macroStart[macroNum];
|
||||||
|
uint8_t value8 = 0;
|
||||||
|
uint16_t delayTime = 0;
|
||||||
|
MACROCOMMANDS token;
|
||||||
|
do {
|
||||||
|
token = (MACROCOMMANDS)nextUInt8();
|
||||||
|
switch (token) {
|
||||||
|
case MACRO_NULL:
|
||||||
|
break;
|
||||||
|
case MACRO_SPEED: // read in 1 extra numberic value 8 bit
|
||||||
|
delayTime = 1000 / nextUInt8();
|
||||||
|
break;
|
||||||
|
case MACRO_JOY_PRESS: // read in 1 extra numberic value 8 bit
|
||||||
|
value8 = nextUInt8();
|
||||||
|
if (execute) {
|
||||||
|
Gamepad.press(value8);
|
||||||
|
Gamepad.write();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MACRO_JOY_RELEASE: // read in 1 extra numberic value 8 bit
|
||||||
|
value8 = nextUInt8();
|
||||||
|
if (execute) {
|
||||||
|
Gamepad.release(value8);
|
||||||
|
Gamepad.write();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MACRO_MOUSE_PRESS: // read in 1 extra numberic value 8 bit
|
||||||
|
value8 = nextUInt8();
|
||||||
|
if (execute) {
|
||||||
|
Mouse.press(value8);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MACRO_MOUSE_RELEASE: // read in 1 extra numberic value 8 bit
|
||||||
|
value8 = nextUInt8();
|
||||||
|
if (execute) {
|
||||||
|
Mouse.release(value8);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MACRO_MOUSE_WHEEL: // read in 1 extra numberic value 8 bit
|
||||||
|
value8 = nextUInt8();
|
||||||
|
if (execute) {
|
||||||
|
Mouse.move(0, 0, value8);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MACRO_DELAY: // read in 1 extra numberic value 16 bit
|
||||||
|
if (execute) {
|
||||||
|
delay(nextUInt16());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MACRO_KEY_PRESS: // one or more keys
|
||||||
|
while ((value8 = nextUInt8()) != MACRO_END) {
|
||||||
|
if (execute) {
|
||||||
|
Keyboard.press((KeyboardKeycode)value8);
|
||||||
|
if (delayTime) delay(delayTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MACRO_KEY_RELEASE:
|
||||||
|
while ((value8 = nextUInt8()) != MACRO_END) {
|
||||||
|
if (execute) {
|
||||||
|
Keyboard.release((KeyboardKeycode)value8);
|
||||||
|
if (delayTime) delay(delayTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MACRO_TYPE:
|
||||||
|
while ((value8 = nextUInt8()) != MACRO_END) {
|
||||||
|
if (execute) {
|
||||||
|
Keyboard.write((KeyboardKeycode)value8);
|
||||||
|
if (delayTime) delay(delayTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MACRO_MOUSE_REL_X: // read in 1 extra numberic value 8 bit
|
||||||
|
value8 = nextUInt8();
|
||||||
|
if (execute) {
|
||||||
|
Mouse.move(value8, 0, 0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MACRO_MOUSE_REL_Y: // read in 1 extra numberic value 8 bit
|
||||||
|
value8 = nextUInt8();
|
||||||
|
if (execute) {
|
||||||
|
Mouse.move(0, value8, 0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MACRO_MOUSE_REL_X_AXIS: { // one or 2 bytes"
|
||||||
|
int8_t axis = nextUInt8();
|
||||||
|
if (axis != -1) {
|
||||||
|
value8 = nextUInt8();
|
||||||
|
if (execute) {
|
||||||
|
// find previous mapping
|
||||||
|
bool found = false;
|
||||||
|
for (uint8_t i = 0; i < m_numMappedAxis; ++i) {
|
||||||
|
if (m_mappedAxis[i].m_number == axis) {
|
||||||
|
m_mappedAxis[i].m_type = MOUSE_REL_X_AXIS;
|
||||||
|
m_mappedAxis[i].m_value = value8;
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
m_mappedAxis[m_numMappedAxis].m_type = MOUSE_REL_X_AXIS;
|
||||||
|
m_mappedAxis[m_numMappedAxis].m_number = axis;
|
||||||
|
m_mappedAxis[m_numMappedAxis++].m_value = value8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (execute) {
|
||||||
|
// find axis
|
||||||
|
for (uint8_t i = 0; i < m_numMappedAxis; ++i) {
|
||||||
|
if (m_mappedAxis[i].m_number == axis) {
|
||||||
|
m_mappedAxis[i].m_type = MAPPING_NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MACRO_MOUSE_REL_Y_AXIS: { // one or 2 bytes
|
||||||
|
int8_t axis = nextUInt8();
|
||||||
|
if (axis != -1) {
|
||||||
|
value8 = nextUInt8();
|
||||||
|
if (execute) {
|
||||||
|
// find previous mapping
|
||||||
|
bool found = false;
|
||||||
|
for (uint8_t i = 0; i < m_numMappedAxis; ++i) {
|
||||||
|
if (m_mappedAxis[i].m_number == axis) {
|
||||||
|
m_mappedAxis[i].m_type = MOUSE_REL_Y_AXIS;
|
||||||
|
m_mappedAxis[i].m_value = value8;
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
m_mappedAxis[m_numMappedAxis].m_type = MOUSE_REL_Y_AXIS;
|
||||||
|
m_mappedAxis[m_numMappedAxis].m_number = axis;
|
||||||
|
m_mappedAxis[m_numMappedAxis++].m_value = value8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (execute) {
|
||||||
|
// find axis
|
||||||
|
for (uint8_t i = 0; i < m_numMappedAxis; ++i) {
|
||||||
|
if (m_mappedAxis[i].m_number == axis) {
|
||||||
|
m_mappedAxis[i].m_type = MAPPING_NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while (token != MACRO_NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CimditProfile::rotaryAction(uint8_t num, int8_t delta) {
|
||||||
|
if (m_displayState != DISPLAY_USER_STRING && m_displayState != DISPLAY_CONFIRMATION) {
|
||||||
|
showActiveProfile();
|
||||||
|
}
|
||||||
|
// find right action
|
||||||
|
// rotary has counter-clockwise and clockwise mapping
|
||||||
|
num = (num << 1) + (delta > 0);
|
||||||
|
for (uint8_t i = 0; i < m_numMappedRotary; ++i) {
|
||||||
|
if (m_mappedRotary[i].m_number == num) {
|
||||||
|
// rotary supports mouse rel axis, next/prev profile and macro
|
||||||
|
switch (m_mappedRotary[i].m_type) {
|
||||||
|
case MOUSE_REL_X_AXIS:
|
||||||
|
Mouse.move(m_mappedRotary[i].m_value * delta, 0, 0);
|
||||||
|
break;
|
||||||
|
case MOUSE_REL_Y_AXIS:
|
||||||
|
Mouse.move(0, m_mappedRotary[i].m_value * delta, 0);
|
||||||
|
break;
|
||||||
|
case MOUSE_REL_WHEEL:
|
||||||
|
Mouse.move(0, 0, m_mappedRotary[i].m_value * delta);
|
||||||
|
break;
|
||||||
|
case NEXT_PROFILE:
|
||||||
|
case PREV_PROFILE:
|
||||||
|
if (m_mappedRotary[i].m_type == NEXT_PROFILE) {
|
||||||
|
m_selectingProfile = (m_selectingProfile + 1) % m_numProfiles;
|
||||||
|
} else {
|
||||||
|
if (m_selectingProfile > 0) {
|
||||||
|
--m_selectingProfile;
|
||||||
|
} else {
|
||||||
|
m_selectingProfile = m_numProfiles - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
showActivate();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CimditProfile::showActiveProfile() {
|
||||||
|
#ifdef HAVE_DISPLAY
|
||||||
|
if (m_customImage) {
|
||||||
|
m_eepromPosition = m_customImage;
|
||||||
|
for (uint8_t y = 0; y < SCREEN_HEIGHT; ++y) {
|
||||||
|
for (uint8_t x = 0; x < SCREEN_WIDTH; x += 8) {
|
||||||
|
uint8_t img = nextUInt8();
|
||||||
|
for (uint8_t t = 0; t < 8; ++t) {
|
||||||
|
display.drawPixel(x + t, y, (img >> (7-t)) & 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
printTextCentered(m_profiles[m_activeProfile]);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
Serial.println(m_profiles[m_activeProfile]);
|
||||||
|
#endif
|
||||||
|
m_displayState = DISPLAY_PROFILE;
|
||||||
|
m_stateTimeout = hal.m_millis + PROFILE_TIME;
|
||||||
|
m_stateStarted = hal.m_millis;
|
||||||
|
display.display();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CimditProfile::showActivate() {
|
||||||
|
#ifdef HAVE_DISPLAY
|
||||||
|
display.clearDisplay();
|
||||||
|
display.setTextSize(2,2);
|
||||||
|
display.setCursor(16, 0);
|
||||||
|
display.write("activate");
|
||||||
|
// default font is 5x8 pixel
|
||||||
|
uint8_t w = (strlen(m_profiles[m_selectingProfile]) + 1) * 2 * 6;
|
||||||
|
uint8_t h = 16;
|
||||||
|
if (w > SCREEN_WIDTH) {
|
||||||
|
display.setTextSize(1,1);
|
||||||
|
w = w >> 1;
|
||||||
|
h = 8;
|
||||||
|
}
|
||||||
|
display.setCursor((SCREEN_WIDTH - w) >> 1, (SCREEN_HEIGHT >> 1) + ((SCREEN_HEIGHT - h)>> 1));
|
||||||
|
display.write(m_profiles[m_selectingProfile]);
|
||||||
|
display.write("?");
|
||||||
|
display.display();
|
||||||
|
#else
|
||||||
|
Serial.print(F("activate "));
|
||||||
|
Serial.print(m_profiles[m_selectingProfile]);
|
||||||
|
Serial.println(F("?"));
|
||||||
|
#endif
|
||||||
|
m_displayState = DISPLAY_CONFIRMATION;
|
||||||
|
m_stateTimeout = hal.m_millis + SELECTION_TIME;
|
||||||
|
m_stateStarted = hal.m_millis;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CimditProfile::printTextCentered(const char* text) {
|
||||||
|
display.clearDisplay();
|
||||||
|
display.setTextSize(2,2);
|
||||||
|
// default font is 6x8 pixel
|
||||||
|
uint8_t w = strlen(text) * 12;
|
||||||
|
uint8_t h = 16;
|
||||||
|
if (w > SCREEN_WIDTH) {
|
||||||
|
display.setTextSize(1,1);
|
||||||
|
w = w >> 1;
|
||||||
|
h = 8;
|
||||||
|
}
|
||||||
|
display.setCursor((SCREEN_WIDTH - w) >> 1, (SCREEN_HEIGHT - h) >> 1);
|
||||||
|
display.write(text);
|
||||||
|
display.display();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CimditProfile::showUserString() {
|
||||||
|
#ifdef HAVE_DISPLAY
|
||||||
|
printTextCentered(m_userString);
|
||||||
|
#endif
|
||||||
|
m_displayState = DISPLAY_USER_STRING;
|
||||||
|
m_stateTimeout = hal.m_millis + m_userTimeout;
|
||||||
|
m_stateStarted = hal.m_millis;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CimditProfile::axisAction(uint8_t num, uint16_t state) {
|
||||||
|
for (uint8_t i = 0; i < m_numMappedAxis; ++i) {
|
||||||
|
if (m_mappedAxis[i].m_number == num) {
|
||||||
|
switch (m_mappedAxis[i].m_type) {
|
||||||
|
case JOYSTICK_AXIS:
|
||||||
|
switch (m_mappedAxis[i].m_value) {
|
||||||
|
case 1:
|
||||||
|
Gamepad.xAxis(map(state, 0, 1023, -32768, 32767));
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
Gamepad.yAxis(map(state, 0, 1023, -32768, 32767));
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
Gamepad.zAxis(map(state, 0, 1023, -128, 127));
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
Gamepad.rxAxis(map(state, 0, 1023, -32768, 32767));
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
Gamepad.ryAxis(map(state, 0, 1023, -32768, 32767));
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
Gamepad.rzAxis(map(state, 0, 1023, -128, 127));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MOUSE_REL_X_AXIS: {
|
||||||
|
int16_t pos = (int16_t)state - 512;
|
||||||
|
if (pos > JOYSTICK_DEAD_ZONE_X) {
|
||||||
|
m_mouseMoveX = map(pos, JOYSTICK_DEAD_ZONE_X, 511, 0, m_mappedAxis[i].m_value);
|
||||||
|
} else if (pos < -JOYSTICK_DEAD_ZONE_X) {
|
||||||
|
m_mouseMoveX = map(pos, -512, -JOYSTICK_DEAD_ZONE_X, -m_mappedAxis[i].m_value, 0);
|
||||||
|
} else {
|
||||||
|
m_mouseMoveX = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MOUSE_REL_Y_AXIS: {
|
||||||
|
int16_t pos = (int16_t)state - 512;
|
||||||
|
if (pos > JOYSTICK_DEAD_ZONE_Y) {
|
||||||
|
m_mouseMoveY = map(pos, JOYSTICK_DEAD_ZONE_Y, 511, 0, m_mappedAxis[i].m_value);
|
||||||
|
} else if (pos < -JOYSTICK_DEAD_ZONE_Y) {
|
||||||
|
m_mouseMoveY = map(pos, -512, -JOYSTICK_DEAD_ZONE_Y, -m_mappedAxis[i].m_value, 0);
|
||||||
|
} else {
|
||||||
|
m_mouseMoveY = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CimditProfile::buttonAction(uint8_t num, bool state) {
|
||||||
|
if (m_displayState != DISPLAY_USER_STRING && m_displayState != DISPLAY_CONFIRMATION) {
|
||||||
|
showActiveProfile();
|
||||||
|
}
|
||||||
|
for (uint8_t i = 0; i < m_numMappedButtons; ++i) {
|
||||||
|
if (m_mappedButtons[i].m_number == num) {
|
||||||
|
switch (m_mappedButtons[i].m_type) {
|
||||||
|
case JOYSTICK_BUTTON:
|
||||||
|
if (state) {
|
||||||
|
Gamepad.press(m_mappedButtons[i].m_value);
|
||||||
|
} else {
|
||||||
|
Gamepad.release(m_mappedButtons[i].m_value);
|
||||||
|
}
|
||||||
|
Gamepad.write();
|
||||||
|
break;
|
||||||
|
case MOUSE_BUTTON:
|
||||||
|
if (state) {
|
||||||
|
Mouse.press(m_mappedButtons[i].m_value);
|
||||||
|
} else {
|
||||||
|
Mouse.release(m_mappedButtons[i].m_value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MOUSE_REL_X_AXIS:
|
||||||
|
Mouse.move(m_mappedButtons[i].m_value, 0, 0);
|
||||||
|
break;
|
||||||
|
case MOUSE_REL_Y_AXIS:
|
||||||
|
Mouse.move(0, m_mappedButtons[i].m_value, 0);
|
||||||
|
break;
|
||||||
|
case MOUSE_REL_WHEEL:
|
||||||
|
Mouse.move(0, 0, m_mappedButtons[i].m_value);
|
||||||
|
break;
|
||||||
|
case NEXT_PROFILE:
|
||||||
|
case PREV_PROFILE:
|
||||||
|
if (m_mappedRotary[i].m_type == NEXT_PROFILE) {
|
||||||
|
m_selectingProfile = (m_selectingProfile + 1) % m_numProfiles;
|
||||||
|
} else {
|
||||||
|
if (m_selectingProfile > 0) {
|
||||||
|
--m_selectingProfile;
|
||||||
|
} else {
|
||||||
|
m_selectingProfile = m_numProfiles - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
showActivate();
|
||||||
|
break;
|
||||||
|
case SWITCH_PROFILE:
|
||||||
|
if (m_stateTimeout && state && m_displayState == DISPLAY_CONFIRMATION) {
|
||||||
|
load(m_selectingProfile);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MACRO_PRESS:
|
||||||
|
if (state)
|
||||||
|
scanOrExecuteMacro(m_mappedButtons[i].m_value, true);
|
||||||
|
break;
|
||||||
|
case MACRO_RELEASE:
|
||||||
|
if (!state)
|
||||||
|
scanOrExecuteMacro(m_mappedButtons[i].m_value, true);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CimditProfile::tick() {
|
||||||
|
if (m_stateTimeout && hal.m_millis >= m_stateTimeout) {
|
||||||
|
switch (m_displayState) {
|
||||||
|
case DISPLAY_BLANK: // ignored
|
||||||
|
break;
|
||||||
|
case DISPLAY_PROFILE: // go to blank display state
|
||||||
|
display.clearDisplay();
|
||||||
|
display.display();
|
||||||
|
m_displayState = DISPLAY_BLANK;
|
||||||
|
m_stateTimeout = 0;
|
||||||
|
m_stateStarted = hal.m_millis;
|
||||||
|
break;
|
||||||
|
case DISPLAY_CONFIRMATION:
|
||||||
|
case DISPLAY_USER_STRING:
|
||||||
|
// go back to profile name
|
||||||
|
showActiveProfile();
|
||||||
|
m_selectingProfile = m_activeProfile;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (hal.m_millis > m_nextBarUpdate) {
|
||||||
|
m_nextBarUpdate = hal.m_millis + BAR_UPDATE_TIME;
|
||||||
|
if (m_stateTimeout) {
|
||||||
|
uint8_t percentage = SCREEN_WIDTH * (hal.m_millis - m_stateStarted) / (m_stateTimeout - m_stateStarted);
|
||||||
|
// white bar from left to percentage
|
||||||
|
display.drawFastHLine(0, SCREEN_HEIGHT-1, percentage, true);
|
||||||
|
// black bar from percentage to right
|
||||||
|
display.drawFastHLine(percentage + 1, SCREEN_HEIGHT-1, SCREEN_WIDTH - percentage - 1, false);
|
||||||
|
display.displayPartial(3);
|
||||||
|
}
|
||||||
|
if (m_displayState == DISPLAY_BLANK) {
|
||||||
|
// clear old pixel
|
||||||
|
display.drawPixel(m_dotX, m_dotY, false);
|
||||||
|
uint8_t part1 = m_dotY/8;
|
||||||
|
uint16_t r = rand();
|
||||||
|
m_dotX = r & 127;
|
||||||
|
m_dotY = r & 31;
|
||||||
|
display.drawPixel(m_dotX, m_dotY, true);
|
||||||
|
uint8_t part2 = m_dotY/8;
|
||||||
|
if (part1 != part2) {
|
||||||
|
display.displayPartial(part2);
|
||||||
|
}
|
||||||
|
display.displayPartial(part1);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if (m_mouseMoveX || m_mouseMoveY) {
|
||||||
|
m_relMouseX += (float)m_mouseMoveX / 50;
|
||||||
|
m_relMouseY += (float)m_mouseMoveY / 50;
|
||||||
|
if (fabs(m_relMouseX) >= 1 || fabs(m_relMouseY) >= 1) {
|
||||||
|
Mouse.move(m_relMouseX, m_relMouseY);
|
||||||
|
m_relMouseX -= (int8_t)m_relMouseX;
|
||||||
|
m_relMouseY -= (int8_t)m_relMouseY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CimditProfile::printFlash() {
|
||||||
|
const uint8_t eepromPosition = m_eepromPosition;
|
||||||
|
m_eepromPosition = 0;
|
||||||
|
uint16_t len = nextUInt16();
|
||||||
|
m_eepromPosition = 0;
|
||||||
|
if (len < 1024) {
|
||||||
|
uint8_t in;
|
||||||
|
for (uint16_t i = 0; i < len; ++i) {
|
||||||
|
in = nextUInt8();
|
||||||
|
Serial.print(in >> 8, 16);
|
||||||
|
Serial.print(in & 255, 16);
|
||||||
|
}
|
||||||
|
Serial.println();
|
||||||
|
}
|
||||||
|
m_eepromPosition = eepromPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef EXTERNAL_EEPROM
|
||||||
|
void CimditProfile::eepromWrite(uint16_t addr, uint8_t val) {
|
||||||
|
Wire.beginTransmission(EXTERNAL_EEPROM);
|
||||||
|
Wire.write((uint8_t)(addr >> 8)); // MSB
|
||||||
|
Wire.write((uint8_t)(addr & 0xFF)); // LSB
|
||||||
|
Wire.write(val);
|
||||||
|
Wire.endTransmission();
|
||||||
|
delay(5);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void CimditProfile::writeFlash() {
|
||||||
|
char buf[5]= {0};
|
||||||
|
Serial.readBytes(buf, 4);
|
||||||
|
uint16_t len = strtol(buf, NULL, 16);
|
||||||
|
buf[2] = 0;
|
||||||
|
m_eepromPosition = 0;
|
||||||
|
#ifdef EXTERNAL_EEPROM
|
||||||
|
eepromWrite(m_eepromPosition++, len >> 8);
|
||||||
|
eepromWrite(m_eepromPosition++, len & 255);
|
||||||
|
#else
|
||||||
|
EEPROM.write(m_eepromPosition++, len >> 8);
|
||||||
|
EEPROM.write(m_eepromPosition++, len & 255);
|
||||||
|
#endif
|
||||||
|
if (len < 1024) {
|
||||||
|
for (uint16_t i = 2; i < len; ++i) {
|
||||||
|
while ((buf[0] = Serial.read()) == -1) {
|
||||||
|
delay(100);
|
||||||
|
}
|
||||||
|
while ((buf[1] = Serial.read()) == -1) {
|
||||||
|
delay(100);
|
||||||
|
}
|
||||||
|
uint8_t in = strtol(buf, NULL, 16);
|
||||||
|
#ifdef EXTERNAL_EEPROM
|
||||||
|
eepromWrite(m_eepromPosition++, in);
|
||||||
|
#else
|
||||||
|
EEPROM.write(m_eepromPosition++, in);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
Serial.println("written");
|
||||||
|
initProfiles();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CimditProfile::setUserString(uint8_t timeout, const char* input) {
|
||||||
|
strncpy(m_userString, input, sizeof(m_userString) - 1);
|
||||||
|
m_userTimeout = timeout * 1000;
|
||||||
|
showUserString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CimditProfile::userDisplay() {
|
||||||
|
uint8_t timeout = 0;
|
||||||
|
char buf = 0;
|
||||||
|
// read number for time to display
|
||||||
|
do {
|
||||||
|
buf = Serial.read();
|
||||||
|
if (buf != '\n') {
|
||||||
|
timeout = timeout * 10 + buf - '0';
|
||||||
|
}
|
||||||
|
} while (buf != '\n');
|
||||||
|
Serial.println(F("ready for .pbm file"));
|
||||||
|
// read header
|
||||||
|
do {
|
||||||
|
buf = Serial.read();
|
||||||
|
} while (buf != '\n');
|
||||||
|
while (!Serial.available()) { delay(10); };
|
||||||
|
buf = Serial.read();
|
||||||
|
if (buf == '#') { // a comment
|
||||||
|
do {
|
||||||
|
buf = Serial.read();
|
||||||
|
} while (buf != '\n');
|
||||||
|
}
|
||||||
|
while (!Serial.available()) { delay(10); };
|
||||||
|
// width height
|
||||||
|
uint8_t width = 0;
|
||||||
|
do {
|
||||||
|
buf = Serial.read();
|
||||||
|
|
||||||
|
if (buf != ' ') {
|
||||||
|
width = width * 10 + buf - '0';
|
||||||
|
}
|
||||||
|
} while (buf != ' ');
|
||||||
|
uint8_t height = 0;
|
||||||
|
do {
|
||||||
|
buf = Serial.read();
|
||||||
|
if (buf != '\n') {
|
||||||
|
height = height * 10 + buf - '0';
|
||||||
|
}
|
||||||
|
} while (buf != '\n');
|
||||||
|
buf = 0;
|
||||||
|
uint16_t len = width * height;
|
||||||
|
if (width != SCREEN_WIDTH || SCREEN_HEIGHT != 32) {
|
||||||
|
for (uint8_t i = 0; i < width * height; ++i) {
|
||||||
|
buf = Serial.read();
|
||||||
|
if (buf == '\n') buf = Serial.read();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (uint8_t y = 0; y < SCREEN_HEIGHT; ++y) {
|
||||||
|
for (uint8_t x = 0; x < SCREEN_WIDTH; ++x) {
|
||||||
|
while ((buf = Serial.read()) == -1) {
|
||||||
|
delay(100);
|
||||||
|
}
|
||||||
|
while (buf != '0' && buf != '1') {
|
||||||
|
buf = Serial.read();
|
||||||
|
}
|
||||||
|
display.drawPixel(x, y, buf == '1');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
display.display();
|
||||||
|
m_displayState = DISPLAY_USER_STRING;
|
||||||
|
uint32_t now = millis();
|
||||||
|
m_stateTimeout = now + (uint32_t)timeout * 1000;
|
||||||
|
m_stateStarted = now;
|
||||||
|
}
|
|
@ -0,0 +1,289 @@
|
||||||
|
/**
|
||||||
|
* \file cimditprofile.h
|
||||||
|
* \brief Declaration of the CimditProfile class
|
||||||
|
* \author GrumpyDeveloper (Sascha Nitsch)
|
||||||
|
* \copyright 2022 Sascha Nitsch
|
||||||
|
* Licensed under MIT license
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CIMDITPROFILE_H_
|
||||||
|
#define CIMDITPROFILE_H_
|
||||||
|
|
||||||
|
// our defines
|
||||||
|
#include "defines.h"
|
||||||
|
|
||||||
|
// system includes
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
// library include
|
||||||
|
#include <HID-Project.h>
|
||||||
|
|
||||||
|
// own include
|
||||||
|
#include "cimdithal.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \class CimditProfile
|
||||||
|
* \brief Profile storage and action class
|
||||||
|
*/
|
||||||
|
class CimditProfile {
|
||||||
|
public:
|
||||||
|
/// constructor
|
||||||
|
CimditProfile();
|
||||||
|
|
||||||
|
/// \brief initialize
|
||||||
|
void begin();
|
||||||
|
|
||||||
|
/// a button has been pressed or release
|
||||||
|
/// \param num which button number
|
||||||
|
/// \param state current button state (true if pressed)
|
||||||
|
void buttonAction(uint8_t num, bool state);
|
||||||
|
|
||||||
|
/// an axis was moved
|
||||||
|
/// \param num which axis number
|
||||||
|
/// \param state current axis state (absolute value)
|
||||||
|
void axisAction(uint8_t num, uint16_t state);
|
||||||
|
|
||||||
|
/// an axis was moved
|
||||||
|
/// \param num which axis number
|
||||||
|
/// \param delta rotary delta value
|
||||||
|
void rotaryAction(uint8_t num, int8_t delta);
|
||||||
|
|
||||||
|
/// periodic tick function, for timeouts, turning off display a.s.o.
|
||||||
|
void tick();
|
||||||
|
|
||||||
|
/// print flash(profile) content to serial
|
||||||
|
void printFlash();
|
||||||
|
|
||||||
|
/// write flash(profile) content from serial
|
||||||
|
void writeFlash();
|
||||||
|
|
||||||
|
/// set user string
|
||||||
|
/// \param timeout timout for string
|
||||||
|
/// \param input string to print out
|
||||||
|
void setUserString(uint8_t timeout, const char* input);
|
||||||
|
|
||||||
|
/// display user submitted graphic
|
||||||
|
void userDisplay();
|
||||||
|
|
||||||
|
/// mapping types
|
||||||
|
enum MappingType {
|
||||||
|
/// no mapping
|
||||||
|
MAPPING_NONE = 0,
|
||||||
|
/// mapped as joystick button (only works for buttons)
|
||||||
|
JOYSTICK_BUTTON,
|
||||||
|
/// mapped as joystick axis (only works for analog values)
|
||||||
|
JOYSTICK_AXIS,
|
||||||
|
/// mapped as mouse button (only works for buttons)
|
||||||
|
MOUSE_BUTTON,
|
||||||
|
/// mapped as mouse relative/incremental X axis (works for analog values, rotary encoder and buttons)
|
||||||
|
MOUSE_REL_X_AXIS,
|
||||||
|
/// mapped as mouse relative/incremental Y axis (works for analog values, rotary encoder and buttons)
|
||||||
|
MOUSE_REL_Y_AXIS,
|
||||||
|
/// mapped as mouse relative/incremental wheel (works for rotary encoder and buttons)
|
||||||
|
MOUSE_REL_WHEEL,
|
||||||
|
/// select to next profile
|
||||||
|
NEXT_PROFILE,
|
||||||
|
/// select to previous profile
|
||||||
|
PREV_PROFILE,
|
||||||
|
/// confirm selection
|
||||||
|
SWITCH_PROFILE,
|
||||||
|
/// macro key pressed
|
||||||
|
MACRO_PRESS,
|
||||||
|
/// macro key released
|
||||||
|
MACRO_RELEASE
|
||||||
|
};
|
||||||
|
|
||||||
|
/// enums for use in macros
|
||||||
|
enum MACROCOMMANDS {
|
||||||
|
/// null terminator
|
||||||
|
MACRO_NULL = 0,
|
||||||
|
/// end marker
|
||||||
|
MACRO_END = 0,
|
||||||
|
// time functions
|
||||||
|
/// speed for typing (chars per second)
|
||||||
|
MACRO_SPEED, // 1
|
||||||
|
/// wait a while (in ms)
|
||||||
|
MACRO_DELAY, // 2
|
||||||
|
// press/release functions
|
||||||
|
/// key press
|
||||||
|
MACRO_KEY_PRESS, // 3
|
||||||
|
/// key release
|
||||||
|
MACRO_KEY_RELEASE, // 4
|
||||||
|
/// joystick button press
|
||||||
|
MACRO_JOY_PRESS, // 5
|
||||||
|
/// joystick button release
|
||||||
|
MACRO_JOY_RELEASE, // 6
|
||||||
|
/// mouse press
|
||||||
|
MACRO_MOUSE_PRESS, // 7
|
||||||
|
/// mouse release
|
||||||
|
MACRO_MOUSE_RELEASE, // 8
|
||||||
|
/// mouse wheel rotation
|
||||||
|
MACRO_MOUSE_WHEEL, // 9
|
||||||
|
// typing functions
|
||||||
|
/// type a series of keys (press, delay, release)<repeated>
|
||||||
|
MACRO_TYPE, // 10
|
||||||
|
// axis mapping functions
|
||||||
|
/// move mouse X according to given value
|
||||||
|
MACRO_MOUSE_REL_X, // 11
|
||||||
|
/// move mouse Y according to given value
|
||||||
|
MACRO_MOUSE_REL_Y, // 12
|
||||||
|
/// move mouse X according to an analog axis
|
||||||
|
MACRO_MOUSE_REL_X_AXIS, // 13
|
||||||
|
/// move mouse Y according to an analog axis
|
||||||
|
MACRO_MOUSE_REL_Y_AXIS, // 14
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// get unsigned int 8 from EEPROM and advance one byte
|
||||||
|
/// \return eeprom value
|
||||||
|
uint8_t nextUInt8();
|
||||||
|
|
||||||
|
/// get unsigned int 16 from EEPROM and advance two byte
|
||||||
|
/// \return eeprom value
|
||||||
|
uint16_t nextUInt16();
|
||||||
|
|
||||||
|
/// get 0-terminated string from EEPROM
|
||||||
|
/// \param destination destination pointer
|
||||||
|
void nextString(unsigned char* destination);
|
||||||
|
|
||||||
|
/// initialize profile structures
|
||||||
|
void initProfiles();
|
||||||
|
|
||||||
|
/// load profile
|
||||||
|
/// \param profileNum number of profile to load
|
||||||
|
void load(uint8_t);
|
||||||
|
|
||||||
|
/// scan macros and optionally execute fiven Macro
|
||||||
|
/// \param macroNum number of macro
|
||||||
|
/// \param execute should macro be executed (true) or just scanned (false)
|
||||||
|
void scanOrExecuteMacro(uint8_t macroNum, bool execute);
|
||||||
|
|
||||||
|
#ifdef EXTERNAL_EEPROM
|
||||||
|
/**
|
||||||
|
* \brief write to eeprom
|
||||||
|
* \param addr addr to write to
|
||||||
|
* \param val value to write
|
||||||
|
*/
|
||||||
|
void eepromWrite(uint16_t addr, uint8_t val);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief show activation confirmation
|
||||||
|
*/
|
||||||
|
void showActivate();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* show currently active profile
|
||||||
|
*/
|
||||||
|
void showActiveProfile();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* show user string
|
||||||
|
*/
|
||||||
|
void showUserString();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief print out text centered on display
|
||||||
|
* \param text
|
||||||
|
*/
|
||||||
|
void printTextCentered(const char* text);
|
||||||
|
|
||||||
|
/// list of profile names
|
||||||
|
char m_profiles[NUMBER_OF_PROFILES][16];
|
||||||
|
|
||||||
|
/// number of profiles
|
||||||
|
uint8_t m_numProfiles;
|
||||||
|
|
||||||
|
/// active profile
|
||||||
|
uint8_t m_activeProfile;
|
||||||
|
|
||||||
|
/// selecting profile
|
||||||
|
uint8_t m_selectingProfile;
|
||||||
|
|
||||||
|
/// Mapping structure
|
||||||
|
struct Map {
|
||||||
|
/// number of (button/axis/rotary)
|
||||||
|
uint8_t m_number;
|
||||||
|
|
||||||
|
/// mapping type
|
||||||
|
MappingType m_type;
|
||||||
|
|
||||||
|
/// optional value
|
||||||
|
int8_t m_value;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// number of mapped buttons
|
||||||
|
uint8_t m_numMappedButtons;
|
||||||
|
|
||||||
|
/// actual button mappings
|
||||||
|
Map m_mappedButtons[64];
|
||||||
|
|
||||||
|
/// number of mapped axis
|
||||||
|
uint8_t m_numMappedAxis;
|
||||||
|
|
||||||
|
/// actual axis mappings
|
||||||
|
Map m_mappedAxis[16];
|
||||||
|
|
||||||
|
/// number of mapped rotary
|
||||||
|
uint8_t m_numMappedRotary;
|
||||||
|
|
||||||
|
/// actual rotary mappings
|
||||||
|
Map m_mappedRotary[8];
|
||||||
|
|
||||||
|
/// automatic mouse movement in X direction
|
||||||
|
int16_t m_mouseMoveX;
|
||||||
|
|
||||||
|
/// automatic mouse movement in Y direction
|
||||||
|
int16_t m_mouseMoveY;
|
||||||
|
|
||||||
|
/// current EEPROM position
|
||||||
|
uint16_t m_eepromPosition;
|
||||||
|
|
||||||
|
/// number of macros
|
||||||
|
uint8_t m_numMacros;
|
||||||
|
|
||||||
|
/// macro start position
|
||||||
|
uint16_t *m_macroStart;
|
||||||
|
|
||||||
|
/// different display states
|
||||||
|
enum DISPLAY_STATE {
|
||||||
|
/// almost blank display to protect oled
|
||||||
|
DISPLAY_BLANK = 0,
|
||||||
|
/// show current profile
|
||||||
|
DISPLAY_PROFILE,
|
||||||
|
/// show confirmation screen
|
||||||
|
DISPLAY_CONFIRMATION,
|
||||||
|
/// show user submitted (via USB) string
|
||||||
|
DISPLAY_USER_STRING
|
||||||
|
};
|
||||||
|
|
||||||
|
/// active display state
|
||||||
|
DISPLAY_STATE m_displayState;
|
||||||
|
|
||||||
|
/// time when state started
|
||||||
|
uint32_t m_stateStarted;
|
||||||
|
|
||||||
|
/// time when state should be timed out
|
||||||
|
uint32_t m_stateTimeout;
|
||||||
|
|
||||||
|
/// time for next bar update
|
||||||
|
uint32_t m_nextBarUpdate;
|
||||||
|
|
||||||
|
/// screen saver last dot X position
|
||||||
|
uint8_t m_dotX;
|
||||||
|
|
||||||
|
/// screen saver last dot Y position
|
||||||
|
uint8_t m_dotY;
|
||||||
|
|
||||||
|
/// user submitted string to output
|
||||||
|
char m_userString[43];
|
||||||
|
|
||||||
|
/// timeout of submitted string
|
||||||
|
uint32_t m_userTimeout;
|
||||||
|
|
||||||
|
float m_relMouseX, m_relMouseY;
|
||||||
|
uint16_t m_customImage;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CIMDITPROFILE_H_
|
|
@ -6,7 +6,7 @@
|
||||||
* Licensed under MIT license
|
* Licensed under MIT license
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
#include "Arduino.h"
|
||||||
// own includes
|
// own includes
|
||||||
#include "cimditrotary.h"
|
#include "cimditrotary.h"
|
||||||
|
|
||||||
|
@ -15,9 +15,6 @@ CimditRotary::CimditRotary() {
|
||||||
m_delta = 0;
|
m_delta = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CimditRotary::begin() {
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CimditRotary::update(bool a, bool b) {
|
bool CimditRotary::update(bool a, bool b) {
|
||||||
if (a == m_a) return false; // no change
|
if (a == m_a) return false; // no change
|
||||||
if (a && !m_a) { // rising bit a
|
if (a && !m_a) { // rising bit a
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
* Licensed under MIT license
|
* Licensed under MIT license
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef CIMDITROTARY_H_
|
#ifndef CIMDITROTARY_H_
|
||||||
#define CIMDITROTARY_H_
|
#define CIMDITROTARY_H_
|
||||||
|
|
||||||
|
@ -21,9 +22,6 @@ class CimditRotary {
|
||||||
/// constructor
|
/// constructor
|
||||||
CimditRotary();
|
CimditRotary();
|
||||||
|
|
||||||
/// initialize
|
|
||||||
void begin();
|
|
||||||
|
|
||||||
/// update internal state with new inputs
|
/// update internal state with new inputs
|
||||||
/// \param a first pin
|
/// \param a first pin
|
||||||
/// \param b second pin
|
/// \param b second pin
|
||||||
|
|
|
@ -0,0 +1,282 @@
|
||||||
|
/**
|
||||||
|
* \file cimditssd1306.h
|
||||||
|
* \brief Declaration of the CimditSSD1306 class
|
||||||
|
* \author GrumpyDeveloper (Sascha Nitsch)
|
||||||
|
* \copyright 2022 Sascha Nitsch
|
||||||
|
* Licensed under MIT license
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
// system includes
|
||||||
|
#include <avr/pgmspace.h>
|
||||||
|
#include <util/delay.h>
|
||||||
|
|
||||||
|
// our includes
|
||||||
|
#include "cimditssd1306.h"
|
||||||
|
#include "glcdfont.c"
|
||||||
|
|
||||||
|
CimditSSD1306::CimditSSD1306(uint8_t w, uint8_t h, uint8_t i2cAddr) {
|
||||||
|
m_width = w;
|
||||||
|
m_height = h;
|
||||||
|
m_buffer = nullptr;
|
||||||
|
m_cursorX = m_cursorY = 0;
|
||||||
|
m_textsizeX = m_textsizeY = 1;
|
||||||
|
m_state = true;
|
||||||
|
m_i2cAddr = i2cAddr;
|
||||||
|
}
|
||||||
|
|
||||||
|
CimditSSD1306::~CimditSSD1306() {
|
||||||
|
if (m_buffer) {
|
||||||
|
free(m_buffer);
|
||||||
|
m_buffer = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CimditSSD1306::commandStart() {
|
||||||
|
Wire.beginTransmission(m_i2cAddr);
|
||||||
|
Wire.write((uint8_t)0x00);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CimditSSD1306::commandEnd() {
|
||||||
|
Wire.endTransmission();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CimditSSD1306::commandListProgMem(const uint8_t *c, uint8_t n) {
|
||||||
|
uint16_t bytesOut = 1;
|
||||||
|
while (n--) {
|
||||||
|
if (bytesOut >= BUFFER_LENGTH) {
|
||||||
|
commandEnd();
|
||||||
|
commandStart();
|
||||||
|
bytesOut = 1;
|
||||||
|
}
|
||||||
|
Wire.write(pgm_read_byte(c++));
|
||||||
|
bytesOut++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// static intialization part 1
|
||||||
|
static const uint8_t PROGMEM init1[] = {
|
||||||
|
SSD1306_SET_DISPLAY_OFF,
|
||||||
|
SSD1306_SET_DISPLAY_CLOCK_DIVIDE_RATIO, 0x80,
|
||||||
|
SSD1306_SET_MULTIPLEX_RATIO
|
||||||
|
};
|
||||||
|
|
||||||
|
/// static initialization part 2
|
||||||
|
static const uint8_t PROGMEM init2[] = {
|
||||||
|
SSD1306_SET_DISPLAY_OFFSET, 0x0,
|
||||||
|
SSD1306_SET_DISPLAY_START_LINE_0,
|
||||||
|
SSD1306_CHARGE_PUMP_SETTING, 0x14,
|
||||||
|
SSD1306_SET_MEMORY_ADDRESSING_MODE, 0x00,
|
||||||
|
SSD1306_SET_SEGMENT_RE_MAP_127,
|
||||||
|
SSD1306_SET_COM_OUTPUT_SCAN_DIRECTION_REMAPPED,
|
||||||
|
SSD1306_SET_COM_PINS_HARDWARE_CONFIGURATION, 0x02,
|
||||||
|
SSD1306_SET_CONTRAST_CONTROL, 0x8F,
|
||||||
|
SSD1306_SET_PRE_CHARGE_PERIOD, 0xF1,
|
||||||
|
SSD1306_SET_VCOM_DESELECT_LEVEL, 0x20,
|
||||||
|
SSD1306_ENTIRE_DISPLAY_ON,
|
||||||
|
SSD1306_SET_NORMAL_DISPLAY,
|
||||||
|
SSD1306_DEACTIVATE_SCROLL,
|
||||||
|
SSD1306_SET_DISPLAY_ON
|
||||||
|
};
|
||||||
|
|
||||||
|
bool CimditSSD1306::begin() {
|
||||||
|
if ((!m_buffer) && !(m_buffer = reinterpret_cast<uint8_t *>(malloc(m_width * (m_height / 8)))))
|
||||||
|
return false;
|
||||||
|
clearDisplay();
|
||||||
|
// Init sequence
|
||||||
|
commandStart();
|
||||||
|
commandListProgMem(init1, sizeof(init1));
|
||||||
|
Wire.write(m_height - 1);
|
||||||
|
commandListProgMem(init2, sizeof(init2));
|
||||||
|
commandEnd();
|
||||||
|
return true; // Success
|
||||||
|
}
|
||||||
|
|
||||||
|
void CimditSSD1306::drawPixel(uint8_t x, uint8_t y, bool state) {
|
||||||
|
if (state) {
|
||||||
|
m_buffer[x + (y >> 3) * m_width] |= (1 << (y & 7));
|
||||||
|
} else {
|
||||||
|
m_buffer[x + (y >> 3) * m_width] &= ~(1 << (y & 7));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CimditSSD1306::clearDisplay(void) {
|
||||||
|
memset(m_buffer, 0, m_width * ((m_height + 7) / 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CimditSSD1306::drawFastHLine(uint8_t x, uint8_t y, uint8_t w, bool state) {
|
||||||
|
uint8_t *pBuf = m_buffer + (y / 8) * m_width + x;
|
||||||
|
uint8_t mask = 1 << (y & 7);
|
||||||
|
if (state) {
|
||||||
|
while (w--) {
|
||||||
|
*pBuf++ |= mask;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mask = ~mask;
|
||||||
|
while (w--) {
|
||||||
|
*pBuf++ &= mask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CimditSSD1306::drawFastVLine(uint8_t x, uint8_t y, uint8_t h, bool state) {
|
||||||
|
uint8_t *pBuf = m_buffer + (y / 8) * m_width + x;
|
||||||
|
// do the first partial byte, if necessary - this requires some masking
|
||||||
|
uint8_t mod = (y & 7);
|
||||||
|
if (mod) {
|
||||||
|
// mask off the high n bits we want to set
|
||||||
|
mod = 8 - mod;
|
||||||
|
// note - lookup table results in a nearly 10% performance
|
||||||
|
// improvement in fill* functions
|
||||||
|
// uint8_t mask = ~(0xFF >> mod);
|
||||||
|
static const uint8_t PROGMEM premask[8] = {0x00, 0x80, 0xC0, 0xE0,
|
||||||
|
0xF0, 0xF8, 0xFC, 0xFE};
|
||||||
|
uint8_t mask = pgm_read_byte(&premask[mod]);
|
||||||
|
// adjust the mask if we're not going to reach the end of this byte
|
||||||
|
if (h < mod) {
|
||||||
|
mask &= (0XFF >> (mod - h));
|
||||||
|
}
|
||||||
|
if (state) {
|
||||||
|
*pBuf |= mask;
|
||||||
|
} else {
|
||||||
|
*pBuf &= ~mask;
|
||||||
|
}
|
||||||
|
pBuf += m_width;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (h >= mod) { // More to go?
|
||||||
|
h -= mod;
|
||||||
|
// Write solid bytes while we can - effectively 8 rows at a time
|
||||||
|
if (h >= 8) {
|
||||||
|
// store a local value to work with
|
||||||
|
uint8_t val = state ? 255 : 0;
|
||||||
|
do {
|
||||||
|
*pBuf = val; // Set byte
|
||||||
|
pBuf += m_width; // Advance pointer 8 rows
|
||||||
|
h -= 8; // Subtract 8 rows from height
|
||||||
|
} while (h >= 8);
|
||||||
|
}
|
||||||
|
if (h) { // Do the final partial byte, if necessary
|
||||||
|
mod = h & 7;
|
||||||
|
// this time we want to mask the low bits of the byte,
|
||||||
|
// vs the high bits we did above
|
||||||
|
// uint8_t mask = (1 << mod) - 1;
|
||||||
|
// note - lookup table results in a nearly 10% performance
|
||||||
|
// improvement in fill* functions
|
||||||
|
static const uint8_t PROGMEM postmask[8] = {0x00, 0x01, 0x03, 0x07,
|
||||||
|
0x0F, 0x1F, 0x3F, 0x7F};
|
||||||
|
uint8_t mask = pgm_read_byte(&postmask[mod]);
|
||||||
|
if (state) {
|
||||||
|
*pBuf |= mask;
|
||||||
|
} else {
|
||||||
|
*pBuf &= ~mask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// statric start command for transmitting screen content
|
||||||
|
static const uint8_t PROGMEM dlist1[] = {
|
||||||
|
SSD1306_SET_PAGE_ADDRESS, 0, 0x3,
|
||||||
|
SSD1306_SET_COLUMN_ADDRESS, 0
|
||||||
|
};
|
||||||
|
|
||||||
|
void CimditSSD1306::display(void) {
|
||||||
|
commandStart();
|
||||||
|
commandListProgMem(dlist1, sizeof(dlist1));
|
||||||
|
Wire.write(m_width - 1); // Column end address
|
||||||
|
commandEnd();
|
||||||
|
uint16_t count = m_width * (m_height >> 3);
|
||||||
|
uint8_t *ptr = m_buffer;
|
||||||
|
Wire.beginTransmission(m_i2cAddr);
|
||||||
|
Wire.write((uint8_t)0x40);
|
||||||
|
uint16_t bytesOut = 1;
|
||||||
|
while (count--) {
|
||||||
|
if (bytesOut >= BUFFER_LENGTH) {
|
||||||
|
Wire.endTransmission();
|
||||||
|
Wire.beginTransmission(m_i2cAddr);
|
||||||
|
Wire.write((uint8_t)0x40);
|
||||||
|
bytesOut = 1;
|
||||||
|
}
|
||||||
|
Wire.write(*ptr++);
|
||||||
|
bytesOut++;
|
||||||
|
}
|
||||||
|
Wire.endTransmission();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CimditSSD1306::displayPartial(uint8_t part) {
|
||||||
|
commandStart();
|
||||||
|
Wire.write(SSD1306_SET_PAGE_ADDRESS);
|
||||||
|
Wire.write(part); // Page start address
|
||||||
|
Wire.write(part); // Page end address
|
||||||
|
Wire.write(SSD1306_SET_COLUMN_ADDRESS);
|
||||||
|
Wire.write(0);
|
||||||
|
Wire.write(m_width - 1); // Column end address
|
||||||
|
Wire.endTransmission();
|
||||||
|
uint16_t count = m_width * (m_height >> 5);
|
||||||
|
uint8_t *ptr = m_buffer + m_width * part;
|
||||||
|
Wire.beginTransmission(m_i2cAddr);
|
||||||
|
Wire.write((uint8_t)0x40);
|
||||||
|
uint16_t bytesOut = 1;
|
||||||
|
while (count--) {
|
||||||
|
if (bytesOut >= BUFFER_LENGTH) {
|
||||||
|
Wire.endTransmission();
|
||||||
|
Wire.beginTransmission(m_i2cAddr);
|
||||||
|
Wire.write((uint8_t)0x40);
|
||||||
|
bytesOut = 1;
|
||||||
|
}
|
||||||
|
Wire.write(*ptr++);
|
||||||
|
bytesOut++;
|
||||||
|
}
|
||||||
|
Wire.endTransmission();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CimditSSD1306::setTextSize(uint8_t sX, uint8_t sY) {
|
||||||
|
m_textsizeX = sX;
|
||||||
|
m_textsizeY = sY;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t CimditSSD1306::write(uint8_t c) {
|
||||||
|
if (c == '\n' || m_cursorX + m_textsizeX * 6) { // a newline or text oveflow
|
||||||
|
m_cursorX = 0; // set X to zero
|
||||||
|
m_cursorY += m_textsizeY * 8; // go down one line
|
||||||
|
} else if (c == '\r') { // a carriage return
|
||||||
|
m_cursorX = 0; // set X to zero
|
||||||
|
} else { // something to print
|
||||||
|
drawChar(m_cursorX, m_cursorY, c, m_textsizeX, m_textsizeY);
|
||||||
|
m_cursorX += m_textsizeX * 6; // Advance x one char
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CimditSSD1306::drawChar(uint8_t x, uint8_t y, unsigned char c, uint8_t sizeX, uint8_t sizeY) {
|
||||||
|
for (int8_t i = 0; i < 5; i++) { // one char is 5 pixel wide
|
||||||
|
uint8_t line = pgm_read_byte(&font[c * 5 + i]); // get pixel from flash/program memory
|
||||||
|
for (int8_t j = 0; j < 8; j++, line >>= 1) { // for each 8 lines
|
||||||
|
if (line & 1) {
|
||||||
|
if (sizeX == 1 && sizeY == 1) { // one pixel size, draw pixel direct
|
||||||
|
drawPixel(x + i, y + j, m_state);
|
||||||
|
} else {
|
||||||
|
fillRect(x + i * sizeX, y + j * sizeY, sizeX, sizeY, m_state); // draw rectangles with given size multiplicator
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CimditSSD1306::fillRect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, bool state) {
|
||||||
|
if (y + h >= m_height) h = m_height - y;
|
||||||
|
if (x + w >= m_width) w = m_width - x;
|
||||||
|
for (int16_t i = x; i < x + w; i++) {
|
||||||
|
drawFastVLine(i, y, h, state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CimditSSD1306::setTextState(bool state) {
|
||||||
|
m_state = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CimditSSD1306::setCursor(uint8_t x, uint8_t y) {
|
||||||
|
m_cursorX = x;
|
||||||
|
m_cursorY = y;
|
||||||
|
}
|
|
@ -0,0 +1,225 @@
|
||||||
|
/**
|
||||||
|
* \file cimditssd1306.h
|
||||||
|
* \brief Declaration of the CimditSSD1306 class
|
||||||
|
* \author GrumpyDeveloper (Sascha Nitsch)
|
||||||
|
* \copyright 2022 Sascha Nitsch
|
||||||
|
* Licensed under MIT license
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CIMDITSSD1306_H_
|
||||||
|
#define CIMDITSSD1306_H_
|
||||||
|
|
||||||
|
// system includes
|
||||||
|
#include <Wire.h>
|
||||||
|
|
||||||
|
/// memory adressing mode
|
||||||
|
#define SSD1306_SET_MEMORY_ADDRESSING_MODE 0x20
|
||||||
|
/// column address start and end
|
||||||
|
#define SSD1306_SET_COLUMN_ADDRESS 0x21
|
||||||
|
/// page start and end address
|
||||||
|
#define SSD1306_SET_PAGE_ADDRESS 0x22
|
||||||
|
/// deactivate scrolling
|
||||||
|
#define SSD1306_DEACTIVATE_SCROLL 0x2E
|
||||||
|
/// set display start line to 0
|
||||||
|
#define SSD1306_SET_DISPLAY_START_LINE_0 0x40
|
||||||
|
/// set contrast
|
||||||
|
#define SSD1306_SET_CONTRAST_CONTROL 0x81
|
||||||
|
/// charge pump setting
|
||||||
|
#define SSD1306_CHARGE_PUMP_SETTING 0x8D
|
||||||
|
/// set segment re-map to column 127
|
||||||
|
#define SSD1306_SET_SEGMENT_RE_MAP_127 0xA1
|
||||||
|
/// entire display on
|
||||||
|
#define SSD1306_ENTIRE_DISPLAY_ON 0xA4
|
||||||
|
/// set normal display
|
||||||
|
#define SSD1306_SET_NORMAL_DISPLAY 0xA6
|
||||||
|
/// set multiplex ratio
|
||||||
|
#define SSD1306_SET_MULTIPLEX_RATIO 0xA8
|
||||||
|
/// set display off
|
||||||
|
#define SSD1306_SET_DISPLAY_OFF 0xAE
|
||||||
|
/// set display on
|
||||||
|
#define SSD1306_SET_DISPLAY_ON 0xAF
|
||||||
|
/// set COM output scan direction to remapped
|
||||||
|
#define SSD1306_SET_COM_OUTPUT_SCAN_DIRECTION_REMAPPED 0xC8
|
||||||
|
/// set display offser
|
||||||
|
#define SSD1306_SET_DISPLAY_OFFSET 0xD3
|
||||||
|
/// set display clock divide ratio
|
||||||
|
#define SSD1306_SET_DISPLAY_CLOCK_DIVIDE_RATIO 0xD5
|
||||||
|
// set pre-charge period
|
||||||
|
#define SSD1306_SET_PRE_CHARGE_PERIOD 0xD9
|
||||||
|
// set com pins hardware configuration
|
||||||
|
#define SSD1306_SET_COM_PINS_HARDWARE_CONFIGURATION 0xDA
|
||||||
|
// set VCOM deselect level
|
||||||
|
#define SSD1306_SET_VCOM_DESELECT_LEVEL 0xDB
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Simple drawing class for SSD1306 OLED displays
|
||||||
|
*/
|
||||||
|
class CimditSSD1306 : public Print {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* \brief constructor
|
||||||
|
* \param w width of display in pixel
|
||||||
|
* \param h height of display in pixel
|
||||||
|
* \param i2cAddr i2c address
|
||||||
|
*/
|
||||||
|
CimditSSD1306(uint8_t w, uint8_t h, uint8_t i2cAddr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief destructor
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
~CimditSSD1306();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief initialize library, needs to be called before any other graphic functions
|
||||||
|
* \return true on success
|
||||||
|
*/
|
||||||
|
bool begin();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief send internal buffer to display
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void display(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief send part of internal buffer to display
|
||||||
|
* \param part which part of screen (each part is 8 pixel high, starting from top at 0
|
||||||
|
*/
|
||||||
|
void displayPartial(uint8_t part);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief clear display content in internal buffer, call display or displayPartial to take effect
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void clearDisplay(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief set a pixel to on or off
|
||||||
|
* \param x x coordinate of pixel
|
||||||
|
* \param y y coordinate of pixel
|
||||||
|
* \param state true for on, false for off
|
||||||
|
*/
|
||||||
|
void drawPixel(uint8_t x, uint8_t y, bool state);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief draw a horizontal line
|
||||||
|
* \param x start x position
|
||||||
|
* \param y start y position
|
||||||
|
* \param w width in pixel
|
||||||
|
* \param state true for on, false for off
|
||||||
|
*/
|
||||||
|
void drawFastHLine(uint8_t x, uint8_t y, uint8_t w, bool state);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Draw a vertical line with a width and state.
|
||||||
|
* Functionality based on adafruit GFX library
|
||||||
|
* \param x x coordinate
|
||||||
|
* \param y top y coordinate
|
||||||
|
* \param h height of the line in pixels
|
||||||
|
* \param state true for pixel on, false for off
|
||||||
|
* \note Changes buffer contents only, no immediate effect on display.
|
||||||
|
Follow up with a call to display() or displayPartial()
|
||||||
|
*/
|
||||||
|
void drawFastVLine(uint8_t x, uint8_t y, uint8_t h, bool state);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief draw a filled rectangle
|
||||||
|
*
|
||||||
|
* \param x x start position
|
||||||
|
* \param y y start position
|
||||||
|
* \param w width in pixel
|
||||||
|
* \param h height in pixel
|
||||||
|
* \param state
|
||||||
|
*/
|
||||||
|
void fillRect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, bool state);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief set text scaling factor
|
||||||
|
*
|
||||||
|
* \param sx X-scaling factor
|
||||||
|
* \param sy Y-scaling factor
|
||||||
|
*/
|
||||||
|
void setTextSize(uint8_t sx, uint8_t sy);
|
||||||
|
|
||||||
|
using Print::write;
|
||||||
|
/**
|
||||||
|
* \brief print a single character to screen
|
||||||
|
*
|
||||||
|
* \param c character to print
|
||||||
|
* \return 1
|
||||||
|
*/
|
||||||
|
size_t write(uint8_t c);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief set text cursor position
|
||||||
|
* \param x X coordinate
|
||||||
|
* \param y Y coordinate
|
||||||
|
*/
|
||||||
|
void setCursor(uint8_t x, uint8_t y);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief set text state
|
||||||
|
* \param state state to output
|
||||||
|
*/
|
||||||
|
void setTextState(bool state);
|
||||||
|
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* \brief draw a single character c at x,y with scaling sX, sY
|
||||||
|
* \param x left coordinate of character
|
||||||
|
* \param y lower coordinate of character
|
||||||
|
* \param c character to print
|
||||||
|
* \param sX horizontal scaling factor
|
||||||
|
* \param sY veritcal scaling factor
|
||||||
|
*/
|
||||||
|
void drawChar(uint8_t x, uint8_t y, unsigned char c, uint8_t size_x, uint8_t size_y);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief start command transmission
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void commandStart();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief send command list from program memory
|
||||||
|
* \param c start pointer
|
||||||
|
* \param n number of items to output
|
||||||
|
*/
|
||||||
|
void commandListProgMem(const uint8_t *c, uint8_t n);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief finish command sending
|
||||||
|
*/
|
||||||
|
void commandEnd();
|
||||||
|
|
||||||
|
/// display width
|
||||||
|
uint8_t m_width;
|
||||||
|
|
||||||
|
/// display height
|
||||||
|
uint8_t m_height;
|
||||||
|
|
||||||
|
/// text cursor position X
|
||||||
|
uint8_t m_cursorX;
|
||||||
|
|
||||||
|
/// text cursor position Y
|
||||||
|
uint8_t m_cursorY;
|
||||||
|
|
||||||
|
/// text drawing state
|
||||||
|
bool m_state;
|
||||||
|
|
||||||
|
/// horizontal text scaling factor
|
||||||
|
uint8_t m_textsizeX;
|
||||||
|
|
||||||
|
/// vertical text scaling factor
|
||||||
|
uint8_t m_textsizeY;
|
||||||
|
|
||||||
|
/// internal buffer for screen pixel data
|
||||||
|
uint8_t *m_buffer;
|
||||||
|
|
||||||
|
/// i2c address of display
|
||||||
|
uint8_t m_i2cAddr;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CIMDITSSD1306_H_
|
|
@ -0,0 +1,67 @@
|
||||||
|
/// we have a display connected
|
||||||
|
#define HAVE_DISPLAY
|
||||||
|
|
||||||
|
/// use a custom keyboard layout
|
||||||
|
#define HID_CUSTOM_LAYOUT
|
||||||
|
|
||||||
|
/// use german keyboard layout
|
||||||
|
#define LAYOUT_GERMAN
|
||||||
|
|
||||||
|
#ifdef HAVE_DISPLAY
|
||||||
|
/// no splash screen on OLED
|
||||||
|
#define SSD1306_NO_SPLASH
|
||||||
|
/// OLED display width, in pixels
|
||||||
|
#define SCREEN_WIDTH 128
|
||||||
|
/// OLED display height, in pixels
|
||||||
|
#define SCREEN_HEIGHT 32
|
||||||
|
/// OLED screen address
|
||||||
|
#define SCREEN_ADDRESS 0x3C
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// how long does the profile selection wait for a confirmation
|
||||||
|
#define SELECTION_TIME 10000
|
||||||
|
|
||||||
|
/// how long to show the profile name/icon until going into screen saver
|
||||||
|
#define PROFILE_TIME 60000
|
||||||
|
|
||||||
|
/// update timeout bar every second
|
||||||
|
#define BAR_UPDATE_TIME 1000
|
||||||
|
|
||||||
|
/// update usb devices every x ms if needed
|
||||||
|
#define UPDATE_INTERVAL 10
|
||||||
|
|
||||||
|
/// dead zone (noise) around the center of the joystick X axis
|
||||||
|
#define JOYSTICK_DEAD_ZONE_X 20
|
||||||
|
|
||||||
|
/// dead zone (noise) around the center of the joystick Y axcs
|
||||||
|
#define JOYSTICK_DEAD_ZONE_Y 20
|
||||||
|
|
||||||
|
/// i2c address of the external EEPROM
|
||||||
|
#define EXTERNAL_EEPROM 0x50
|
||||||
|
|
||||||
|
/// pin for analog mux bit 0
|
||||||
|
#define ANALOG_MUX0 6
|
||||||
|
|
||||||
|
/// pin for analog mux bit 1
|
||||||
|
#define ANALOG_MUX1 8
|
||||||
|
|
||||||
|
/// pin for analog mux bit 2
|
||||||
|
#define ANALOG_MUX2 9
|
||||||
|
|
||||||
|
/// pin for analog mux bit 3
|
||||||
|
#define ANALOG_MUX3 10
|
||||||
|
|
||||||
|
/// analog input pin
|
||||||
|
#define ANALOG_IN A1
|
||||||
|
|
||||||
|
/// rotary encoder interrupt pin
|
||||||
|
#define ROT_INT 7
|
||||||
|
|
||||||
|
/// scan analog every 12 milliseconds
|
||||||
|
#define ANALOG_INTERVAL 12
|
||||||
|
|
||||||
|
/// scan keys every 4 milliseconds
|
||||||
|
#define KEYSCAN_INTERVAL 4
|
||||||
|
|
||||||
|
/// number of profiles
|
||||||
|
#define NUMBER_OF_PROFILES 8
|
|
@ -0,0 +1,143 @@
|
||||||
|
// This is the 'classic' fixed-space bitmap font for Adafruit_GFX since 1.0.
|
||||||
|
// See gfxfont.h for newer custom bitmap font info.
|
||||||
|
|
||||||
|
#ifndef FONT5X7_H
|
||||||
|
#define FONT5X7_H
|
||||||
|
|
||||||
|
#ifdef __AVR__
|
||||||
|
#include <avr/io.h>
|
||||||
|
#include <avr/pgmspace.h>
|
||||||
|
#elif defined(ESP8266)
|
||||||
|
#include <pgmspace.h>
|
||||||
|
#elif defined(__IMXRT1052__) || defined(__IMXRT1062__)
|
||||||
|
// PROGMEM is defefind for T4 to place data in specific memory section
|
||||||
|
#undef PROGMEM
|
||||||
|
#define PROGMEM
|
||||||
|
#else
|
||||||
|
#define PROGMEM
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Standard ASCII 5x7 font
|
||||||
|
|
||||||
|
static const unsigned char font[] PROGMEM = {
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x5B, 0x4F, 0x5B, 0x3E, 0x3E, 0x6B,
|
||||||
|
0x4F, 0x6B, 0x3E, 0x1C, 0x3E, 0x7C, 0x3E, 0x1C, 0x18, 0x3C, 0x7E, 0x3C,
|
||||||
|
0x18, 0x1C, 0x57, 0x7D, 0x57, 0x1C, 0x1C, 0x5E, 0x7F, 0x5E, 0x1C, 0x00,
|
||||||
|
0x18, 0x3C, 0x18, 0x00, 0xFF, 0xE7, 0xC3, 0xE7, 0xFF, 0x00, 0x18, 0x24,
|
||||||
|
0x18, 0x00, 0xFF, 0xE7, 0xDB, 0xE7, 0xFF, 0x30, 0x48, 0x3A, 0x06, 0x0E,
|
||||||
|
0x26, 0x29, 0x79, 0x29, 0x26, 0x40, 0x7F, 0x05, 0x05, 0x07, 0x40, 0x7F,
|
||||||
|
0x05, 0x25, 0x3F, 0x5A, 0x3C, 0xE7, 0x3C, 0x5A, 0x7F, 0x3E, 0x1C, 0x1C,
|
||||||
|
0x08, 0x08, 0x1C, 0x1C, 0x3E, 0x7F, 0x14, 0x22, 0x7F, 0x22, 0x14, 0x5F,
|
||||||
|
0x5F, 0x00, 0x5F, 0x5F, 0x06, 0x09, 0x7F, 0x01, 0x7F, 0x00, 0x66, 0x89,
|
||||||
|
0x95, 0x6A, 0x60, 0x60, 0x60, 0x60, 0x60, 0x94, 0xA2, 0xFF, 0xA2, 0x94,
|
||||||
|
0x08, 0x04, 0x7E, 0x04, 0x08, 0x10, 0x20, 0x7E, 0x20, 0x10, 0x08, 0x08,
|
||||||
|
0x2A, 0x1C, 0x08, 0x08, 0x1C, 0x2A, 0x08, 0x08, 0x1E, 0x10, 0x10, 0x10,
|
||||||
|
0x10, 0x0C, 0x1E, 0x0C, 0x1E, 0x0C, 0x30, 0x38, 0x3E, 0x38, 0x30, 0x06,
|
||||||
|
0x0E, 0x3E, 0x0E, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5F,
|
||||||
|
0x00, 0x00, 0x00, 0x07, 0x00, 0x07, 0x00, 0x14, 0x7F, 0x14, 0x7F, 0x14,
|
||||||
|
0x24, 0x2A, 0x7F, 0x2A, 0x12, 0x23, 0x13, 0x08, 0x64, 0x62, 0x36, 0x49,
|
||||||
|
0x56, 0x20, 0x50, 0x00, 0x08, 0x07, 0x03, 0x00, 0x00, 0x1C, 0x22, 0x41,
|
||||||
|
0x00, 0x00, 0x41, 0x22, 0x1C, 0x00, 0x2A, 0x1C, 0x7F, 0x1C, 0x2A, 0x08,
|
||||||
|
0x08, 0x3E, 0x08, 0x08, 0x00, 0x80, 0x70, 0x30, 0x00, 0x08, 0x08, 0x08,
|
||||||
|
0x08, 0x08, 0x00, 0x00, 0x60, 0x60, 0x00, 0x20, 0x10, 0x08, 0x04, 0x02,
|
||||||
|
0x3E, 0x51, 0x49, 0x45, 0x3E, 0x00, 0x42, 0x7F, 0x40, 0x00, 0x72, 0x49,
|
||||||
|
0x49, 0x49, 0x46, 0x21, 0x41, 0x49, 0x4D, 0x33, 0x18, 0x14, 0x12, 0x7F,
|
||||||
|
0x10, 0x27, 0x45, 0x45, 0x45, 0x39, 0x3C, 0x4A, 0x49, 0x49, 0x31, 0x41,
|
||||||
|
0x21, 0x11, 0x09, 0x07, 0x36, 0x49, 0x49, 0x49, 0x36, 0x46, 0x49, 0x49,
|
||||||
|
0x29, 0x1E, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x40, 0x34, 0x00, 0x00,
|
||||||
|
0x00, 0x08, 0x14, 0x22, 0x41, 0x14, 0x14, 0x14, 0x14, 0x14, 0x00, 0x41,
|
||||||
|
0x22, 0x14, 0x08, 0x02, 0x01, 0x59, 0x09, 0x06, 0x3E, 0x41, 0x5D, 0x59,
|
||||||
|
0x4E, 0x7C, 0x12, 0x11, 0x12, 0x7C, 0x7F, 0x49, 0x49, 0x49, 0x36, 0x3E,
|
||||||
|
0x41, 0x41, 0x41, 0x22, 0x7F, 0x41, 0x41, 0x41, 0x3E, 0x7F, 0x49, 0x49,
|
||||||
|
0x49, 0x41, 0x7F, 0x09, 0x09, 0x09, 0x01, 0x3E, 0x41, 0x41, 0x51, 0x73,
|
||||||
|
0x7F, 0x08, 0x08, 0x08, 0x7F, 0x00, 0x41, 0x7F, 0x41, 0x00, 0x20, 0x40,
|
||||||
|
0x41, 0x3F, 0x01, 0x7F, 0x08, 0x14, 0x22, 0x41, 0x7F, 0x40, 0x40, 0x40,
|
||||||
|
0x40, 0x7F, 0x02, 0x1C, 0x02, 0x7F, 0x7F, 0x04, 0x08, 0x10, 0x7F, 0x3E,
|
||||||
|
0x41, 0x41, 0x41, 0x3E, 0x7F, 0x09, 0x09, 0x09, 0x06, 0x3E, 0x41, 0x51,
|
||||||
|
0x21, 0x5E, 0x7F, 0x09, 0x19, 0x29, 0x46, 0x26, 0x49, 0x49, 0x49, 0x32,
|
||||||
|
0x03, 0x01, 0x7F, 0x01, 0x03, 0x3F, 0x40, 0x40, 0x40, 0x3F, 0x1F, 0x20,
|
||||||
|
0x40, 0x20, 0x1F, 0x3F, 0x40, 0x38, 0x40, 0x3F, 0x63, 0x14, 0x08, 0x14,
|
||||||
|
0x63, 0x03, 0x04, 0x78, 0x04, 0x03, 0x61, 0x59, 0x49, 0x4D, 0x43, 0x00,
|
||||||
|
0x7F, 0x41, 0x41, 0x41, 0x02, 0x04, 0x08, 0x10, 0x20, 0x00, 0x41, 0x41,
|
||||||
|
0x41, 0x7F, 0x04, 0x02, 0x01, 0x02, 0x04, 0x40, 0x40, 0x40, 0x40, 0x40,
|
||||||
|
0x00, 0x03, 0x07, 0x08, 0x00, 0x20, 0x54, 0x54, 0x78, 0x40, 0x7F, 0x28,
|
||||||
|
0x44, 0x44, 0x38, 0x38, 0x44, 0x44, 0x44, 0x28, 0x38, 0x44, 0x44, 0x28,
|
||||||
|
0x7F, 0x38, 0x54, 0x54, 0x54, 0x18, 0x00, 0x08, 0x7E, 0x09, 0x02, 0x18,
|
||||||
|
0xA4, 0xA4, 0x9C, 0x78, 0x7F, 0x08, 0x04, 0x04, 0x78, 0x00, 0x44, 0x7D,
|
||||||
|
0x40, 0x00, 0x20, 0x40, 0x40, 0x3D, 0x00, 0x7F, 0x10, 0x28, 0x44, 0x00,
|
||||||
|
0x00, 0x41, 0x7F, 0x40, 0x00, 0x7C, 0x04, 0x78, 0x04, 0x78, 0x7C, 0x08,
|
||||||
|
0x04, 0x04, 0x78, 0x38, 0x44, 0x44, 0x44, 0x38, 0xFC, 0x18, 0x24, 0x24,
|
||||||
|
0x18, 0x18, 0x24, 0x24, 0x18, 0xFC, 0x7C, 0x08, 0x04, 0x04, 0x08, 0x48,
|
||||||
|
0x54, 0x54, 0x54, 0x24, 0x04, 0x04, 0x3F, 0x44, 0x24, 0x3C, 0x40, 0x40,
|
||||||
|
0x20, 0x7C, 0x1C, 0x20, 0x40, 0x20, 0x1C, 0x3C, 0x40, 0x30, 0x40, 0x3C,
|
||||||
|
0x44, 0x28, 0x10, 0x28, 0x44, 0x4C, 0x90, 0x90, 0x90, 0x7C, 0x44, 0x64,
|
||||||
|
0x54, 0x4C, 0x44, 0x00, 0x08, 0x36, 0x41, 0x00, 0x00, 0x00, 0x77, 0x00,
|
||||||
|
0x00, 0x00, 0x41, 0x36, 0x08, 0x00, 0x02, 0x01, 0x02, 0x04, 0x02, 0x3C,
|
||||||
|
0x26, 0x23, 0x26, 0x3C, 0x1E, 0xA1, 0xA1, 0x61, 0x12, 0x3A, 0x40, 0x40,
|
||||||
|
0x20, 0x7A, 0x38, 0x54, 0x54, 0x55, 0x59, 0x21, 0x55, 0x55, 0x79, 0x41,
|
||||||
|
0x22, 0x54, 0x54, 0x78, 0x42, // a-umlaut
|
||||||
|
0x21, 0x55, 0x54, 0x78, 0x40, 0x20, 0x54, 0x55, 0x79, 0x40, 0x0C, 0x1E,
|
||||||
|
0x52, 0x72, 0x12, 0x39, 0x55, 0x55, 0x55, 0x59, 0x39, 0x54, 0x54, 0x54,
|
||||||
|
0x59, 0x39, 0x55, 0x54, 0x54, 0x58, 0x00, 0x00, 0x45, 0x7C, 0x41, 0x00,
|
||||||
|
0x02, 0x45, 0x7D, 0x42, 0x00, 0x01, 0x45, 0x7C, 0x40, 0x7D, 0x12, 0x11,
|
||||||
|
0x12, 0x7D, // A-umlaut
|
||||||
|
0xF0, 0x28, 0x25, 0x28, 0xF0, 0x7C, 0x54, 0x55, 0x45, 0x00, 0x20, 0x54,
|
||||||
|
0x54, 0x7C, 0x54, 0x7C, 0x0A, 0x09, 0x7F, 0x49, 0x32, 0x49, 0x49, 0x49,
|
||||||
|
0x32, 0x3A, 0x44, 0x44, 0x44, 0x3A, // o-umlaut
|
||||||
|
0x32, 0x4A, 0x48, 0x48, 0x30, 0x3A, 0x41, 0x41, 0x21, 0x7A, 0x3A, 0x42,
|
||||||
|
0x40, 0x20, 0x78, 0x00, 0x9D, 0xA0, 0xA0, 0x7D, 0x3D, 0x42, 0x42, 0x42,
|
||||||
|
0x3D, // O-umlaut
|
||||||
|
0x3D, 0x40, 0x40, 0x40, 0x3D, 0x3C, 0x24, 0xFF, 0x24, 0x24, 0x48, 0x7E,
|
||||||
|
0x49, 0x43, 0x66, 0x2B, 0x2F, 0xFC, 0x2F, 0x2B, 0xFF, 0x09, 0x29, 0xF6,
|
||||||
|
0x20, 0xC0, 0x88, 0x7E, 0x09, 0x03, 0x20, 0x54, 0x54, 0x79, 0x41, 0x00,
|
||||||
|
0x00, 0x44, 0x7D, 0x41, 0x30, 0x48, 0x48, 0x4A, 0x32, 0x38, 0x40, 0x40,
|
||||||
|
0x22, 0x7A, 0x00, 0x7A, 0x0A, 0x0A, 0x72, 0x7D, 0x0D, 0x19, 0x31, 0x7D,
|
||||||
|
0x26, 0x29, 0x29, 0x2F, 0x28, 0x26, 0x29, 0x29, 0x29, 0x26, 0x30, 0x48,
|
||||||
|
0x4D, 0x40, 0x20, 0x38, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
|
||||||
|
0x38, 0x2F, 0x10, 0xC8, 0xAC, 0xBA, 0x2F, 0x10, 0x28, 0x34, 0xFA, 0x00,
|
||||||
|
0x00, 0x7B, 0x00, 0x00, 0x08, 0x14, 0x2A, 0x14, 0x22, 0x22, 0x14, 0x2A,
|
||||||
|
0x14, 0x08, 0x55, 0x00, 0x55, 0x00, 0x55, // #176 (25% block) missing in old
|
||||||
|
// code
|
||||||
|
0xAA, 0x55, 0xAA, 0x55, 0xAA, // 50% block
|
||||||
|
0xFF, 0x55, 0xFF, 0x55, 0xFF, // 75% block
|
||||||
|
0x00, 0x00, 0x00, 0xFF, 0x00, 0x10, 0x10, 0x10, 0xFF, 0x00, 0x14, 0x14,
|
||||||
|
0x14, 0xFF, 0x00, 0x10, 0x10, 0xFF, 0x00, 0xFF, 0x10, 0x10, 0xF0, 0x10,
|
||||||
|
0xF0, 0x14, 0x14, 0x14, 0xFC, 0x00, 0x14, 0x14, 0xF7, 0x00, 0xFF, 0x00,
|
||||||
|
0x00, 0xFF, 0x00, 0xFF, 0x14, 0x14, 0xF4, 0x04, 0xFC, 0x14, 0x14, 0x17,
|
||||||
|
0x10, 0x1F, 0x10, 0x10, 0x1F, 0x10, 0x1F, 0x14, 0x14, 0x14, 0x1F, 0x00,
|
||||||
|
0x10, 0x10, 0x10, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x10, 0x10, 0x10,
|
||||||
|
0x10, 0x1F, 0x10, 0x10, 0x10, 0x10, 0xF0, 0x10, 0x00, 0x00, 0x00, 0xFF,
|
||||||
|
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xFF, 0x10, 0x00,
|
||||||
|
0x00, 0x00, 0xFF, 0x14, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x1F,
|
||||||
|
0x10, 0x17, 0x00, 0x00, 0xFC, 0x04, 0xF4, 0x14, 0x14, 0x17, 0x10, 0x17,
|
||||||
|
0x14, 0x14, 0xF4, 0x04, 0xF4, 0x00, 0x00, 0xFF, 0x00, 0xF7, 0x14, 0x14,
|
||||||
|
0x14, 0x14, 0x14, 0x14, 0x14, 0xF7, 0x00, 0xF7, 0x14, 0x14, 0x14, 0x17,
|
||||||
|
0x14, 0x10, 0x10, 0x1F, 0x10, 0x1F, 0x14, 0x14, 0x14, 0xF4, 0x14, 0x10,
|
||||||
|
0x10, 0xF0, 0x10, 0xF0, 0x00, 0x00, 0x1F, 0x10, 0x1F, 0x00, 0x00, 0x00,
|
||||||
|
0x1F, 0x14, 0x00, 0x00, 0x00, 0xFC, 0x14, 0x00, 0x00, 0xF0, 0x10, 0xF0,
|
||||||
|
0x10, 0x10, 0xFF, 0x10, 0xFF, 0x14, 0x14, 0x14, 0xFF, 0x14, 0x10, 0x10,
|
||||||
|
0x10, 0x1F, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x10, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
|
0xFF, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x38, 0x44, 0x44,
|
||||||
|
0x38, 0x44, 0xFC, 0x4A, 0x4A, 0x4A, 0x34, // sharp-s or beta
|
||||||
|
0x7E, 0x02, 0x02, 0x06, 0x06, 0x02, 0x7E, 0x02, 0x7E, 0x02, 0x63, 0x55,
|
||||||
|
0x49, 0x41, 0x63, 0x38, 0x44, 0x44, 0x3C, 0x04, 0x40, 0x7E, 0x20, 0x1E,
|
||||||
|
0x20, 0x06, 0x02, 0x7E, 0x02, 0x02, 0x99, 0xA5, 0xE7, 0xA5, 0x99, 0x1C,
|
||||||
|
0x2A, 0x49, 0x2A, 0x1C, 0x4C, 0x72, 0x01, 0x72, 0x4C, 0x30, 0x4A, 0x4D,
|
||||||
|
0x4D, 0x30, 0x30, 0x48, 0x78, 0x48, 0x30, 0xBC, 0x62, 0x5A, 0x46, 0x3D,
|
||||||
|
0x3E, 0x49, 0x49, 0x49, 0x00, 0x7E, 0x01, 0x01, 0x01, 0x7E, 0x2A, 0x2A,
|
||||||
|
0x2A, 0x2A, 0x2A, 0x44, 0x44, 0x5F, 0x44, 0x44, 0x40, 0x51, 0x4A, 0x44,
|
||||||
|
0x40, 0x40, 0x44, 0x4A, 0x51, 0x40, 0x00, 0x00, 0xFF, 0x01, 0x03, 0xE0,
|
||||||
|
0x80, 0xFF, 0x00, 0x00, 0x08, 0x08, 0x6B, 0x6B, 0x08, 0x36, 0x12, 0x36,
|
||||||
|
0x24, 0x36, 0x06, 0x0F, 0x09, 0x0F, 0x06, 0x00, 0x00, 0x18, 0x18, 0x00,
|
||||||
|
0x00, 0x00, 0x10, 0x10, 0x00, 0x30, 0x40, 0xFF, 0x01, 0x01, 0x00, 0x1F,
|
||||||
|
0x01, 0x01, 0x1E, 0x00, 0x19, 0x1D, 0x17, 0x12, 0x00, 0x3C, 0x3C, 0x3C,
|
||||||
|
0x3C, 0x00, 0x00, 0x00, 0x00, 0x00 // #255 NBSP
|
||||||
|
};
|
||||||
|
|
||||||
|
// allow clean compilation with [-Wunused-const-variable=] and [-Wall]
|
||||||
|
static inline void avoid_unused_const_variable_compiler_warning(void) {
|
||||||
|
(void)font;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // FONT5X7_H
|
|
@ -0,0 +1,66 @@
|
||||||
|
module.exports = function(grunt) {
|
||||||
|
// Project configuration.
|
||||||
|
grunt.initConfig({
|
||||||
|
pkg: grunt.file.readJSON('package.json'),
|
||||||
|
ts: {
|
||||||
|
default: {
|
||||||
|
src: ['ts/**/*.ts'],
|
||||||
|
outDir: 'tmp/',
|
||||||
|
options: {
|
||||||
|
module: 'none',
|
||||||
|
sourceMap: false,
|
||||||
|
target: 'es6',
|
||||||
|
rootDir: 'ts/'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
concat: {
|
||||||
|
js: {
|
||||||
|
src: ['tmp/**/*.js'],
|
||||||
|
dest: 'tmp/bootstrap.out'
|
||||||
|
},
|
||||||
|
dist: {
|
||||||
|
src: ['html/index.html'],
|
||||||
|
dest: 'webroot/index.html',
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
process: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
jsbootstrapts: {
|
||||||
|
files: ['ts/**/*.ts'],
|
||||||
|
tasks: ['ts', 'concat']
|
||||||
|
},
|
||||||
|
html: {
|
||||||
|
files: ['html/*'],
|
||||||
|
tasks: ['concat']
|
||||||
|
},
|
||||||
|
lessdefault: {
|
||||||
|
files: ['less/*.less'],
|
||||||
|
tasks: ['less:default', 'concat']
|
||||||
|
},
|
||||||
|
},
|
||||||
|
less: {
|
||||||
|
default: {
|
||||||
|
options: {
|
||||||
|
"strictImports": true,
|
||||||
|
"compress": true
|
||||||
|
},
|
||||||
|
files: {
|
||||||
|
"tmp/default.css": "less/main.less",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
grunt.loadNpmTasks('grunt-contrib-watch');
|
||||||
|
grunt.loadNpmTasks('grunt-contrib-less');
|
||||||
|
grunt.loadNpmTasks('grunt-contrib-concat');
|
||||||
|
grunt.loadNpmTasks("grunt-ts");
|
||||||
|
|
||||||
|
// Default task(s).
|
||||||
|
grunt.registerTask('default', ['less', 'ts', 'concat', 'watch']);
|
||||||
|
grunt.registerTask('release', ['less', 'ts', 'concat']);
|
||||||
|
|
||||||
|
};
|
|
@ -0,0 +1,205 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Cimdit Profile generator</title>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<style type="text/css">
|
||||||
|
<%= grunt.file.read('tmp/default.css') %>
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<form><div>
|
||||||
|
<textarea id="jsoncounter" class="lineCounter" wrap="off" readonly>1</textarea>
|
||||||
|
<textarea id="json" class="codeEditor" wrap="off">
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "Joystick",
|
||||||
|
"customimage": "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007FFFFFFC000000000000000000000001FFFFFFFF800000000000000000000003FFFFFFFFC00000000000000000000007FFFFFFFFE0000000000000000000000FE0000007F0000000000000000000001F80000001F8000000000000000000001F1A000000F8000000000000000000003E1E00000E7C000000000000000000003E1E00001F7C000000000000000000003C5F80001F3C000000000000000000003CFFC0000E3C000000000000000000003CFFC000E03C000000000000000000003C7F0001E07C000000000000000000003E1E0000F07C000000000000000000003E1E1FF8E078000000000000000000001F143FFC00F8000000000000000000001F807FFE01F8000000000000000000000FD1FFFF87F00000000000000000000007FFF81FFFE00000000000000000000003FFF00FFFC00000000000000000000001FFE007FF8000000000000000000000007F8001FE00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
"mappedbuttons": [
|
||||||
|
{
|
||||||
|
"source": 20,
|
||||||
|
"type": "JOYSTICK_BUTTON",
|
||||||
|
"target": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": 62,
|
||||||
|
"type": "SWITCH_PROFILE"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": 61,
|
||||||
|
"type": "MACRO_PRESS",
|
||||||
|
"macro": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": 60,
|
||||||
|
"type": "MACRO_PRESS",
|
||||||
|
"macro": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": 59,
|
||||||
|
"type": "MACRO_PRESS",
|
||||||
|
"macro": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": 59,
|
||||||
|
"type": "MACRO_RELEASE",
|
||||||
|
"macro": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": 58,
|
||||||
|
"type": "MACRO_PRESS",
|
||||||
|
"macro": 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": 58,
|
||||||
|
"type": "MACRO_RELEASE",
|
||||||
|
"macro": 5
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"mappedaxis": [
|
||||||
|
{
|
||||||
|
"source": 0,
|
||||||
|
"type": "JOYSTICK_AXIS",
|
||||||
|
"axis": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": 1,
|
||||||
|
"type": "JOYSTICK_AXIS",
|
||||||
|
"axis": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": 2,
|
||||||
|
"type": "JOYSTICK_AXIS",
|
||||||
|
"axis": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": 3,
|
||||||
|
"type": "JOYSTICK_AXIS",
|
||||||
|
"axis": 4
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"mappedrotary": [
|
||||||
|
{
|
||||||
|
"source": 0,
|
||||||
|
"type": "PREV_PROFILE"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": 1,
|
||||||
|
"type": "NEXT_PROFILE"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"macros": [
|
||||||
|
[
|
||||||
|
"MACRO_SPEED",
|
||||||
|
10,
|
||||||
|
"MACRO_TYPE",
|
||||||
|
"test"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"MACRO_SPEED",
|
||||||
|
10,
|
||||||
|
"MACRO_KEY_PRESS",
|
||||||
|
"KEY_LEFT_SHIFT",
|
||||||
|
"t",
|
||||||
|
"MACRO_KEY_RELEASE",
|
||||||
|
"t",
|
||||||
|
"KEY_LEFT_SHIFT",
|
||||||
|
"MACRO_TYPE",
|
||||||
|
"est"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"MACRO_SPEED",
|
||||||
|
10,
|
||||||
|
"MACRO_TYPE",
|
||||||
|
"te",
|
||||||
|
"MACRO_JOY_PRESS",
|
||||||
|
2,
|
||||||
|
"MACRO_DELAY",
|
||||||
|
2000,
|
||||||
|
"MACRO_JOY_RELEASE",
|
||||||
|
2,
|
||||||
|
"MACRO_TYPE",
|
||||||
|
"s"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"MACRO_TYPE",
|
||||||
|
"t"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"MACRO_MOUSE_PRESS",
|
||||||
|
2,
|
||||||
|
"MACRO_KEY_PRESS",
|
||||||
|
"KEY_LEFT_SHIFT",
|
||||||
|
"MACRO_MOUSE_REL_X_AXIS",
|
||||||
|
0,
|
||||||
|
5,
|
||||||
|
"MACRO_MOUSE_REL_Y_AXIS",
|
||||||
|
1,
|
||||||
|
5
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"MACRO_MOUSE_REL_X_AXIS",
|
||||||
|
-1,
|
||||||
|
"MACRO_MOUSE_REL_Y_AXIS",
|
||||||
|
-1,
|
||||||
|
"MACRO_KEY_RELEASE",
|
||||||
|
"KEY_LEFT_SHIFT",
|
||||||
|
"MACRO_MOUSE_RELEASE",
|
||||||
|
2
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Mouse",
|
||||||
|
"mappedbuttons": [
|
||||||
|
{
|
||||||
|
"source": 62,
|
||||||
|
"type": "SWITCH_PROFILE"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": 15,
|
||||||
|
"type": "MOUSE_REL_X_AXIS",
|
||||||
|
"value": 25
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": 23,
|
||||||
|
"type": "MOUSE_REL_Y_AXIS",
|
||||||
|
"value": -25
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"mappedaxis": [
|
||||||
|
{
|
||||||
|
"source": 0,
|
||||||
|
"type": "MOUSE_REL_X_AXIS",
|
||||||
|
"value": 50
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": 1,
|
||||||
|
"type": "MOUSE_REL_Y_AXIS",
|
||||||
|
"value": 50
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"mappedrotary": [
|
||||||
|
{
|
||||||
|
"source": 0,
|
||||||
|
"type": "PREV_PROFILE"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": 1,
|
||||||
|
"type": "NEXT_PROFILE"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
</textarea>
|
||||||
|
<p><button id="generatestring" class="button">Generate String</button></p>
|
||||||
|
<p id="error"></p>
|
||||||
|
<textarea id="string"></textarea>
|
||||||
|
<p><button id="generatejson" class="button">Generate Json</button></p>
|
||||||
|
</div></form>
|
||||||
|
<script type="text/javascript">
|
||||||
|
<%= grunt.file.read('tmp/bootstrap.out') %>
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,46 @@
|
||||||
|
textarea {
|
||||||
|
width:100%;
|
||||||
|
}
|
||||||
|
#string {
|
||||||
|
height:5vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.codeEditor, .lineCounter {
|
||||||
|
font-family: courier new, courier, monospace;
|
||||||
|
margin: 0;
|
||||||
|
padding: 10px 0;
|
||||||
|
height: 75vh;
|
||||||
|
border-radius: 0;
|
||||||
|
resize: none;
|
||||||
|
line-height: 1.2;
|
||||||
|
outline: none;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.codeEditor {
|
||||||
|
padding-left: calc(3.5rem + 5px);
|
||||||
|
width:100%;
|
||||||
|
background-color:#272822;
|
||||||
|
border-color:#272822;
|
||||||
|
color:#ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lineCounter {
|
||||||
|
display: flex;
|
||||||
|
border-color: transparent;
|
||||||
|
overflow-y: hidden;
|
||||||
|
text-align: right;
|
||||||
|
box-shadow: none;
|
||||||
|
color: #707070;
|
||||||
|
background-color: #d8d8d8;
|
||||||
|
position: absolute;
|
||||||
|
width: 3.5rem;
|
||||||
|
background-color:#3E3D32;
|
||||||
|
border-color:#3E3D32;
|
||||||
|
color:#928869;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lineCounter:focus-visible,
|
||||||
|
.codeEditor:focus-visible {
|
||||||
|
outline:none;
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
{
|
||||||
|
"name": "profilegenerator",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "create profile string via browser",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"author": "GrumpyDeveloper https://contentnation.net/grumpydevelop",
|
||||||
|
"license": "MIT",
|
||||||
|
"devDependencies": {
|
||||||
|
"grunt": "^1.4.1",
|
||||||
|
"grunt-contrib-concat": "^2.0.0",
|
||||||
|
"grunt-contrib-less": "^3.0.0",
|
||||||
|
"grunt-contrib-watch": "^1.1.0",
|
||||||
|
"grunt-ts": "^4.0.1"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,702 @@
|
||||||
|
type ProfileJson = {
|
||||||
|
name: string;
|
||||||
|
customimage?: string;
|
||||||
|
mappedbuttons?: EntityJson[];
|
||||||
|
mappedaxis?: EntityJson[];
|
||||||
|
mappedrotary?: EntityJson[];
|
||||||
|
macros?: Array<any[]>;
|
||||||
|
}
|
||||||
|
|
||||||
|
type EntityJson = {
|
||||||
|
source: number;
|
||||||
|
type: string;
|
||||||
|
target?: number;
|
||||||
|
axis?: number;
|
||||||
|
value?: number;
|
||||||
|
macro?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
type EntityProfileString = {
|
||||||
|
bytes: number;
|
||||||
|
count: number;
|
||||||
|
string: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main application class
|
||||||
|
*/
|
||||||
|
class ProfileGenerator {
|
||||||
|
private json : HTMLTextAreaElement;
|
||||||
|
private jsonCounter : HTMLTextAreaElement;
|
||||||
|
private generatejson : HTMLButtonElement;
|
||||||
|
private generatestring : HTMLButtonElement;
|
||||||
|
private error : HTMLParagraphElement;
|
||||||
|
private profile : HTMLTextAreaElement;
|
||||||
|
private lineCountCache: number;
|
||||||
|
|
||||||
|
private profileEnum : Array<string> = [
|
||||||
|
"MAPPING_NONE",
|
||||||
|
"JOYSTICK_BUTTON",
|
||||||
|
"JOYSTICK_AXIS",
|
||||||
|
"MOUSE_BUTTON",
|
||||||
|
"MOUSE_REL_X_AXIS",
|
||||||
|
"MOUSE_REL_Y_AXIS",
|
||||||
|
"MOUSE_REL_WHEEL",
|
||||||
|
"NEXT_PROFILE",
|
||||||
|
"PREV_PROFILE",
|
||||||
|
"SWITCH_PROFILE",
|
||||||
|
"MACRO_PRESS",
|
||||||
|
"MACRO_RELEASE"
|
||||||
|
];
|
||||||
|
private macroEnum: Array<string> = [
|
||||||
|
"MACRO_NULL",
|
||||||
|
"MACRO_SPEED",
|
||||||
|
"MACRO_DELAY",
|
||||||
|
"MACRO_KEY_PRESS",
|
||||||
|
"MACRO_KEY_RELEASE",
|
||||||
|
"MACRO_JOY_PRESS",
|
||||||
|
"MACRO_JOY_RELEASE",
|
||||||
|
"MACRO_MOUSE_PRESS",
|
||||||
|
"MACRO_MOUSE_RELEASE",
|
||||||
|
"MACRO_MOUSE_WHEEL",
|
||||||
|
"MACRO_TYPE",
|
||||||
|
"MACRO_MOUSE_REL_X",
|
||||||
|
"MACRO_MOUSE_REL_Y",
|
||||||
|
"MACRO_MOUSE_REL_X_AXIS",
|
||||||
|
"MACRO_MOUSE_REL_Y_AXIS"
|
||||||
|
];
|
||||||
|
|
||||||
|
private keyLookup = {
|
||||||
|
"KEY_RESERVED":0,
|
||||||
|
"KEY_ERROR_ROLLOVER":1,
|
||||||
|
"KEY_POST_FAIL":2,
|
||||||
|
"KEY_ERROR_UNDEFINED":3,
|
||||||
|
"KEY_A":4,
|
||||||
|
"KEY_B":5,
|
||||||
|
"KEY_C":6,
|
||||||
|
"KEY_D":7,
|
||||||
|
"KEY_E":8,
|
||||||
|
"KEY_F":9,
|
||||||
|
"KEY_G":10,
|
||||||
|
"KEY_H":11,
|
||||||
|
"KEY_I":12,
|
||||||
|
"KEY_J":13,
|
||||||
|
"KEY_K":14,
|
||||||
|
"KEY_L":15,
|
||||||
|
"KEY_M":16,
|
||||||
|
"KEY_N":17,
|
||||||
|
"KEY_O":18,
|
||||||
|
"KEY_P":19,
|
||||||
|
"KEY_Q":20,
|
||||||
|
"KEY_R":21,
|
||||||
|
"KEY_S":22,
|
||||||
|
"KEY_T":23,
|
||||||
|
"KEY_U":24,
|
||||||
|
"KEY_V":25,
|
||||||
|
"KEY_W":26,
|
||||||
|
"KEY_X":27,
|
||||||
|
"KEY_Y":28,
|
||||||
|
"KEY_Z":29,
|
||||||
|
"KEY_1":30,
|
||||||
|
"KEY_2":31,
|
||||||
|
"KEY_3":32,
|
||||||
|
"KEY_4":33,
|
||||||
|
"KEY_5":34,
|
||||||
|
"KEY_6":35,
|
||||||
|
"KEY_7":36,
|
||||||
|
"KEY_8":37,
|
||||||
|
"KEY_9":38,
|
||||||
|
"KEY_0":39,
|
||||||
|
"KEY_ENTER":40,
|
||||||
|
"KEY_RETURN":40,
|
||||||
|
"KEY_ESC":41,
|
||||||
|
"KEY_BACKSPACE":42,
|
||||||
|
"KEY_TAB":43,
|
||||||
|
"KEY_SPACE":44,
|
||||||
|
"KEY_MINUS":45,
|
||||||
|
"KEY_EQUAL":46,
|
||||||
|
"KEY_LEFT_BRACE":47,
|
||||||
|
"KEY_RIGHT_BRACE":48,
|
||||||
|
"KEY_BACKSLASH":49,
|
||||||
|
"KEY_NON_US_NUM":50,
|
||||||
|
"KEY_SEMICOLON":51,
|
||||||
|
"KEY_QUOTE":52,
|
||||||
|
"KEY_TILDE":53,
|
||||||
|
"KEY_COMMA":54,
|
||||||
|
"KEY_PERIOD":55,
|
||||||
|
"KEY_SLASH":56,
|
||||||
|
"KEY_CAPS_LOCK":0x39,
|
||||||
|
"KEY_F1":0x3A,
|
||||||
|
"KEY_F2":0x3B,
|
||||||
|
"KEY_F3":0x3C,
|
||||||
|
"KEY_F4":0x3D,
|
||||||
|
"KEY_F5":0x3E,
|
||||||
|
"KEY_F6":0x3F,
|
||||||
|
"KEY_F7":0x40,
|
||||||
|
"KEY_F8":0x41,
|
||||||
|
"KEY_F9":0x42,
|
||||||
|
"KEY_F10":0x43,
|
||||||
|
"KEY_F11":0x44,
|
||||||
|
"KEY_F12":0x45,
|
||||||
|
"KEY_PRINT":0x46,
|
||||||
|
"KEY_PRINTSCREEN":0x46,
|
||||||
|
"KEY_SCROLL_LOCK":0x47,
|
||||||
|
"KEY_PAUSE":0x48,
|
||||||
|
"KEY_INSERT":0x49,
|
||||||
|
"KEY_HOME":0x4A,
|
||||||
|
"KEY_PAGE_UP":0x4B,
|
||||||
|
"KEY_DELETE":0x4C,
|
||||||
|
"KEY_END":0x4D,
|
||||||
|
"KEY_PAGE_DOWN":0x4E,
|
||||||
|
"KEY_RIGHT_ARROW":0x4F,
|
||||||
|
"KEY_LEFT_ARROW":0x50,
|
||||||
|
"KEY_DOWN_ARROW":0x51,
|
||||||
|
"KEY_UP_ARROW":0x52,
|
||||||
|
"KEY_RIGHT":0x4F,
|
||||||
|
"KEY_LEFT":0x50,
|
||||||
|
"KEY_DOWN":0x51,
|
||||||
|
"KEY_UP":0x52,
|
||||||
|
"KEY_NUM_LOCK":0x53,
|
||||||
|
"KEYPAD_DIVIDE":0x54,
|
||||||
|
"KEYPAD_MULTIPLY":0x55,
|
||||||
|
"KEYPAD_SUBTRACT":0x56,
|
||||||
|
"KEYPAD_ADD":0x57,
|
||||||
|
"KEYPAD_ENTER":0x58,
|
||||||
|
"KEYPAD_1":0x59,
|
||||||
|
"KEYPAD_2":0x5A,
|
||||||
|
"KEYPAD_3":0x5B,
|
||||||
|
"KEYPAD_4":0x5C,
|
||||||
|
"KEYPAD_5":0x5D,
|
||||||
|
"KEYPAD_6":0x5E,
|
||||||
|
"KEYPAD_7":0x5F,
|
||||||
|
"KEYPAD_8":0x60,
|
||||||
|
"KEYPAD_9":0x61,
|
||||||
|
"KEYPAD_0":0x62,
|
||||||
|
"KEYPAD_DOT":0x63,
|
||||||
|
"KEY_NON_US":0x64,
|
||||||
|
"KEY_APPLICATION":0x65,
|
||||||
|
"KEY_MENU":0x65,
|
||||||
|
"KEY_POWER":0x66,
|
||||||
|
"KEY_PAD_EQUALS":0x67,
|
||||||
|
"KEY_F13":0x68,
|
||||||
|
"KEY_F14":0x69,
|
||||||
|
"KEY_F15":0x6A,
|
||||||
|
"KEY_F16":0x6B,
|
||||||
|
"KEY_F17":0x6C,
|
||||||
|
"KEY_F18":0x6D,
|
||||||
|
"KEY_F19":0x6E,
|
||||||
|
"KEY_F20":0x6F,
|
||||||
|
"KEY_F21":0x70,
|
||||||
|
"KEY_F22":0x71,
|
||||||
|
"KEY_F23":0x72,
|
||||||
|
"KEY_F24":0x73,
|
||||||
|
"KEY_EXECUTE":0x74,
|
||||||
|
"KEY_HELP":0x75,
|
||||||
|
"KEY_MENU2":0x76,
|
||||||
|
"KEY_SELECT":0x77,
|
||||||
|
"KEY_STOP":0x78,
|
||||||
|
"KEY_AGAIN":0x79,
|
||||||
|
"KEY_UNDO":0x7A,
|
||||||
|
"KEY_CUT":0x7B,
|
||||||
|
"KEY_COPY":0x7C,
|
||||||
|
"KEY_PASTE":0x7D,
|
||||||
|
"KEY_FIND":0x7E,
|
||||||
|
"KEY_MUTE":0x7F,
|
||||||
|
"KEY_VOLUME_MUTE":0x7F,
|
||||||
|
"KEY_VOLUME_UP":0x80,
|
||||||
|
"KEY_VOLUME_DOWN":0x81,
|
||||||
|
"KEY_LOCKING_CAPS_LOCK":0x82,
|
||||||
|
"KEY_LOCKING_NUM_LOCK":0x83,
|
||||||
|
"KEY_LOCKING_SCROLL_LOCK":0x84,
|
||||||
|
"KEYPAD_COMMA":0x85,
|
||||||
|
"KEYPAD_EQUAL_SIGN":0x86,
|
||||||
|
"KEY_INTERNATIONAL1":0x87,
|
||||||
|
"KEY_INTERNATIONAL2":0x88,
|
||||||
|
"KEY_INTERNATIONAL3":0x89,
|
||||||
|
"KEY_INTERNATIONAL4":0x8A,
|
||||||
|
"KEY_INTERNATIONAL5":0x8B,
|
||||||
|
"KEY_INTERNATIONAL6":0x8C,
|
||||||
|
"KEY_INTERNATIONAL7":0x8D,
|
||||||
|
"KEY_INTERNATIONAL8":0x8E,
|
||||||
|
"KEY_INTERNATIONAL9":0x8F,
|
||||||
|
"KEY_LANG1":0x90,
|
||||||
|
"KEY_LANG2":0x91,
|
||||||
|
"KEY_LANG3":0x92,
|
||||||
|
"KEY_LANG4":0x93,
|
||||||
|
"KEY_LANG5":0x94,
|
||||||
|
"KEY_LANG6":0x95,
|
||||||
|
"KEY_LANG7":0x96,
|
||||||
|
"KEY_LANG8":0x97,
|
||||||
|
"KEY_LANG9":0x98,
|
||||||
|
"KEY_ALTERNATE_ERASE":0x99,
|
||||||
|
"KEY_SYSREQ_ATTENTION":0x9A,
|
||||||
|
"KEY_CANCEL":0x9B,
|
||||||
|
"KEY_CLEAR":0x9C,
|
||||||
|
"KEY_PRIOR":0x9D,
|
||||||
|
"KEY_RETURN2":0x9E,
|
||||||
|
"KEY_SEPARATOR":0x9F,
|
||||||
|
"KEY_OUT":0xA0,
|
||||||
|
"KEY_OPER":0xA1,
|
||||||
|
"KEY_CLEAR_AGAIN":0xA2,
|
||||||
|
"KEY_CRSEL_PROPS":0xA3,
|
||||||
|
"KEY_EXSEL":0xA4,
|
||||||
|
"KEY_PAD_00":0xB0,
|
||||||
|
"KEY_PAD_000":0xB1,
|
||||||
|
"KEY_THOUSANDS_SEPARATOR":0xB2,
|
||||||
|
"KEY_DECIMAL_SEPARATOR":0xB3,
|
||||||
|
"KEY_CURRENCY_UNIT":0xB4,
|
||||||
|
"KEY_CURRENCY_SUB_UNIT":0xB5,
|
||||||
|
"KEYPAD_LEFT_BRACE":0xB6,
|
||||||
|
"KEYPAD_RIGHT_BRACE":0xB7,
|
||||||
|
"KEYPAD_LEFT_CURLY_BRACE":0xB8,
|
||||||
|
"KEYPAD_RIGHT_CURLY_BRACE":0xB9,
|
||||||
|
"KEYPAD_TAB":0xBA,
|
||||||
|
"KEYPAD_BACKSPACE":0xBB,
|
||||||
|
"KEYPAD_A":0xBC,
|
||||||
|
"KEYPAD_B":0xBD,
|
||||||
|
"KEYPAD_C":0xBE,
|
||||||
|
"KEYPAD_D":0xBF,
|
||||||
|
"KEYPAD_E":0xC0,
|
||||||
|
"KEYPAD_F":0xC1,
|
||||||
|
"KEYPAD_XOR":0xC2,
|
||||||
|
"KEYPAD_CARET":0xC3,
|
||||||
|
"KEYPAD_PERCENT":0xC4,
|
||||||
|
"KEYPAD_LESS_THAN":0xC5,
|
||||||
|
"KEYPAD_GREATER_THAN":0xC6,
|
||||||
|
"KEYPAD_AMPERSAND":0xC7,
|
||||||
|
"KEYPAD_DOUBLEAMPERSAND":0xC8,
|
||||||
|
"KEYPAD_PIPE":0xC9,
|
||||||
|
"KEYPAD_DOUBLEPIPE":0xCA,
|
||||||
|
"KEYPAD_COLON":0xCB,
|
||||||
|
"KEYPAD_POUND_SIGN":0xCC,
|
||||||
|
"KEYPAD_SPACE":0xCD,
|
||||||
|
"KEYPAD_AT_SIGN":0xCE,
|
||||||
|
"KEYPAD_EXCLAMATION_POINT":0xCF,
|
||||||
|
"KEYPAD_MEMORY_STORE":0xD0,
|
||||||
|
"KEYPAD_MEMORY_RECALL":0xD1,
|
||||||
|
"KEYPAD_MEMORY_CLEAR":0xD2,
|
||||||
|
"KEYPAD_MEMORY_ADD":0xD3,
|
||||||
|
"KEYPAD_MEMORY_SUBTRACT":0xD4,
|
||||||
|
"KEYPAD_MEMORY_MULTIPLY":0xD5,
|
||||||
|
"KEYPAD_MEMORY_DIVIDE":0xD6,
|
||||||
|
"KEYPAD_PLUS_MINUS":0xD7,
|
||||||
|
"KEYPAD_CLEAR":0xD8,
|
||||||
|
"KEYPAD_CLEAR_ENTRY":0xD9,
|
||||||
|
"KEYPAD_BINARY":0xDA,
|
||||||
|
"KEYPAD_OCTAL":0xDB,
|
||||||
|
"KEYPAD_DECIMAL":0xDC,
|
||||||
|
"KEYPAD_HEXADECIMAL":0xDD,
|
||||||
|
"KEY_LEFT_CTRL":0xE0,
|
||||||
|
"KEY_LEFT_SHIFT":0xE1,
|
||||||
|
"KEY_LEFT_ALT":0xE2,
|
||||||
|
"KEY_LEFT_GUI":0xE3,
|
||||||
|
"KEY_LEFT_WINDOWS":0xE3,
|
||||||
|
"KEY_RIGHT_CTRL":0xE4,
|
||||||
|
"KEY_RIGHT_SHIFT":0xE5,
|
||||||
|
"KEY_RIGHT_ALT":0xE6,
|
||||||
|
"KEY_RIGHT_GUI":0xE7,
|
||||||
|
"KEY_RIGHT_WINDOWS":0xE7,
|
||||||
|
};
|
||||||
|
constructor() {
|
||||||
|
this.json = <HTMLTextAreaElement>document.getElementById("json");
|
||||||
|
this.jsonCounter = <HTMLTextAreaElement>document.getElementById("jsoncounter");
|
||||||
|
this.profile = <HTMLTextAreaElement>document.getElementById("string");
|
||||||
|
this.generatejson = <HTMLButtonElement>document.getElementById("generatejson");
|
||||||
|
this.generatestring = <HTMLButtonElement>document.getElementById("generatestring");
|
||||||
|
this.error = <HTMLParagraphElement>document.getElementById("error");
|
||||||
|
this.generatestring.addEventListener("click", this.createProfile.bind(this));
|
||||||
|
this.generatejson.addEventListener("click", this.createJson.bind(this));
|
||||||
|
this.lineCountCache = 0;
|
||||||
|
this.json.addEventListener('scroll', () => {
|
||||||
|
this.jsonCounter.scrollTop = this.json.scrollTop;
|
||||||
|
this.jsonCounter.scrollLeft = this.json.scrollLeft;
|
||||||
|
});
|
||||||
|
this.json.addEventListener('input', () => {
|
||||||
|
this.line_counter();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.line_counter();
|
||||||
|
}
|
||||||
|
createProfile(event: Event) {
|
||||||
|
event.preventDefault();
|
||||||
|
var input = this.json.value;
|
||||||
|
var json = {};
|
||||||
|
try {
|
||||||
|
json = JSON.parse(input);
|
||||||
|
} catch (e) {
|
||||||
|
this.error.innerHTML = e.message;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
var profiles = [];
|
||||||
|
var lengths = [];
|
||||||
|
var profileCount = 0;
|
||||||
|
for (var pNum in json) {
|
||||||
|
var p = this.parseProfile(json[pNum])
|
||||||
|
profiles.push(p[1]);
|
||||||
|
lengths.push(p[0]);
|
||||||
|
++profileCount;
|
||||||
|
}
|
||||||
|
profiles.unshift(this.hexString(profileCount));
|
||||||
|
var length = 3;
|
||||||
|
for (var i = 0; i < lengths.length; ++i) {
|
||||||
|
length += lengths[i];
|
||||||
|
}
|
||||||
|
profiles.unshift(this.hexString(length >> 8) + this.hexString(length & 255));
|
||||||
|
this.profile.value = "cimdit:F" + profiles.join("");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
hexString(input: number) : string {
|
||||||
|
if (input < 0) {
|
||||||
|
input += 256;
|
||||||
|
}
|
||||||
|
var hex = input.toString(16);
|
||||||
|
if (hex.length < 2) {
|
||||||
|
hex = "0" + hex;
|
||||||
|
}
|
||||||
|
return hex;
|
||||||
|
}
|
||||||
|
|
||||||
|
parseProfile(json: Object) {
|
||||||
|
var out = "";
|
||||||
|
var length = 2;
|
||||||
|
// get name
|
||||||
|
var tmp = json["name"];
|
||||||
|
for (var pos in tmp) {
|
||||||
|
out += this.hexString(tmp.charCodeAt(pos));
|
||||||
|
}
|
||||||
|
out += "00";
|
||||||
|
length += out.length/2;
|
||||||
|
// custom image
|
||||||
|
if (json["customimage"]) {
|
||||||
|
out += "01";
|
||||||
|
out += json["customimage"];
|
||||||
|
length += 513;
|
||||||
|
} else {
|
||||||
|
out += "00";
|
||||||
|
++length;
|
||||||
|
}
|
||||||
|
// add buttons
|
||||||
|
if (json["mappedbuttons"] instanceof Array) {
|
||||||
|
var buttons = this.map(json["mappedbuttons"]);
|
||||||
|
out += this.hexString(buttons.count);
|
||||||
|
out += buttons.string;
|
||||||
|
length += buttons.bytes + 1;
|
||||||
|
} else {
|
||||||
|
out += "00";
|
||||||
|
++length;
|
||||||
|
}
|
||||||
|
// add axis
|
||||||
|
if (json["mappedaxis"] instanceof Array) {
|
||||||
|
var axis = this.map(json["mappedaxis"]);
|
||||||
|
out += this.hexString(axis.count);
|
||||||
|
out += axis.string;
|
||||||
|
length += axis.bytes + 1;
|
||||||
|
} else {
|
||||||
|
out += "00";
|
||||||
|
++length;
|
||||||
|
}
|
||||||
|
// add rotary
|
||||||
|
if (json["mappedrotary"] instanceof Array) {
|
||||||
|
var rotary = this.map(json["mappedrotary"]);
|
||||||
|
out += this.hexString(rotary.count);
|
||||||
|
out += rotary.string;
|
||||||
|
length += rotary.bytes + 1;
|
||||||
|
} else {
|
||||||
|
out += "00";
|
||||||
|
++length;
|
||||||
|
}
|
||||||
|
// add macro sequences
|
||||||
|
if (json["macros"] instanceof Array) {
|
||||||
|
var macro = this.createMacroString(json["macros"]);
|
||||||
|
out += this.hexString(macro.count);
|
||||||
|
out += macro.string;
|
||||||
|
length += macro.bytes + 1;
|
||||||
|
} else {
|
||||||
|
out += "00";
|
||||||
|
++length;
|
||||||
|
}
|
||||||
|
out = this.hexString(length >> 8) + this.hexString(length & 255) + out;
|
||||||
|
return [length, out];
|
||||||
|
}
|
||||||
|
|
||||||
|
map(entities: Array<EntityJson>) : EntityProfileString {
|
||||||
|
var out ="";
|
||||||
|
var bytes = 0
|
||||||
|
var count = 0;
|
||||||
|
for (var i = 0; i < entities.length; ++i) {
|
||||||
|
var entity = entities[i];
|
||||||
|
try {
|
||||||
|
var tmp = this.hexString(entity.source);
|
||||||
|
tmp += this.hexString(this.profileEnum.indexOf(entity.type));
|
||||||
|
if (entity.target !== undefined) {
|
||||||
|
tmp += this.hexString(entity.target);
|
||||||
|
} else if (entity.axis !== undefined) {
|
||||||
|
tmp += this.hexString(entity.axis);
|
||||||
|
} else if (entity.value !== undefined) {
|
||||||
|
tmp += this.hexString(entity.value);
|
||||||
|
} else if (entity.macro !== undefined) {
|
||||||
|
tmp += this.hexString(entity.macro);
|
||||||
|
} else {
|
||||||
|
tmp += "00";
|
||||||
|
}
|
||||||
|
out += tmp;
|
||||||
|
bytes += 3;
|
||||||
|
++count;
|
||||||
|
} catch(e) {
|
||||||
|
// print error
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {bytes: bytes, count: count, string: out};
|
||||||
|
}
|
||||||
|
|
||||||
|
createMacroString(macros: any[][]) : EntityProfileString {
|
||||||
|
var bytes = 0;
|
||||||
|
var out = "";
|
||||||
|
for (var i = 0; i < macros.length; ++i) {
|
||||||
|
var macro = macros[i];
|
||||||
|
var append = false;
|
||||||
|
for (var j = 0; j < macro.length; ++j) {
|
||||||
|
var token = macro[j];
|
||||||
|
if (token === "MACRO_SPEED" || token === "MACRO_MOUSE_WHEEL" || token.toString().match(/^MACRO_(JOY|MOUSE)_(PRESS|RELEASE)$/)) { // expect an unsigned integer variable
|
||||||
|
if (append) {
|
||||||
|
append = false;
|
||||||
|
out += "00";
|
||||||
|
++bytes;
|
||||||
|
}
|
||||||
|
out += this.hexString(this.macroEnum.indexOf(token)) + this.hexString(macro[++j]);
|
||||||
|
bytes += 2;
|
||||||
|
} else if (token === "MACRO_DELAY") { // expect an 16 bit integer variable
|
||||||
|
if (append) {
|
||||||
|
append = false;
|
||||||
|
out += "00";
|
||||||
|
++bytes;
|
||||||
|
}
|
||||||
|
var value = macro[++j];
|
||||||
|
out += this.hexString(this.macroEnum.indexOf(token)) + this.hexString((value >> 8)) + this.hexString(value & 255);
|
||||||
|
bytes += 3;
|
||||||
|
} else if (token.toString().match(/^MACRO_KEY_(PRESS|RELEASE)$/) || token === "MACRO_TYPE") { // followed by a list of keys/buttons
|
||||||
|
if (append) {
|
||||||
|
append = false;
|
||||||
|
out += "00";
|
||||||
|
++bytes;
|
||||||
|
}
|
||||||
|
out += this.hexString(this.macroEnum.indexOf(token));
|
||||||
|
append = true;
|
||||||
|
++bytes;
|
||||||
|
} else if (token === "MACRO_MOUSE_REL_X" || token === "MACRO_MOUSE_REL_Y") { // expect one integer values
|
||||||
|
if (append) {
|
||||||
|
append = false;
|
||||||
|
out += "00";
|
||||||
|
++bytes;
|
||||||
|
}
|
||||||
|
out += this.hexString(this.macroEnum.indexOf(token)) + this.hexString(macro[++j]);
|
||||||
|
bytes +=2;
|
||||||
|
} else if (token === "MACRO_MOUSE_REL_X_AXIS" || token === "MACRO_MOUSE_REL_Y_AXIS") { // expect one two integer values, joystick axis and speed if axis != -1
|
||||||
|
if (append) {
|
||||||
|
append = false;
|
||||||
|
out += "00";
|
||||||
|
++bytes;
|
||||||
|
}
|
||||||
|
if (macro[j + 1] == -1) {
|
||||||
|
out += this.hexString(this.macroEnum.indexOf(token)) + this.hexString(macro[++j]);
|
||||||
|
bytes +=2;
|
||||||
|
} else {
|
||||||
|
out += this.hexString(this.macroEnum.indexOf(token)) + this.hexString(macro[++j]) + this.hexString(macro[++j]);
|
||||||
|
bytes +=3;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (typeof(token) === "number") {
|
||||||
|
out += this.hexString(token);
|
||||||
|
++bytes;
|
||||||
|
} else {
|
||||||
|
if (token.startsWith("KEY_")) {
|
||||||
|
out += this.hexString(this.keyLookup[token]);
|
||||||
|
++bytes;
|
||||||
|
} else {
|
||||||
|
for (var k = 0; k < token.length; ++k) {
|
||||||
|
out += this.hexString(this.keyLookup["KEY_" + token[k].toUpperCase()]);
|
||||||
|
++bytes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (append) {
|
||||||
|
append = false;
|
||||||
|
out += "00";
|
||||||
|
++bytes;
|
||||||
|
}
|
||||||
|
out += "00";
|
||||||
|
++bytes;
|
||||||
|
}
|
||||||
|
return {bytes: bytes, count: macros.length, string: out};
|
||||||
|
}
|
||||||
|
|
||||||
|
fromHexS(input: string) : number {
|
||||||
|
var ret = parseInt(input, 16);
|
||||||
|
if (ret>127) ret -= 256;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
fromHexU(input: string) : number {
|
||||||
|
return parseInt(input, 16);
|
||||||
|
}
|
||||||
|
createJson(event: Event) {
|
||||||
|
event.preventDefault();
|
||||||
|
var string = this.profile.value;
|
||||||
|
// strip cimdit command
|
||||||
|
string = string.replace("cimdit:F","");
|
||||||
|
var tokens = string.match(/.{1,2}/g);
|
||||||
|
// parse token list
|
||||||
|
// ignore first 2 entries (length)
|
||||||
|
tokens.shift();
|
||||||
|
tokens.shift();
|
||||||
|
var json : ProfileJson[];
|
||||||
|
json = [];
|
||||||
|
var numProfile = this.fromHexU(tokens.shift());
|
||||||
|
for (var i = 0; i < numProfile; ++i) {
|
||||||
|
json.push(this.createProfileFromTokens(tokens));
|
||||||
|
}
|
||||||
|
this.json.value = JSON.stringify(json,null," ");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
createProfileFromTokens(tokens) : ProfileJson {
|
||||||
|
// var bytes = tokens.shift() * 255 + tokens.shift() - 2;
|
||||||
|
tokens.shift(); tokens.shift();
|
||||||
|
var name = "";
|
||||||
|
var char: number;
|
||||||
|
do {
|
||||||
|
char = this.fromHexU(tokens.shift());
|
||||||
|
if (char)
|
||||||
|
name += String.fromCharCode(char);
|
||||||
|
} while (char !== 0 && tokens.length > 0);
|
||||||
|
var ret:ProfileJson = {name: name};
|
||||||
|
var customImage = tokens.shift();
|
||||||
|
if (customImage != "00") {
|
||||||
|
var cu = "";
|
||||||
|
for (var i = 0; i < 512; ++i) {
|
||||||
|
cu += tokens.shift();
|
||||||
|
}
|
||||||
|
ret.customimage = cu;
|
||||||
|
}
|
||||||
|
var mappedButtons:EntityJson[] = [];
|
||||||
|
var numButtons = this.fromHexU(tokens.shift());
|
||||||
|
for (var i = 0; i < numButtons; ++i) {
|
||||||
|
mappedButtons.push(this.createEntityFromTokens(tokens));
|
||||||
|
}
|
||||||
|
ret.mappedbuttons = mappedButtons;
|
||||||
|
var mappedAxis:EntityJson[] = [];
|
||||||
|
var numAxis = this.fromHexU(tokens.shift());
|
||||||
|
for (var i = 0; i < numAxis; ++i) {
|
||||||
|
mappedAxis.push(this.createEntityFromTokens(tokens));
|
||||||
|
}
|
||||||
|
ret.mappedaxis = mappedAxis;
|
||||||
|
var mappedRotary:EntityJson[] = [];
|
||||||
|
var numRotary = this.fromHexU(tokens.shift());
|
||||||
|
for (var i = 0; i < numRotary; ++i) {
|
||||||
|
mappedRotary.push(this.createEntityFromTokens(tokens));
|
||||||
|
}
|
||||||
|
ret.mappedrotary = mappedRotary;
|
||||||
|
var macros : Array<any[]> = [];
|
||||||
|
var numMacro = this.fromHexU(tokens.shift());
|
||||||
|
for (var i = 0; i < numMacro; ++i) {
|
||||||
|
macros.push(this.createMacrosFromTokens(tokens));
|
||||||
|
}
|
||||||
|
ret.macros = macros;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
createEntityFromTokens(tokens) :EntityJson{
|
||||||
|
var entity: EntityJson = {source: this.fromHexU(tokens.shift()), type: this.profileEnum[this.fromHexU(tokens.shift())]};
|
||||||
|
if (entity.type === 'JOYSTICK_BUTTON' || entity.type === 'MOUSE_BUTTON') {
|
||||||
|
entity.target = this.fromHexU(tokens.shift());
|
||||||
|
} else if (entity.type === 'JOYSTICK_AXIS') {
|
||||||
|
entity.axis = this.fromHexU(tokens.shift());
|
||||||
|
} else if (entity.type === 'MOUSE_REL_X_AXIS' || entity.type === 'MOUSE_REL_Y_AXIS' || entity.type === 'MOUSE_REL_WHEEL') {
|
||||||
|
entity.value = this.fromHexS(tokens.shift());
|
||||||
|
} else if (entity.type === 'MACRO_PRESS' || entity.type === 'MACRO_RELEASE') {
|
||||||
|
entity.macro = this.fromHexU(tokens.shift());
|
||||||
|
} else {
|
||||||
|
tokens.shift();
|
||||||
|
}
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
getKey(input: number) : string {
|
||||||
|
return Object.keys(this.keyLookup).find(k=>this.keyLookup[k]===input);
|
||||||
|
}
|
||||||
|
|
||||||
|
createMacrosFromTokens(tokens: Array<string>) : Array<string | number> {
|
||||||
|
var macro : Array<string | number> = [];
|
||||||
|
do {
|
||||||
|
var token = this.macroEnum[this.fromHexU(tokens.shift())];
|
||||||
|
if (token !== "MACRO_NULL") {
|
||||||
|
macro.push(token);
|
||||||
|
}
|
||||||
|
switch(token) {
|
||||||
|
case "MACRO_NULL":
|
||||||
|
break;
|
||||||
|
case "MACRO_SPEED": // read in 1 extra numberic value 8 bit
|
||||||
|
case "MACRO_JOY_PRESS":
|
||||||
|
case "MACRO_JOY_RELEASE":
|
||||||
|
case "MACRO_MOUSE_PRESS":
|
||||||
|
case "MACRO_MOUSE_RELEASE":
|
||||||
|
case "MACRO_MOUSE_WHEEL":
|
||||||
|
macro.push(this.fromHexU(tokens.shift()));
|
||||||
|
break;
|
||||||
|
case "MACRO_DELAY": // read in 1 extra numberic value 16 bit
|
||||||
|
macro.push((this.fromHexU(tokens.shift())<<8) + this.fromHexU(tokens.shift()));
|
||||||
|
break;
|
||||||
|
case "MACRO_KEY_PRESS": // one or more keys
|
||||||
|
case "MACRO_KEY_RELEASE":
|
||||||
|
case "MACRO_TYPE":
|
||||||
|
var next: number;
|
||||||
|
var tmp = "";
|
||||||
|
do {
|
||||||
|
next = this.fromHexU(tokens.shift());
|
||||||
|
if (next != 0) {
|
||||||
|
var k = this.getKey(next);
|
||||||
|
if (k.match(/^KEY_\S$/)) {
|
||||||
|
tmp += k[4].toLowerCase();
|
||||||
|
} else {
|
||||||
|
if (tmp !== "")
|
||||||
|
macro.push(tmp);
|
||||||
|
tmp = "";
|
||||||
|
macro.push(k);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (next != 0);
|
||||||
|
if (tmp !== "") {
|
||||||
|
macro.push(tmp);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "MACRO_MOUSE_REL_X":
|
||||||
|
case "MACRO_MOUSE_REL_Y": // one bytes
|
||||||
|
var next :number = this.fromHexS(tokens.shift());
|
||||||
|
macro.push(next);
|
||||||
|
break;
|
||||||
|
case "MACRO_MOUSE_REL_X_AXIS":
|
||||||
|
case "MACRO_MOUSE_REL_Y_AXIS": // one or 2 bytes
|
||||||
|
var next :number = this.fromHexS(tokens.shift());
|
||||||
|
macro.push(next);
|
||||||
|
if (next != -1) {
|
||||||
|
macro.push(this.fromHexS(tokens.shift()));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while (token !== "MACRO_NULL" && tokens.length > 0);
|
||||||
|
return macro;
|
||||||
|
}
|
||||||
|
|
||||||
|
line_counter() {
|
||||||
|
var lineCount = this.json.value.split('\n').length;
|
||||||
|
var outarr = new Array();
|
||||||
|
if (this.lineCountCache != lineCount) {
|
||||||
|
for (var x = 0; x < lineCount; x++) {
|
||||||
|
outarr[x] = (x + 1);
|
||||||
|
}
|
||||||
|
this.jsonCounter.value = outarr.join('\n');
|
||||||
|
}
|
||||||
|
this.lineCountCache = lineCount;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
/// <reference path="ProfileGenerator.ts" />
|
||||||
|
/// <reference path="window.ts" />
|
||||||
|
/**
|
||||||
|
* Main entry function
|
||||||
|
*/
|
||||||
|
|
||||||
|
/// create our class as soon as the document is loaded
|
||||||
|
document.addEventListener("readystatechange", function(event: Event) {
|
||||||
|
if (!window.pg) {
|
||||||
|
window.pg = new ProfileGenerator();
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,11 @@
|
||||||
|
/// <reference path="ProfileGenerator.ts" />
|
||||||
|
|
||||||
|
/**
|
||||||
|
* extend Window to make our global instance available (for debugging purposes)
|
||||||
|
*/
|
||||||
|
interface Window {
|
||||||
|
/**
|
||||||
|
* our instance
|
||||||
|
*/
|
||||||
|
pg: ProfileGenerator;
|
||||||
|
}
|
|
@ -0,0 +1,887 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Cimdit Profile generator</title>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<style type="text/css">
|
||||||
|
textarea{width:100%}#string{height:5vh}.codeEditor,.lineCounter{font-family:courier new, courier, monospace;margin:0;padding:10px 0;height:75vh;border-radius:0;resize:none;line-height:1.2;outline:none;box-sizing:border-box}.codeEditor{padding-left:calc(3.5rem + 5px);width:100%;background-color:#272822;border-color:#272822;color:#ffffff}.lineCounter{display:flex;border-color:transparent;overflow-y:hidden;text-align:right;box-shadow:none;color:#707070;background-color:#d8d8d8;position:absolute;width:3.5rem;background-color:#3E3D32;border-color:#3E3D32;color:#928869}.lineCounter:focus-visible,.codeEditor:focus-visible{outline:none}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<form><div>
|
||||||
|
<textarea id="jsoncounter" class="lineCounter" wrap="off" readonly>1</textarea>
|
||||||
|
<textarea id="json" class="codeEditor" wrap="off">
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "Joystick",
|
||||||
|
"customimage": "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007FFFFFFC000000000000000000000001FFFFFFFF800000000000000000000003FFFFFFFFC00000000000000000000007FFFFFFFFE0000000000000000000000FE0000007F0000000000000000000001F80000001F8000000000000000000001F1A000000F8000000000000000000003E1E00000E7C000000000000000000003E1E00001F7C000000000000000000003C5F80001F3C000000000000000000003CFFC0000E3C000000000000000000003CFFC000E03C000000000000000000003C7F0001E07C000000000000000000003E1E0000F07C000000000000000000003E1E1FF8E078000000000000000000001F143FFC00F8000000000000000000001F807FFE01F8000000000000000000000FD1FFFF87F00000000000000000000007FFF81FFFE00000000000000000000003FFF00FFFC00000000000000000000001FFE007FF8000000000000000000000007F8001FE00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
"mappedbuttons": [
|
||||||
|
{
|
||||||
|
"source": 20,
|
||||||
|
"type": "JOYSTICK_BUTTON",
|
||||||
|
"target": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": 62,
|
||||||
|
"type": "SWITCH_PROFILE"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": 61,
|
||||||
|
"type": "MACRO_PRESS",
|
||||||
|
"macro": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": 60,
|
||||||
|
"type": "MACRO_PRESS",
|
||||||
|
"macro": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": 59,
|
||||||
|
"type": "MACRO_PRESS",
|
||||||
|
"macro": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": 59,
|
||||||
|
"type": "MACRO_RELEASE",
|
||||||
|
"macro": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": 58,
|
||||||
|
"type": "MACRO_PRESS",
|
||||||
|
"macro": 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": 58,
|
||||||
|
"type": "MACRO_RELEASE",
|
||||||
|
"macro": 5
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"mappedaxis": [
|
||||||
|
{
|
||||||
|
"source": 0,
|
||||||
|
"type": "JOYSTICK_AXIS",
|
||||||
|
"axis": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": 1,
|
||||||
|
"type": "JOYSTICK_AXIS",
|
||||||
|
"axis": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": 2,
|
||||||
|
"type": "JOYSTICK_AXIS",
|
||||||
|
"axis": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": 3,
|
||||||
|
"type": "JOYSTICK_AXIS",
|
||||||
|
"axis": 4
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"mappedrotary": [
|
||||||
|
{
|
||||||
|
"source": 0,
|
||||||
|
"type": "PREV_PROFILE"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": 1,
|
||||||
|
"type": "NEXT_PROFILE"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"macros": [
|
||||||
|
[
|
||||||
|
"MACRO_SPEED",
|
||||||
|
10,
|
||||||
|
"MACRO_TYPE",
|
||||||
|
"test"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"MACRO_SPEED",
|
||||||
|
10,
|
||||||
|
"MACRO_KEY_PRESS",
|
||||||
|
"KEY_LEFT_SHIFT",
|
||||||
|
"t",
|
||||||
|
"MACRO_KEY_RELEASE",
|
||||||
|
"t",
|
||||||
|
"KEY_LEFT_SHIFT",
|
||||||
|
"MACRO_TYPE",
|
||||||
|
"est"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"MACRO_SPEED",
|
||||||
|
10,
|
||||||
|
"MACRO_TYPE",
|
||||||
|
"te",
|
||||||
|
"MACRO_JOY_PRESS",
|
||||||
|
2,
|
||||||
|
"MACRO_DELAY",
|
||||||
|
2000,
|
||||||
|
"MACRO_JOY_RELEASE",
|
||||||
|
2,
|
||||||
|
"MACRO_TYPE",
|
||||||
|
"s"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"MACRO_TYPE",
|
||||||
|
"t"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"MACRO_MOUSE_PRESS",
|
||||||
|
2,
|
||||||
|
"MACRO_KEY_PRESS",
|
||||||
|
"KEY_LEFT_SHIFT",
|
||||||
|
"MACRO_MOUSE_REL_X_AXIS",
|
||||||
|
0,
|
||||||
|
5,
|
||||||
|
"MACRO_MOUSE_REL_Y_AXIS",
|
||||||
|
1,
|
||||||
|
5
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"MACRO_MOUSE_REL_X_AXIS",
|
||||||
|
-1,
|
||||||
|
"MACRO_MOUSE_REL_Y_AXIS",
|
||||||
|
-1,
|
||||||
|
"MACRO_KEY_RELEASE",
|
||||||
|
"KEY_LEFT_SHIFT",
|
||||||
|
"MACRO_MOUSE_RELEASE",
|
||||||
|
2
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Mouse",
|
||||||
|
"mappedbuttons": [
|
||||||
|
{
|
||||||
|
"source": 62,
|
||||||
|
"type": "SWITCH_PROFILE"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": 15,
|
||||||
|
"type": "MOUSE_REL_X_AXIS",
|
||||||
|
"value": 25
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": 23,
|
||||||
|
"type": "MOUSE_REL_Y_AXIS",
|
||||||
|
"value": -25
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"mappedaxis": [
|
||||||
|
{
|
||||||
|
"source": 0,
|
||||||
|
"type": "MOUSE_REL_X_AXIS",
|
||||||
|
"value": 50
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": 1,
|
||||||
|
"type": "MOUSE_REL_Y_AXIS",
|
||||||
|
"value": 50
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"mappedrotary": [
|
||||||
|
{
|
||||||
|
"source": 0,
|
||||||
|
"type": "PREV_PROFILE"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": 1,
|
||||||
|
"type": "NEXT_PROFILE"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
</textarea>
|
||||||
|
<p><button id="generatestring" class="button">Generate String</button></p>
|
||||||
|
<p id="error"></p>
|
||||||
|
<textarea id="string"></textarea>
|
||||||
|
<p><button id="generatejson" class="button">Generate Json</button></p>
|
||||||
|
</div></form>
|
||||||
|
<script type="text/javascript">
|
||||||
|
document.addEventListener("readystatechange", function (event) {
|
||||||
|
if (!window.pg) {
|
||||||
|
window.pg = new ProfileGenerator();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var ProfileGenerator = (function () {
|
||||||
|
function ProfileGenerator() {
|
||||||
|
var _this = this;
|
||||||
|
this.profileEnum = [
|
||||||
|
"MAPPING_NONE",
|
||||||
|
"JOYSTICK_BUTTON",
|
||||||
|
"JOYSTICK_AXIS",
|
||||||
|
"MOUSE_BUTTON",
|
||||||
|
"MOUSE_REL_X_AXIS",
|
||||||
|
"MOUSE_REL_Y_AXIS",
|
||||||
|
"MOUSE_REL_WHEEL",
|
||||||
|
"NEXT_PROFILE",
|
||||||
|
"PREV_PROFILE",
|
||||||
|
"SWITCH_PROFILE",
|
||||||
|
"MACRO_PRESS",
|
||||||
|
"MACRO_RELEASE"
|
||||||
|
];
|
||||||
|
this.macroEnum = [
|
||||||
|
"MACRO_NULL",
|
||||||
|
"MACRO_SPEED",
|
||||||
|
"MACRO_DELAY",
|
||||||
|
"MACRO_KEY_PRESS",
|
||||||
|
"MACRO_KEY_RELEASE",
|
||||||
|
"MACRO_JOY_PRESS",
|
||||||
|
"MACRO_JOY_RELEASE",
|
||||||
|
"MACRO_MOUSE_PRESS",
|
||||||
|
"MACRO_MOUSE_RELEASE",
|
||||||
|
"MACRO_MOUSE_WHEEL",
|
||||||
|
"MACRO_TYPE",
|
||||||
|
"MACRO_MOUSE_REL_X",
|
||||||
|
"MACRO_MOUSE_REL_Y",
|
||||||
|
"MACRO_MOUSE_REL_X_AXIS",
|
||||||
|
"MACRO_MOUSE_REL_Y_AXIS"
|
||||||
|
];
|
||||||
|
this.keyLookup = {
|
||||||
|
"KEY_RESERVED": 0,
|
||||||
|
"KEY_ERROR_ROLLOVER": 1,
|
||||||
|
"KEY_POST_FAIL": 2,
|
||||||
|
"KEY_ERROR_UNDEFINED": 3,
|
||||||
|
"KEY_A": 4,
|
||||||
|
"KEY_B": 5,
|
||||||
|
"KEY_C": 6,
|
||||||
|
"KEY_D": 7,
|
||||||
|
"KEY_E": 8,
|
||||||
|
"KEY_F": 9,
|
||||||
|
"KEY_G": 10,
|
||||||
|
"KEY_H": 11,
|
||||||
|
"KEY_I": 12,
|
||||||
|
"KEY_J": 13,
|
||||||
|
"KEY_K": 14,
|
||||||
|
"KEY_L": 15,
|
||||||
|
"KEY_M": 16,
|
||||||
|
"KEY_N": 17,
|
||||||
|
"KEY_O": 18,
|
||||||
|
"KEY_P": 19,
|
||||||
|
"KEY_Q": 20,
|
||||||
|
"KEY_R": 21,
|
||||||
|
"KEY_S": 22,
|
||||||
|
"KEY_T": 23,
|
||||||
|
"KEY_U": 24,
|
||||||
|
"KEY_V": 25,
|
||||||
|
"KEY_W": 26,
|
||||||
|
"KEY_X": 27,
|
||||||
|
"KEY_Y": 28,
|
||||||
|
"KEY_Z": 29,
|
||||||
|
"KEY_1": 30,
|
||||||
|
"KEY_2": 31,
|
||||||
|
"KEY_3": 32,
|
||||||
|
"KEY_4": 33,
|
||||||
|
"KEY_5": 34,
|
||||||
|
"KEY_6": 35,
|
||||||
|
"KEY_7": 36,
|
||||||
|
"KEY_8": 37,
|
||||||
|
"KEY_9": 38,
|
||||||
|
"KEY_0": 39,
|
||||||
|
"KEY_ENTER": 40,
|
||||||
|
"KEY_RETURN": 40,
|
||||||
|
"KEY_ESC": 41,
|
||||||
|
"KEY_BACKSPACE": 42,
|
||||||
|
"KEY_TAB": 43,
|
||||||
|
"KEY_SPACE": 44,
|
||||||
|
"KEY_MINUS": 45,
|
||||||
|
"KEY_EQUAL": 46,
|
||||||
|
"KEY_LEFT_BRACE": 47,
|
||||||
|
"KEY_RIGHT_BRACE": 48,
|
||||||
|
"KEY_BACKSLASH": 49,
|
||||||
|
"KEY_NON_US_NUM": 50,
|
||||||
|
"KEY_SEMICOLON": 51,
|
||||||
|
"KEY_QUOTE": 52,
|
||||||
|
"KEY_TILDE": 53,
|
||||||
|
"KEY_COMMA": 54,
|
||||||
|
"KEY_PERIOD": 55,
|
||||||
|
"KEY_SLASH": 56,
|
||||||
|
"KEY_CAPS_LOCK": 0x39,
|
||||||
|
"KEY_F1": 0x3A,
|
||||||
|
"KEY_F2": 0x3B,
|
||||||
|
"KEY_F3": 0x3C,
|
||||||
|
"KEY_F4": 0x3D,
|
||||||
|
"KEY_F5": 0x3E,
|
||||||
|
"KEY_F6": 0x3F,
|
||||||
|
"KEY_F7": 0x40,
|
||||||
|
"KEY_F8": 0x41,
|
||||||
|
"KEY_F9": 0x42,
|
||||||
|
"KEY_F10": 0x43,
|
||||||
|
"KEY_F11": 0x44,
|
||||||
|
"KEY_F12": 0x45,
|
||||||
|
"KEY_PRINT": 0x46,
|
||||||
|
"KEY_PRINTSCREEN": 0x46,
|
||||||
|
"KEY_SCROLL_LOCK": 0x47,
|
||||||
|
"KEY_PAUSE": 0x48,
|
||||||
|
"KEY_INSERT": 0x49,
|
||||||
|
"KEY_HOME": 0x4A,
|
||||||
|
"KEY_PAGE_UP": 0x4B,
|
||||||
|
"KEY_DELETE": 0x4C,
|
||||||
|
"KEY_END": 0x4D,
|
||||||
|
"KEY_PAGE_DOWN": 0x4E,
|
||||||
|
"KEY_RIGHT_ARROW": 0x4F,
|
||||||
|
"KEY_LEFT_ARROW": 0x50,
|
||||||
|
"KEY_DOWN_ARROW": 0x51,
|
||||||
|
"KEY_UP_ARROW": 0x52,
|
||||||
|
"KEY_RIGHT": 0x4F,
|
||||||
|
"KEY_LEFT": 0x50,
|
||||||
|
"KEY_DOWN": 0x51,
|
||||||
|
"KEY_UP": 0x52,
|
||||||
|
"KEY_NUM_LOCK": 0x53,
|
||||||
|
"KEYPAD_DIVIDE": 0x54,
|
||||||
|
"KEYPAD_MULTIPLY": 0x55,
|
||||||
|
"KEYPAD_SUBTRACT": 0x56,
|
||||||
|
"KEYPAD_ADD": 0x57,
|
||||||
|
"KEYPAD_ENTER": 0x58,
|
||||||
|
"KEYPAD_1": 0x59,
|
||||||
|
"KEYPAD_2": 0x5A,
|
||||||
|
"KEYPAD_3": 0x5B,
|
||||||
|
"KEYPAD_4": 0x5C,
|
||||||
|
"KEYPAD_5": 0x5D,
|
||||||
|
"KEYPAD_6": 0x5E,
|
||||||
|
"KEYPAD_7": 0x5F,
|
||||||
|
"KEYPAD_8": 0x60,
|
||||||
|
"KEYPAD_9": 0x61,
|
||||||
|
"KEYPAD_0": 0x62,
|
||||||
|
"KEYPAD_DOT": 0x63,
|
||||||
|
"KEY_NON_US": 0x64,
|
||||||
|
"KEY_APPLICATION": 0x65,
|
||||||
|
"KEY_MENU": 0x65,
|
||||||
|
"KEY_POWER": 0x66,
|
||||||
|
"KEY_PAD_EQUALS": 0x67,
|
||||||
|
"KEY_F13": 0x68,
|
||||||
|
"KEY_F14": 0x69,
|
||||||
|
"KEY_F15": 0x6A,
|
||||||
|
"KEY_F16": 0x6B,
|
||||||
|
"KEY_F17": 0x6C,
|
||||||
|
"KEY_F18": 0x6D,
|
||||||
|
"KEY_F19": 0x6E,
|
||||||
|
"KEY_F20": 0x6F,
|
||||||
|
"KEY_F21": 0x70,
|
||||||
|
"KEY_F22": 0x71,
|
||||||
|
"KEY_F23": 0x72,
|
||||||
|
"KEY_F24": 0x73,
|
||||||
|
"KEY_EXECUTE": 0x74,
|
||||||
|
"KEY_HELP": 0x75,
|
||||||
|
"KEY_MENU2": 0x76,
|
||||||
|
"KEY_SELECT": 0x77,
|
||||||
|
"KEY_STOP": 0x78,
|
||||||
|
"KEY_AGAIN": 0x79,
|
||||||
|
"KEY_UNDO": 0x7A,
|
||||||
|
"KEY_CUT": 0x7B,
|
||||||
|
"KEY_COPY": 0x7C,
|
||||||
|
"KEY_PASTE": 0x7D,
|
||||||
|
"KEY_FIND": 0x7E,
|
||||||
|
"KEY_MUTE": 0x7F,
|
||||||
|
"KEY_VOLUME_MUTE": 0x7F,
|
||||||
|
"KEY_VOLUME_UP": 0x80,
|
||||||
|
"KEY_VOLUME_DOWN": 0x81,
|
||||||
|
"KEY_LOCKING_CAPS_LOCK": 0x82,
|
||||||
|
"KEY_LOCKING_NUM_LOCK": 0x83,
|
||||||
|
"KEY_LOCKING_SCROLL_LOCK": 0x84,
|
||||||
|
"KEYPAD_COMMA": 0x85,
|
||||||
|
"KEYPAD_EQUAL_SIGN": 0x86,
|
||||||
|
"KEY_INTERNATIONAL1": 0x87,
|
||||||
|
"KEY_INTERNATIONAL2": 0x88,
|
||||||
|
"KEY_INTERNATIONAL3": 0x89,
|
||||||
|
"KEY_INTERNATIONAL4": 0x8A,
|
||||||
|
"KEY_INTERNATIONAL5": 0x8B,
|
||||||
|
"KEY_INTERNATIONAL6": 0x8C,
|
||||||
|
"KEY_INTERNATIONAL7": 0x8D,
|
||||||
|
"KEY_INTERNATIONAL8": 0x8E,
|
||||||
|
"KEY_INTERNATIONAL9": 0x8F,
|
||||||
|
"KEY_LANG1": 0x90,
|
||||||
|
"KEY_LANG2": 0x91,
|
||||||
|
"KEY_LANG3": 0x92,
|
||||||
|
"KEY_LANG4": 0x93,
|
||||||
|
"KEY_LANG5": 0x94,
|
||||||
|
"KEY_LANG6": 0x95,
|
||||||
|
"KEY_LANG7": 0x96,
|
||||||
|
"KEY_LANG8": 0x97,
|
||||||
|
"KEY_LANG9": 0x98,
|
||||||
|
"KEY_ALTERNATE_ERASE": 0x99,
|
||||||
|
"KEY_SYSREQ_ATTENTION": 0x9A,
|
||||||
|
"KEY_CANCEL": 0x9B,
|
||||||
|
"KEY_CLEAR": 0x9C,
|
||||||
|
"KEY_PRIOR": 0x9D,
|
||||||
|
"KEY_RETURN2": 0x9E,
|
||||||
|
"KEY_SEPARATOR": 0x9F,
|
||||||
|
"KEY_OUT": 0xA0,
|
||||||
|
"KEY_OPER": 0xA1,
|
||||||
|
"KEY_CLEAR_AGAIN": 0xA2,
|
||||||
|
"KEY_CRSEL_PROPS": 0xA3,
|
||||||
|
"KEY_EXSEL": 0xA4,
|
||||||
|
"KEY_PAD_00": 0xB0,
|
||||||
|
"KEY_PAD_000": 0xB1,
|
||||||
|
"KEY_THOUSANDS_SEPARATOR": 0xB2,
|
||||||
|
"KEY_DECIMAL_SEPARATOR": 0xB3,
|
||||||
|
"KEY_CURRENCY_UNIT": 0xB4,
|
||||||
|
"KEY_CURRENCY_SUB_UNIT": 0xB5,
|
||||||
|
"KEYPAD_LEFT_BRACE": 0xB6,
|
||||||
|
"KEYPAD_RIGHT_BRACE": 0xB7,
|
||||||
|
"KEYPAD_LEFT_CURLY_BRACE": 0xB8,
|
||||||
|
"KEYPAD_RIGHT_CURLY_BRACE": 0xB9,
|
||||||
|
"KEYPAD_TAB": 0xBA,
|
||||||
|
"KEYPAD_BACKSPACE": 0xBB,
|
||||||
|
"KEYPAD_A": 0xBC,
|
||||||
|
"KEYPAD_B": 0xBD,
|
||||||
|
"KEYPAD_C": 0xBE,
|
||||||
|
"KEYPAD_D": 0xBF,
|
||||||
|
"KEYPAD_E": 0xC0,
|
||||||
|
"KEYPAD_F": 0xC1,
|
||||||
|
"KEYPAD_XOR": 0xC2,
|
||||||
|
"KEYPAD_CARET": 0xC3,
|
||||||
|
"KEYPAD_PERCENT": 0xC4,
|
||||||
|
"KEYPAD_LESS_THAN": 0xC5,
|
||||||
|
"KEYPAD_GREATER_THAN": 0xC6,
|
||||||
|
"KEYPAD_AMPERSAND": 0xC7,
|
||||||
|
"KEYPAD_DOUBLEAMPERSAND": 0xC8,
|
||||||
|
"KEYPAD_PIPE": 0xC9,
|
||||||
|
"KEYPAD_DOUBLEPIPE": 0xCA,
|
||||||
|
"KEYPAD_COLON": 0xCB,
|
||||||
|
"KEYPAD_POUND_SIGN": 0xCC,
|
||||||
|
"KEYPAD_SPACE": 0xCD,
|
||||||
|
"KEYPAD_AT_SIGN": 0xCE,
|
||||||
|
"KEYPAD_EXCLAMATION_POINT": 0xCF,
|
||||||
|
"KEYPAD_MEMORY_STORE": 0xD0,
|
||||||
|
"KEYPAD_MEMORY_RECALL": 0xD1,
|
||||||
|
"KEYPAD_MEMORY_CLEAR": 0xD2,
|
||||||
|
"KEYPAD_MEMORY_ADD": 0xD3,
|
||||||
|
"KEYPAD_MEMORY_SUBTRACT": 0xD4,
|
||||||
|
"KEYPAD_MEMORY_MULTIPLY": 0xD5,
|
||||||
|
"KEYPAD_MEMORY_DIVIDE": 0xD6,
|
||||||
|
"KEYPAD_PLUS_MINUS": 0xD7,
|
||||||
|
"KEYPAD_CLEAR": 0xD8,
|
||||||
|
"KEYPAD_CLEAR_ENTRY": 0xD9,
|
||||||
|
"KEYPAD_BINARY": 0xDA,
|
||||||
|
"KEYPAD_OCTAL": 0xDB,
|
||||||
|
"KEYPAD_DECIMAL": 0xDC,
|
||||||
|
"KEYPAD_HEXADECIMAL": 0xDD,
|
||||||
|
"KEY_LEFT_CTRL": 0xE0,
|
||||||
|
"KEY_LEFT_SHIFT": 0xE1,
|
||||||
|
"KEY_LEFT_ALT": 0xE2,
|
||||||
|
"KEY_LEFT_GUI": 0xE3,
|
||||||
|
"KEY_LEFT_WINDOWS": 0xE3,
|
||||||
|
"KEY_RIGHT_CTRL": 0xE4,
|
||||||
|
"KEY_RIGHT_SHIFT": 0xE5,
|
||||||
|
"KEY_RIGHT_ALT": 0xE6,
|
||||||
|
"KEY_RIGHT_GUI": 0xE7,
|
||||||
|
"KEY_RIGHT_WINDOWS": 0xE7,
|
||||||
|
};
|
||||||
|
this.json = document.getElementById("json");
|
||||||
|
this.jsonCounter = document.getElementById("jsoncounter");
|
||||||
|
this.profile = document.getElementById("string");
|
||||||
|
this.generatejson = document.getElementById("generatejson");
|
||||||
|
this.generatestring = document.getElementById("generatestring");
|
||||||
|
this.error = document.getElementById("error");
|
||||||
|
this.generatestring.addEventListener("click", this.createProfile.bind(this));
|
||||||
|
this.generatejson.addEventListener("click", this.createJson.bind(this));
|
||||||
|
this.lineCountCache = 0;
|
||||||
|
this.json.addEventListener('scroll', function () {
|
||||||
|
_this.jsonCounter.scrollTop = _this.json.scrollTop;
|
||||||
|
_this.jsonCounter.scrollLeft = _this.json.scrollLeft;
|
||||||
|
});
|
||||||
|
this.json.addEventListener('input', function () {
|
||||||
|
_this.line_counter();
|
||||||
|
});
|
||||||
|
this.line_counter();
|
||||||
|
}
|
||||||
|
ProfileGenerator.prototype.createProfile = function (event) {
|
||||||
|
event.preventDefault();
|
||||||
|
var input = this.json.value;
|
||||||
|
var json = {};
|
||||||
|
try {
|
||||||
|
json = JSON.parse(input);
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
this.error.innerHTML = e.message;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
var profiles = [];
|
||||||
|
var lengths = [];
|
||||||
|
var profileCount = 0;
|
||||||
|
for (var pNum in json) {
|
||||||
|
var p = this.parseProfile(json[pNum]);
|
||||||
|
profiles.push(p[1]);
|
||||||
|
lengths.push(p[0]);
|
||||||
|
++profileCount;
|
||||||
|
}
|
||||||
|
profiles.unshift(this.hexString(profileCount));
|
||||||
|
var length = 3;
|
||||||
|
for (var i = 0; i < lengths.length; ++i) {
|
||||||
|
length += lengths[i];
|
||||||
|
}
|
||||||
|
profiles.unshift(this.hexString(length >> 8) + this.hexString(length & 255));
|
||||||
|
this.profile.value = "cimdit:F" + profiles.join("");
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
ProfileGenerator.prototype.hexString = function (input) {
|
||||||
|
if (input < 0) {
|
||||||
|
input += 256;
|
||||||
|
}
|
||||||
|
var hex = input.toString(16);
|
||||||
|
if (hex.length < 2) {
|
||||||
|
hex = "0" + hex;
|
||||||
|
}
|
||||||
|
return hex;
|
||||||
|
};
|
||||||
|
ProfileGenerator.prototype.parseProfile = function (json) {
|
||||||
|
var out = "";
|
||||||
|
var length = 2;
|
||||||
|
var tmp = json["name"];
|
||||||
|
for (var pos in tmp) {
|
||||||
|
out += this.hexString(tmp.charCodeAt(pos));
|
||||||
|
}
|
||||||
|
out += "00";
|
||||||
|
length += out.length / 2;
|
||||||
|
if (json["customimage"]) {
|
||||||
|
out += "01";
|
||||||
|
out += json["customimage"];
|
||||||
|
length += 513;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
out += "00";
|
||||||
|
++length;
|
||||||
|
}
|
||||||
|
if (json["mappedbuttons"] instanceof Array) {
|
||||||
|
var buttons = this.map(json["mappedbuttons"]);
|
||||||
|
out += this.hexString(buttons.count);
|
||||||
|
out += buttons.string;
|
||||||
|
length += buttons.bytes + 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
out += "00";
|
||||||
|
++length;
|
||||||
|
}
|
||||||
|
if (json["mappedaxis"] instanceof Array) {
|
||||||
|
var axis = this.map(json["mappedaxis"]);
|
||||||
|
out += this.hexString(axis.count);
|
||||||
|
out += axis.string;
|
||||||
|
length += axis.bytes + 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
out += "00";
|
||||||
|
++length;
|
||||||
|
}
|
||||||
|
if (json["mappedrotary"] instanceof Array) {
|
||||||
|
var rotary = this.map(json["mappedrotary"]);
|
||||||
|
out += this.hexString(rotary.count);
|
||||||
|
out += rotary.string;
|
||||||
|
length += rotary.bytes + 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
out += "00";
|
||||||
|
++length;
|
||||||
|
}
|
||||||
|
if (json["macros"] instanceof Array) {
|
||||||
|
var macro = this.createMacroString(json["macros"]);
|
||||||
|
out += this.hexString(macro.count);
|
||||||
|
out += macro.string;
|
||||||
|
length += macro.bytes + 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
out += "00";
|
||||||
|
++length;
|
||||||
|
}
|
||||||
|
out = this.hexString(length >> 8) + this.hexString(length & 255) + out;
|
||||||
|
return [length, out];
|
||||||
|
};
|
||||||
|
ProfileGenerator.prototype.map = function (entities) {
|
||||||
|
var out = "";
|
||||||
|
var bytes = 0;
|
||||||
|
var count = 0;
|
||||||
|
for (var i = 0; i < entities.length; ++i) {
|
||||||
|
var entity = entities[i];
|
||||||
|
try {
|
||||||
|
var tmp = this.hexString(entity.source);
|
||||||
|
tmp += this.hexString(this.profileEnum.indexOf(entity.type));
|
||||||
|
if (entity.target !== undefined) {
|
||||||
|
tmp += this.hexString(entity.target);
|
||||||
|
}
|
||||||
|
else if (entity.axis !== undefined) {
|
||||||
|
tmp += this.hexString(entity.axis);
|
||||||
|
}
|
||||||
|
else if (entity.value !== undefined) {
|
||||||
|
tmp += this.hexString(entity.value);
|
||||||
|
}
|
||||||
|
else if (entity.macro !== undefined) {
|
||||||
|
tmp += this.hexString(entity.macro);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
tmp += "00";
|
||||||
|
}
|
||||||
|
out += tmp;
|
||||||
|
bytes += 3;
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return { bytes: bytes, count: count, string: out };
|
||||||
|
};
|
||||||
|
ProfileGenerator.prototype.createMacroString = function (macros) {
|
||||||
|
var bytes = 0;
|
||||||
|
var out = "";
|
||||||
|
for (var i = 0; i < macros.length; ++i) {
|
||||||
|
var macro = macros[i];
|
||||||
|
var append = false;
|
||||||
|
for (var j = 0; j < macro.length; ++j) {
|
||||||
|
var token = macro[j];
|
||||||
|
if (token === "MACRO_SPEED" || token === "MACRO_MOUSE_WHEEL" || token.toString().match(/^MACRO_(JOY|MOUSE)_(PRESS|RELEASE)$/)) {
|
||||||
|
if (append) {
|
||||||
|
append = false;
|
||||||
|
out += "00";
|
||||||
|
++bytes;
|
||||||
|
}
|
||||||
|
out += this.hexString(this.macroEnum.indexOf(token)) + this.hexString(macro[++j]);
|
||||||
|
bytes += 2;
|
||||||
|
}
|
||||||
|
else if (token === "MACRO_DELAY") {
|
||||||
|
if (append) {
|
||||||
|
append = false;
|
||||||
|
out += "00";
|
||||||
|
++bytes;
|
||||||
|
}
|
||||||
|
var value = macro[++j];
|
||||||
|
out += this.hexString(this.macroEnum.indexOf(token)) + this.hexString((value >> 8)) + this.hexString(value & 255);
|
||||||
|
bytes += 3;
|
||||||
|
}
|
||||||
|
else if (token.toString().match(/^MACRO_KEY_(PRESS|RELEASE)$/) || token === "MACRO_TYPE") {
|
||||||
|
if (append) {
|
||||||
|
append = false;
|
||||||
|
out += "00";
|
||||||
|
++bytes;
|
||||||
|
}
|
||||||
|
out += this.hexString(this.macroEnum.indexOf(token));
|
||||||
|
append = true;
|
||||||
|
++bytes;
|
||||||
|
}
|
||||||
|
else if (token === "MACRO_MOUSE_REL_X" || token === "MACRO_MOUSE_REL_Y") {
|
||||||
|
if (append) {
|
||||||
|
append = false;
|
||||||
|
out += "00";
|
||||||
|
++bytes;
|
||||||
|
}
|
||||||
|
out += this.hexString(this.macroEnum.indexOf(token)) + this.hexString(macro[++j]);
|
||||||
|
bytes += 2;
|
||||||
|
}
|
||||||
|
else if (token === "MACRO_MOUSE_REL_X_AXIS" || token === "MACRO_MOUSE_REL_Y_AXIS") {
|
||||||
|
if (append) {
|
||||||
|
append = false;
|
||||||
|
out += "00";
|
||||||
|
++bytes;
|
||||||
|
}
|
||||||
|
if (macro[j + 1] == -1) {
|
||||||
|
out += this.hexString(this.macroEnum.indexOf(token)) + this.hexString(macro[++j]);
|
||||||
|
bytes += 2;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
out += this.hexString(this.macroEnum.indexOf(token)) + this.hexString(macro[++j]) + this.hexString(macro[++j]);
|
||||||
|
bytes += 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (typeof (token) === "number") {
|
||||||
|
out += this.hexString(token);
|
||||||
|
++bytes;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (token.startsWith("KEY_")) {
|
||||||
|
out += this.hexString(this.keyLookup[token]);
|
||||||
|
++bytes;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (var k = 0; k < token.length; ++k) {
|
||||||
|
out += this.hexString(this.keyLookup["KEY_" + token[k].toUpperCase()]);
|
||||||
|
++bytes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (append) {
|
||||||
|
append = false;
|
||||||
|
out += "00";
|
||||||
|
++bytes;
|
||||||
|
}
|
||||||
|
out += "00";
|
||||||
|
++bytes;
|
||||||
|
}
|
||||||
|
return { bytes: bytes, count: macros.length, string: out };
|
||||||
|
};
|
||||||
|
ProfileGenerator.prototype.fromHexS = function (input) {
|
||||||
|
var ret = parseInt(input, 16);
|
||||||
|
if (ret > 127)
|
||||||
|
ret -= 256;
|
||||||
|
return ret;
|
||||||
|
};
|
||||||
|
ProfileGenerator.prototype.fromHexU = function (input) {
|
||||||
|
return parseInt(input, 16);
|
||||||
|
};
|
||||||
|
ProfileGenerator.prototype.createJson = function (event) {
|
||||||
|
event.preventDefault();
|
||||||
|
var string = this.profile.value;
|
||||||
|
string = string.replace("cimdit:F", "");
|
||||||
|
var tokens = string.match(/.{1,2}/g);
|
||||||
|
tokens.shift();
|
||||||
|
tokens.shift();
|
||||||
|
var json;
|
||||||
|
json = [];
|
||||||
|
var numProfile = this.fromHexU(tokens.shift());
|
||||||
|
for (var i = 0; i < numProfile; ++i) {
|
||||||
|
json.push(this.createProfileFromTokens(tokens));
|
||||||
|
}
|
||||||
|
this.json.value = JSON.stringify(json, null, " ");
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
ProfileGenerator.prototype.createProfileFromTokens = function (tokens) {
|
||||||
|
tokens.shift();
|
||||||
|
tokens.shift();
|
||||||
|
var name = "";
|
||||||
|
var char;
|
||||||
|
do {
|
||||||
|
char = this.fromHexU(tokens.shift());
|
||||||
|
if (char)
|
||||||
|
name += String.fromCharCode(char);
|
||||||
|
} while (char !== 0 && tokens.length > 0);
|
||||||
|
var ret = { name: name };
|
||||||
|
var customImage = tokens.shift();
|
||||||
|
if (customImage != "00") {
|
||||||
|
var cu = "";
|
||||||
|
for (var i = 0; i < 512; ++i) {
|
||||||
|
cu += tokens.shift();
|
||||||
|
}
|
||||||
|
ret.customimage = cu;
|
||||||
|
}
|
||||||
|
var mappedButtons = [];
|
||||||
|
var numButtons = this.fromHexU(tokens.shift());
|
||||||
|
for (var i = 0; i < numButtons; ++i) {
|
||||||
|
mappedButtons.push(this.createEntityFromTokens(tokens));
|
||||||
|
}
|
||||||
|
ret.mappedbuttons = mappedButtons;
|
||||||
|
var mappedAxis = [];
|
||||||
|
var numAxis = this.fromHexU(tokens.shift());
|
||||||
|
for (var i = 0; i < numAxis; ++i) {
|
||||||
|
mappedAxis.push(this.createEntityFromTokens(tokens));
|
||||||
|
}
|
||||||
|
ret.mappedaxis = mappedAxis;
|
||||||
|
var mappedRotary = [];
|
||||||
|
var numRotary = this.fromHexU(tokens.shift());
|
||||||
|
for (var i = 0; i < numRotary; ++i) {
|
||||||
|
mappedRotary.push(this.createEntityFromTokens(tokens));
|
||||||
|
}
|
||||||
|
ret.mappedrotary = mappedRotary;
|
||||||
|
var macros = [];
|
||||||
|
var numMacro = this.fromHexU(tokens.shift());
|
||||||
|
for (var i = 0; i < numMacro; ++i) {
|
||||||
|
macros.push(this.createMacrosFromTokens(tokens));
|
||||||
|
}
|
||||||
|
ret.macros = macros;
|
||||||
|
return ret;
|
||||||
|
};
|
||||||
|
ProfileGenerator.prototype.createEntityFromTokens = function (tokens) {
|
||||||
|
var entity = { source: this.fromHexU(tokens.shift()), type: this.profileEnum[this.fromHexU(tokens.shift())] };
|
||||||
|
if (entity.type === 'JOYSTICK_BUTTON' || entity.type === 'MOUSE_BUTTON') {
|
||||||
|
entity.target = this.fromHexU(tokens.shift());
|
||||||
|
}
|
||||||
|
else if (entity.type === 'JOYSTICK_AXIS') {
|
||||||
|
entity.axis = this.fromHexU(tokens.shift());
|
||||||
|
}
|
||||||
|
else if (entity.type === 'MOUSE_REL_X_AXIS' || entity.type === 'MOUSE_REL_Y_AXIS' || entity.type === 'MOUSE_REL_WHEEL') {
|
||||||
|
entity.value = this.fromHexS(tokens.shift());
|
||||||
|
}
|
||||||
|
else if (entity.type === 'MACRO_PRESS' || entity.type === 'MACRO_RELEASE') {
|
||||||
|
entity.macro = this.fromHexU(tokens.shift());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
tokens.shift();
|
||||||
|
}
|
||||||
|
return entity;
|
||||||
|
};
|
||||||
|
ProfileGenerator.prototype.getKey = function (input) {
|
||||||
|
var _this = this;
|
||||||
|
return Object.keys(this.keyLookup).find(function (k) { return _this.keyLookup[k] === input; });
|
||||||
|
};
|
||||||
|
ProfileGenerator.prototype.createMacrosFromTokens = function (tokens) {
|
||||||
|
var macro = [];
|
||||||
|
do {
|
||||||
|
var token = this.macroEnum[this.fromHexU(tokens.shift())];
|
||||||
|
if (token !== "MACRO_NULL") {
|
||||||
|
macro.push(token);
|
||||||
|
}
|
||||||
|
switch (token) {
|
||||||
|
case "MACRO_NULL":
|
||||||
|
break;
|
||||||
|
case "MACRO_SPEED":
|
||||||
|
case "MACRO_JOY_PRESS":
|
||||||
|
case "MACRO_JOY_RELEASE":
|
||||||
|
case "MACRO_MOUSE_PRESS":
|
||||||
|
case "MACRO_MOUSE_RELEASE":
|
||||||
|
case "MACRO_MOUSE_WHEEL":
|
||||||
|
macro.push(this.fromHexU(tokens.shift()));
|
||||||
|
break;
|
||||||
|
case "MACRO_DELAY":
|
||||||
|
macro.push((this.fromHexU(tokens.shift()) << 8) + this.fromHexU(tokens.shift()));
|
||||||
|
break;
|
||||||
|
case "MACRO_KEY_PRESS":
|
||||||
|
case "MACRO_KEY_RELEASE":
|
||||||
|
case "MACRO_TYPE":
|
||||||
|
var next;
|
||||||
|
var tmp = "";
|
||||||
|
do {
|
||||||
|
next = this.fromHexU(tokens.shift());
|
||||||
|
if (next != 0) {
|
||||||
|
var k = this.getKey(next);
|
||||||
|
if (k.match(/^KEY_\S$/)) {
|
||||||
|
tmp += k[4].toLowerCase();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (tmp !== "")
|
||||||
|
macro.push(tmp);
|
||||||
|
tmp = "";
|
||||||
|
macro.push(k);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (next != 0);
|
||||||
|
if (tmp !== "") {
|
||||||
|
macro.push(tmp);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "MACRO_MOUSE_REL_X":
|
||||||
|
case "MACRO_MOUSE_REL_Y":
|
||||||
|
var next = this.fromHexS(tokens.shift());
|
||||||
|
macro.push(next);
|
||||||
|
break;
|
||||||
|
case "MACRO_MOUSE_REL_X_AXIS":
|
||||||
|
case "MACRO_MOUSE_REL_Y_AXIS":
|
||||||
|
var next = this.fromHexS(tokens.shift());
|
||||||
|
macro.push(next);
|
||||||
|
if (next != -1) {
|
||||||
|
macro.push(this.fromHexS(tokens.shift()));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while (token !== "MACRO_NULL" && tokens.length > 0);
|
||||||
|
return macro;
|
||||||
|
};
|
||||||
|
ProfileGenerator.prototype.line_counter = function () {
|
||||||
|
var lineCount = this.json.value.split('\n').length;
|
||||||
|
var outarr = new Array();
|
||||||
|
if (this.lineCountCache != lineCount) {
|
||||||
|
for (var x = 0; x < lineCount; x++) {
|
||||||
|
outarr[x] = (x + 1);
|
||||||
|
}
|
||||||
|
this.jsonCounter.value = outarr.join('\n');
|
||||||
|
}
|
||||||
|
this.lineCountCache = lineCount;
|
||||||
|
};
|
||||||
|
return ProfileGenerator;
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in New Issue