diff --git a/.gitignore b/.gitignore
index 0babea1..8580a2b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,3 +8,8 @@
/electronics/fp-info-cache
/spec.d
/html
+profilegenerator/.tscache
+profilegenerator/node_modules
+profilegenerator/tmp
+profilegenerator/package-lock.json
+profilegenerator/ts/.baseDir.ts
diff --git a/profilegenerator/Gruntfile.js b/profilegenerator/Gruntfile.js
new file mode 100644
index 0000000..f5528ff
--- /dev/null
+++ b/profilegenerator/Gruntfile.js
@@ -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']);
+
+};
diff --git a/profilegenerator/html/index.html b/profilegenerator/html/index.html
new file mode 100644
index 0000000..6f799ab
--- /dev/null
+++ b/profilegenerator/html/index.html
@@ -0,0 +1,205 @@
+
+
+
+Cimdit Profile generator
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/profilegenerator/less/main.less b/profilegenerator/less/main.less
new file mode 100644
index 0000000..06990e4
--- /dev/null
+++ b/profilegenerator/less/main.less
@@ -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;
+ }
diff --git a/profilegenerator/package.json b/profilegenerator/package.json
new file mode 100644
index 0000000..471c403
--- /dev/null
+++ b/profilegenerator/package.json
@@ -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"
+ }
+}
diff --git a/profilegenerator/ts/ProfileGenerator.ts b/profilegenerator/ts/ProfileGenerator.ts
new file mode 100644
index 0000000..6938019
--- /dev/null
+++ b/profilegenerator/ts/ProfileGenerator.ts
@@ -0,0 +1,702 @@
+type ProfileJson = {
+ name: string;
+ customimage?: string;
+ mappedbuttons?: EntityJson[];
+ mappedaxis?: EntityJson[];
+ mappedrotary?: EntityJson[];
+ macros?: Array;
+}
+
+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 = [
+ "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 = [
+ "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 = 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', () => {
+ 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) : 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 = [];
+ 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) : Array {
+ var macro : Array = [];
+ 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;
+ }
+}
\ No newline at end of file
diff --git a/profilegenerator/ts/init.ts b/profilegenerator/ts/init.ts
new file mode 100644
index 0000000..d21054e
--- /dev/null
+++ b/profilegenerator/ts/init.ts
@@ -0,0 +1,12 @@
+///
+///
+/**
+ * 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();
+ }
+});
diff --git a/profilegenerator/ts/window.ts b/profilegenerator/ts/window.ts
new file mode 100644
index 0000000..e95def3
--- /dev/null
+++ b/profilegenerator/ts/window.ts
@@ -0,0 +1,11 @@
+///
+
+/**
+ * extend Window to make our global instance available (for debugging purposes)
+ */
+interface Window {
+ /**
+ * our instance
+ */
+ pg: ProfileGenerator;
+}
diff --git a/profilegenerator/webroot/index.html b/profilegenerator/webroot/index.html
new file mode 100644
index 0000000..45a0aab
--- /dev/null
+++ b/profilegenerator/webroot/index.html
@@ -0,0 +1,887 @@
+
+
+
+Cimdit Profile generator
+
+
+
+
+
+
+
+
+
\ No newline at end of file