Browse Source

Made a userspace that allows you to use your keyboard as an order of operations based calculator (#2864)

* Made DZ60 layout with calculator

* Cleaned up and commented, preparing to fix bug with negative in front of open parenthesis as first character

* Fixed bug where negative sign infront of parenthesis as first character was parsed incorrectly

* Made a better solution for the bug from the previous commit

* Modularized and added a userfile so that this code can be used on various keyboards, found in doogle999

* Removed commented code from keymap

* Made the layer that is used for calculations a define so that it can be changed per keyboard

* Made the readme

* Made the readme in the correct place

* Revert "Made the readme in the correct place"

This reverts commit 7f8b59ed9e59c77401a48be3a7ac1e8fd8e84e32.

* Manually synced with qmk upstream

* Stopped repeat, made keys print character that they are defined as rather than what the keyboard wants them to do

* Added support for numpad, might make all keycodes custom so that there is no need to change doogle999.c if you want to change the keycode that is associated with a function, also made numpad automatically activating an option

* Fixed some bugs with backspacing, updated the readme

* Fixed some bugs with numlock turning on at the wrong times when a shift key was down

* Made the return to layer work automatically instead of just forcing it to layer 0

* fixes and style changes, 20% decreased binary size

* Fixed some bugs with double printing and compilation errors on my side

* Fixed bug with exceeding the buffer size

* Removed changes that added const-ness

* Made changes so that backspace does not repeat to remove backspace bugs, still some bugs with recalculating without having typed anything

* Fixed obo error with calc main loop

* Made includes more accurate in keymap for dz60

* Moved flags to user makefile
Ajax 7 years ago
parent
commit
b0a021c07a

+ 74 - 0
keyboards/dz60/keymaps/doogle999/keymap.c

@@ -0,0 +1,74 @@
+#include QMK_KEYBOARD_H
+
+#include "doogle999.h"
+
+#define ______ KC_NO
+
+const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
+
+/* Base layer
+ * ,-----------------------------------------------------------------------------------------.
+ * | ESC |  1  |  2  |  3  |  4  |  5  |  6  |  7  |  8  |  9  |  0  |  -  |  =  | Backspace |
+ * |-----------------------------------------------------------------------------------------+
+ * |  Tab   |  Q  |  W  |  E  |  R  |  T  |  Y  |  U  |  I  |  O  |  P  |  [  |  ]  |    \   |
+ * |-----------------------------------------------------------------------------------------+
+ * |   Fn    |  A  |  S  |  D  |  F  |  G  |  H  |  J  |  K  |  L  |  ;  |  '  |    Enter    |
+ * |-----------------------------------------------------------------------------------------+
+ * |   Shift   |  Z  |  X  |  C  |  V  |  B  |  N  |  M  |  ,  |  .  |   Shift   |  U  | Del |
+ * |-----------------------------------------------------------------------------------------+
+ * | Ctrl |  Cmd  |  Alt  |               Space               |  /  |  Fn  |  L  |  D  |  R  |
+ * `-----------------------------------------------------------------------------------------'
+ */
+
+	LAYOUT_directional(
+      KC_ESC, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, ______, KC_BSPC,
+      KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_BSLS,
+      MO(1), KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_ENT,
+      KC_LSFT, ______, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_RSFT, KC_UP, KC_DELETE,
+      KC_LCTL, KC_LGUI, KC_LALT, KC_SPC, KC_SPC, KC_SPC, KC_SLSH, MO(1), KC_LEFT, KC_DOWN, KC_RIGHT
+      ),
+
+/* Fn layer
+ * ,-----------------------------------------------------------------------------------------.
+ * |  ~  | F1  | F2  | F3  | F4  | F5  | F6  | f7  | F8  | F9  | F10 | F11 | F12 | Backspace |
+ * |-----------------------------------------------------------------------------------------+
+ * | Reset  | NP1 | NP2 | NP3 | NP4 | NP5 | NP6 | NP7 | NP8 | NP9 | NP0 |VolD |VolU |  Mute  |
+ * |-----------------------------------------------------------------------------------------+
+ * |         |     |     |     |     |     |     |     |     | BlD | BlI | BlT |    Menu     |
+ * |-----------------------------------------------------------------------------------------+
+ * |   Shift   | Cyc+| Cyc-| Val+| Val-| Hue+| Hue-| Sat+| Sat-| Tog |   Shift   | Pup | Ins |
+ * |-----------------------------------------------------------------------------------------+
+ * | Ctrl |  Cmd  |  Alt  |               Space               |HwCal|      |Home | Pdn | End |
+ * `-----------------------------------------------------------------------------------------'
+ */
+
+	LAYOUT_directional(
+      KC_GRV, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, ______, KC_CALC,
+      RESET, KC_KP_1, KC_KP_2, KC_KP_3, KC_KP_4, KC_KP_5, KC_KP_6, KC_KP_7, KC_KP_8, KC_KP_9, KC_KP_0, KC_VOLD, KC_VOLU, KC_MUTE,
+      ______, ______, ______, ______, ______, ______, ______, ______, ______, BL_DEC, BL_INC, BL_TOGG, KC_APP,
+      KC_LSFT, ______, RGB_MOD, RGB_RMOD, RGB_VAI, RGB_VAD, RGB_HUI, RGB_HUD, RGB_SAI, RGB_SAD, RGB_TOG, KC_RSFT, KC_PGUP, KC_INSERT,
+      KC_LCTL, KC_LGUI, KC_LALT, KC_SPC, KC_SPC, KC_SPC, TO(2), ______, KC_HOME, KC_PGDOWN, KC_END
+      ),
+
+  /* Hardware calculator layer
+  * ,-----------------------------------------------------------------------------------------.
+  * |EndCa|  1  |  2  |  3  |  4  |  5  |  6  |  7  |  8  |  9  |  0  |  -  |  =  | Backspace |
+  * |-----------------------------------------------------------------------------------------+
+  * |        |  Q  |     |  E  |     |  T  |     |     |     |     |  P  |     |     |        |
+  * |-----------------------------------------------------------------------------------------+
+  * |         |     |  S  |     |     |     |     |     |     |  L  |     |     |     Calc    |
+  * |-----------------------------------------------------------------------------------------+
+  * |   Shift   |     |     |     |  C  |     |     |     |     |  .  |   Shift   |     |     |
+  * |-----------------------------------------------------------------------------------------+
+  * |      |        |      |                                   |  /  |      |     |     |     |
+  * `-----------------------------------------------------------------------------------------'
+  */
+
+	LAYOUT_directional(
+    ENDCALC, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, ______, KC_BSPC,
+    ______, KC_Q,  ______, KC_E, ______, KC_T, ______, ______, ______, ______, KC_P,  ______, ______, ______,
+    ______, ______, KC_S, ______, ______, ______, ______, ______, ______, KC_L, ______, ______, CALC,
+    KC_LSFT, ______, ______, ______, KC_C, ______, ______, ______, ______, ______, KC_DOT, KC_RSFT, ______, ______,
+    ______, ______, ______, ______, ______, ______, KC_SLSH, ______, ______, ______, ______
+  ),
+};

+ 0 - 1
tmk_core/rules.mk

@@ -103,7 +103,6 @@ endif
 CFLAGS += -Wa,-adhlns=$(@:%.o=%.lst)
 CFLAGS += $(CSTANDARD)
 
-
 #---------------- Compiler Options C++ ----------------
 #  -g*:          generate debugging information
 #  -O*:          optimization level

+ 460 - 0
users/doogle999/doogle999.c

@@ -0,0 +1,460 @@
+#include "doogle999.h"
+
+static unsigned char inputLocation = 0; // Current index in text input
+
+static double calc(const char input[CALC_BUFFER_SIZE +1]) // Finds value of input char array, relatively small and fast I think
+{
+  char inputToken[CALC_BUFFER_SIZE + 1]; // Input buffer, used when a single token (generally a number) takes up more
+  unsigned char inputTokenLocation = 0, inputLocation = 0; // Keep track of indices
+
+  struct Token tokens[CALC_BUFFER_SIZE + 1]; // Input, converted to tokens, one extra large to accomodate for possible negative sign then open parenthesis as first character
+  unsigned char tokenCount = 0; // Keep track of index
+
+  bool dashAsMinus = false; // Kind of a hacky solution to determining whether to treat a dash as a minus sign or a negative sign
+
+  while(inputLocation < CALC_BUFFER_SIZE + 1)
+  {
+    char digit = input[inputLocation];
+
+    if(inputLocation == 0 && input[inputLocation] == CALC_CHAR_SUB && input[inputLocation + 1] == CALC_CHAR_BEG)
+    {
+      tokens[tokenCount].raw.num = 0;
+      tokens[tokenCount].isNum = true;
+
+      tokenCount++;
+      dashAsMinus = true;
+    }
+
+    if ((digit >= '0' && digit <= '9') || /* valid digit */
+        (inputTokenLocation != 0 && input[inputLocation] == CALC_CHAR_DEC) || /* valid floating point */
+        (!dashAsMinus && inputTokenLocation == 0 && input[inputLocation] == CALC_CHAR_SUB)) /* - is negative sign */
+    {
+      inputToken[inputTokenLocation] = input[inputLocation];
+      inputTokenLocation++;
+      inputLocation++;
+      continue;
+    }
+
+    if(inputTokenLocation != 0)
+    {
+      // sscanf(inputToken, "%lf", &tokens[tokenCount].raw.num); // I would like to use sscanf here, but the small version of stdio.h on the chip doesn't allow sscanf or its sister functions to be used to process floats
+      tokens[tokenCount].raw.num = atof(inputToken);
+      tokens[tokenCount].isNum = true;
+      for(unsigned char i = 0; i < inputTokenLocation + 1; i++)
+      {
+        inputToken[i] = '\0';
+      }
+      inputTokenLocation = 0;
+      tokenCount++;
+      dashAsMinus = true;
+      continue;
+    }
+
+    /* inputTokenLocation == 0 */
+    tokens[tokenCount].isNum = false;
+    tokens[tokenCount].raw.op.c = input[inputLocation];
+    tokens[tokenCount].raw.op.priority = 0;
+    tokens[tokenCount].raw.op.ltr = true;
+    dashAsMinus = false;
+
+    switch(input[inputLocation])
+    {
+      case CALC_CHAR_BEG:
+        break;
+      case CALC_CHAR_END:
+        dashAsMinus = true;
+        break;
+      case CALC_CHAR_ADD:
+        tokens[tokenCount].raw.op.priority = CALC_PRIO_ADD;
+        break;
+      case CALC_CHAR_SUB:
+        tokens[tokenCount].raw.op.priority = CALC_PRIO_SUB;
+        break;
+      case CALC_CHAR_MUL:
+        tokens[tokenCount].raw.op.priority = CALC_PRIO_MUL;
+        break;
+      case CALC_CHAR_DIV:
+        tokens[tokenCount].raw.op.priority = CALC_PRIO_DIV;
+        break;
+      case CALC_CHAR_EXP:
+        tokens[tokenCount].raw.op.priority = CALC_PRIO_EXP;
+        tokens[tokenCount].raw.op.ltr = false;
+        break;
+      case CALC_CHAR_SIN:
+      case CALC_CHAR_COS:
+      case CALC_CHAR_TAN:
+      case CALC_CHAR_ASN:
+      case CALC_CHAR_ACS:
+      case CALC_CHAR_ATN:
+      case CALC_CHAR_LGE:
+      case CALC_CHAR_LOG:
+      case CALC_CHAR_SQT:
+        break;
+      case CALC_CHAR_EUL:
+        tokens[tokenCount].isNum = true;
+        tokens[tokenCount].raw.num = CALC_VALU_EUL;
+        dashAsMinus = true;
+        break;
+      case CALC_CHAR_PI:
+        tokens[tokenCount].isNum = true;
+        tokens[tokenCount].raw.num = CALC_VALU_PI;
+        dashAsMinus = true;
+        break;
+      case '\0':
+        tokenCount--;
+        inputLocation = CALC_BUFFER_SIZE;
+        break;
+      default:
+        tokenCount--;
+        break;
+    }
+    tokenCount++;
+    inputLocation++;
+  }
+
+  struct Token output[CALC_BUFFER_SIZE + 1]; // Final output tokens before evaluation
+  struct Token opstack[CALC_BUFFER_SIZE + 1]; // Stack of operators
+  unsigned char outputLocation = 0, opstackLocation = 0; // Keep track of indices
+
+  unsigned char numBrackets = 0; // The number of parenthesis
+
+  for(unsigned char i = 0; i < tokenCount; i++)
+  {
+    if(tokens[i].isNum)
+    {
+      output[outputLocation] = tokens[i];
+      outputLocation++;
+    }
+    else if(tokens[i].raw.op.c == CALC_CHAR_BEG)
+    {
+      opstack[opstackLocation] = tokens[i];
+      opstackLocation++;
+    }
+    else if(tokens[i].raw.op.c == CALC_CHAR_END)
+    {
+      while(opstack[opstackLocation - 1].raw.op.c != CALC_CHAR_BEG)
+      {
+        output[outputLocation] = opstack[opstackLocation - 1];
+        outputLocation++;
+        opstackLocation--;
+      }
+      opstackLocation--;
+
+      numBrackets += 2;
+    }
+    else if(tokens[i].raw.op.priority == 0)
+    {
+      opstack[opstackLocation] = tokens[i];
+      opstackLocation++;
+    }
+    else
+    {
+      while(opstackLocation != 0
+        && (opstack[opstackLocation - 1].raw.op.priority == 0
+          || tokens[i].raw.op.priority < opstack[opstackLocation - 1].raw.op.priority
+          || (tokens[i].raw.op.priority == opstack[opstackLocation - 1].raw.op.priority && opstack[opstackLocation - 1].raw.op.ltr))
+        && opstack[opstackLocation - 1].raw.op.c != CALC_CHAR_BEG)
+      {
+        output[outputLocation] = opstack[opstackLocation - 1];
+        outputLocation++;
+        opstackLocation--;
+      }
+      opstack[opstackLocation] = tokens[i];
+      opstackLocation++;
+    }
+  }
+
+  tokenCount -= numBrackets;
+
+  for(signed char i = opstackLocation - 1; i >= 0; i--)
+  {
+    output[outputLocation] = opstack[i];
+    outputLocation++;
+    opstackLocation--;
+  }
+
+  double answer[CALC_BUFFER_SIZE];
+  unsigned char answerLocation = 0;
+
+  for(unsigned char i = 0; i < tokenCount; i++)
+  {
+    if(output[i].isNum)
+    {
+      answer[answerLocation] = output[i].raw.num;
+      answerLocation++;
+      continue;
+    }
+
+    if(output[i].raw.op.priority == 0)
+    {
+      if (answerLocation < 1) { /* not handled here -- ERROR? */ } else
+      if(answerLocation >= 1)
+      {
+        double (*op)(double);
+        switch(output[i].raw.op.c)
+        {
+        case CALC_CHAR_SIN:
+          op = sin;
+          break;
+        case CALC_CHAR_COS:
+          op = cos;
+          break;
+        case CALC_CHAR_TAN:
+          op = tan;
+          break;
+        case CALC_CHAR_ASN:
+          op = asin;
+          break;
+        case CALC_CHAR_ACS:
+          op = acos;
+          break;
+        case CALC_CHAR_ATN:
+          op = atan;
+          break;
+        case CALC_CHAR_LGE:
+          op = log;
+          break;
+        case CALC_CHAR_LOG:
+          op = log10;
+          break;
+        case CALC_CHAR_SQT:
+          op = sqrt;
+          break;
+        default:
+          continue; /* invalid input */
+        }
+        answer[answerLocation - 1] = op(answer[answerLocation - 1]);
+      }
+    }
+    /* priority != 0 */
+    else if(answerLocation >= 2)
+    {
+      switch(output[i].raw.op.c)
+      {
+      case CALC_CHAR_ADD:
+        answer[answerLocation - 2] += answer[answerLocation - 1];
+        break;
+      case CALC_CHAR_SUB:
+        answer[answerLocation - 2] -= answer[answerLocation - 1];
+        break;
+      case CALC_CHAR_MUL:
+        answer[answerLocation - 2] *= answer[answerLocation - 1];
+        break;
+      case CALC_CHAR_DIV:
+        answer[answerLocation - 2] /= answer[answerLocation - 1];
+        break;
+      case CALC_CHAR_EXP:
+        answer[answerLocation - 2] = pow(answer[answerLocation - 2], answer[answerLocation - 1]);
+        break;
+      }
+
+      answerLocation--;
+    }
+  }
+
+  return answer[0];
+}
+
+/*
+ * @returns  0 when nothing should happen and QMK should work as usual
+ * @returns -1 when invalid input was given, QMK should ignore it
+ * @returns -2 when BSP should be done
+ * @returns -3 when CALC should be done
+ * @returns -4 when ENDCALC should be done
+ * @returns positive value of CALC_* when normal input was processed
+ */
+static int process_input(const uint16_t keycode, const uint8_t mods, const keyevent_t event)
+{
+  /* handle even when no key was pressed */
+  if(!event.pressed)
+  {
+    switch(keycode)
+    {
+      /* QMK should handle those */
+      case KC_RSFT:
+      case KC_LSFT:
+        return 0;
+        break;
+    }
+    /* ??? ignore */
+    return -1;
+  }
+
+  /* when shift key is pressed handle characters differently */
+  char characterPressed;
+  if((get_mods() & MODS_SHIFT_MASK))
+  {
+    switch(keycode)
+    {
+      case KC_9:
+        characterPressed = CALC_CHAR_BEG;
+        break;
+      case KC_0:
+        characterPressed = CALC_CHAR_END;
+        break;
+      case KC_EQUAL:
+        characterPressed = CALC_CHAR_ADD;
+        break;
+      case KC_KP_PLUS:
+        characterPressed = CALC_CHAR_ADD;
+        break;
+      case KC_6:
+        characterPressed = CALC_CHAR_EXP;
+        break;
+      case KC_8:
+        characterPressed = CALC_CHAR_MUL;
+        break;
+      case KC_KP_ASTERISK:
+        characterPressed = CALC_CHAR_MUL;
+        break;
+      case KC_S:
+        characterPressed = CALC_CHAR_ASN;
+        break;
+      case KC_C:
+        characterPressed = CALC_CHAR_ACS;
+        break;
+      case KC_T:
+        characterPressed = CALC_CHAR_ATN;
+        break;
+      case KC_L:
+        characterPressed = CALC_CHAR_LOG;
+        break;
+      default:
+        return -1;
+        break;
+    }
+    return characterPressed;
+  }
+
+  /* normal key handling:  shift not pressed */
+
+  /* digits */
+  if (keycode == KC_KP_0 || keycode == KC_0) {
+    return '0';
+  } else if (keycode >= KC_KP_1 && keycode <= KC_KP_9) {
+    return keycode - KC_KP_1 +1 + '0';
+  } else if (keycode >= KC_1 && keycode <= KC_9) {
+    return keycode - KC_1 +1 + '0';
+  }
+
+  /* other tokens */
+  switch (keycode) {
+    case KC_MINUS:
+    case KC_KP_MINUS:
+      return characterPressed = CALC_CHAR_SUB;
+    case KC_SLASH:
+    case KC_KP_SLASH:
+      return characterPressed = CALC_CHAR_DIV;
+    case KC_S:
+      return characterPressed = CALC_CHAR_SIN;
+    case KC_C:
+      return characterPressed = CALC_CHAR_COS;
+    case KC_T:
+      return characterPressed = CALC_CHAR_TAN;
+    case KC_Q:
+      return characterPressed = CALC_CHAR_SQT;
+    case KC_L:
+      return characterPressed = CALC_CHAR_LGE;
+    case KC_DOT:
+    case KC_KP_DOT:
+      return characterPressed = CALC_CHAR_DEC;
+    case KC_P:
+      return characterPressed = CALC_CHAR_PI;
+    case KC_E:
+      return characterPressed = CALC_CHAR_EUL;
+    case KC_BSPC:
+      return -2;
+    case KC_RSFT:
+      return 0;
+    case KC_LSFT:
+      return 0;
+    case CALC:
+      return -3;
+    case ENDCALC:
+      return -4;
+    default:
+      return -1;
+  }
+}
+
+bool process_record_user(uint16_t keycode, keyrecord_t* record)
+{
+	static char text[CALC_BUFFER_SIZE + 1]; // Used to store input and then output when ready to print
+	static char backspaceText[CALC_BUFFER_SIZE + 1]; // Pretty dumb waste of memory because only backspace characters, used with send_string to backspace and remove input
+
+	if((biton32(layer_state) == CALC_LAYER && CALC_FORCE_NUM_LOCK_INSIDE_CALC) || (biton32(layer_state) != CALC_LAYER && CALC_FORCE_NUM_LOCK_OUTSIDE_CALC))
+	{
+		bool numpadKeyPressed = record->event.pressed &&
+			!(get_mods() & MODS_SHIFT_MASK) &&
+			/* KC_KP_1, KC_KP_2, ..., KC_KP_0, KC_KP_DOT */
+			(keycode >= KC_KP_1 && keycode <= KC_KP_DOT);
+
+		if(numpadKeyPressed && !(host_keyboard_leds() & (1 << USB_LED_NUM_LOCK)))
+		{
+			add_key(KC_NLCK);
+			send_keyboard_report();
+			del_key(KC_NLCK);
+		}
+	}
+
+	if(biton32(layer_state) != CALC_LAYER) { return true; }
+
+	int action = process_input(keycode, get_mods(), record->event);
+	switch(action)
+	{
+	case 0:
+		return true;
+	case -1:
+		return false;
+	case -2:
+		if(inputLocation > 0)
+		{
+			inputLocation--;
+			text[inputLocation] = '\0';
+			backspaceText[0] = (char)8;
+			backspaceText[1] = '\0';
+			send_string(backspaceText);
+		}
+		return false;
+	case -3:
+		for(int i = 0; i < inputLocation; i++)
+		{
+			backspaceText[i] = (char)8;
+		}
+		send_string(backspaceText);
+		dtostrf(calc(text), CALC_PRINT_SIZE, CALC_PRINT_SIZE, text);
+		send_string(text);
+		for(unsigned char i = 0; i < CALC_BUFFER_SIZE; i++)
+		{
+			text[i] = '\0';
+			backspaceText[i] = '\0';
+		}
+		inputLocation = 0;
+		return false;
+	case -4:
+		for(unsigned char i = 0; i < CALC_BUFFER_SIZE; i++)
+		{
+			text[i] = '\0';
+			backspaceText[i] = '\0';
+		}
+		inputLocation = 0;
+		layer_off(CALC_LAYER);
+		return false;
+	default:
+		break;
+	}
+	char characterPressed = (char)action;
+
+	if(inputLocation < CALC_BUFFER_SIZE)
+	{
+		text[inputLocation] = characterPressed;
+		inputLocation++;
+
+		char characterToSend[2];
+		characterToSend[0] = characterPressed;
+		characterToSend[1] = '\0';
+
+		send_string(characterToSend);
+	}
+	return false;
+}

+ 99 - 0
users/doogle999/doogle999.h

@@ -0,0 +1,99 @@
+#ifndef USERSPACE
+#define USERSPACE
+
+#include "quantum.h"
+
+#define NO_ACTION_ONESHOT
+#define NO_ACTION_MACRO
+
+#define MODS_SHIFT_MASK (MOD_BIT(KC_LSHIFT)|MOD_BIT(KC_RSHIFT))
+
+// Layer the calculator is on
+#define CALC_LAYER 2
+
+// Inside is whether when you are in calc mode it should automatically force numlock, outside is whether it should do it outside of calculator mode
+#define CALC_FORCE_NUM_LOCK_INSIDE_CALC true
+#define CALC_FORCE_NUM_LOCK_OUTSIDE_CALC true
+
+// Maximum number of characters the calculator can have
+#define CALC_BUFFER_SIZE 32
+
+// Minimum width of the printed text / the number of decimal places
+#define CALC_PRINT_SIZE 6
+
+/*-----
+  Special
+-----*/
+#define CALC_CHAR_BEG '('
+#define CALC_CHAR_END ')'
+#define CALC_CHAR_DEC '.'
+
+/*-----
+  Operators - Can add more here such as modulo %, factorial !
+-----*/
+#define CALC_CHAR_ADD '+'
+#define CALC_PRIO_ADD 1
+
+#define CALC_CHAR_SUB '-'
+#define CALC_PRIO_SUB 1
+
+#define CALC_CHAR_MUL '*'
+#define CALC_PRIO_MUL 2
+
+#define CALC_CHAR_DIV '/'
+#define CALC_PRIO_DIV 2
+
+#define CALC_CHAR_EXP '^'
+#define CALC_PRIO_EXP 3
+
+/*-----
+  Functions
+-----*/
+#define CALC_CHAR_SIN 's'
+#define CALC_CHAR_COS 'c'
+#define CALC_CHAR_TAN 't'
+
+#define CALC_CHAR_ASN 'S'
+#define CALC_CHAR_ACS 'C'
+#define CALC_CHAR_ATN 'T'
+
+#define CALC_CHAR_LGE 'l'
+#define CALC_CHAR_LOG 'L'
+
+#define CALC_CHAR_SQT 'q'
+
+/*-----
+  Constants
+-----*/
+#define CALC_CHAR_EUL 'e'
+#define CALC_VALU_EUL 2.71828182845904523536
+
+#define CALC_CHAR_PI 'p'
+#define CALC_VALU_PI 3.14159265358979323846
+
+struct OP // Operator/function
+{
+  char c;
+  unsigned char priority;
+  bool ltr;
+};
+
+union TokenRaw // A token after the input has been processed, can either be a number or an operator/function
+{
+  double num;
+  struct OP op;
+};
+
+struct Token // Encapsulator
+{
+  bool isNum;
+  union TokenRaw raw;
+};
+
+enum CalcFunctions // Hardware calculator key functionality
+{
+  CALC = SAFE_RANGE,
+  ENDCALC
+};
+
+#endif

File diff suppressed because it is too large
+ 41 - 0
users/doogle999/readme.md


+ 14 - 0
users/doogle999/rules.mk

@@ -0,0 +1,14 @@
+SRC += doogle999.c
+
+CFLAGS += -fstrict-aliasing -ftree-vrp
+
+BOOTMAGIC_ENABLE = no	# Virtual DIP switch configuration(+1000)
+MOUSEKEY_ENABLE = no	# Mouse keys(+4700)
+EXTRAKEY_ENABLE = yes	# Audio control and System control(+450)
+CONSOLE_ENABLE = no	# Console for debug(+400)
+COMMAND_ENABLE = no    # Commands for debug and configuration
+SLEEP_LED_ENABLE = no  # Breathing sleep LED during USB suspend
+NKRO_ENABLE = yes		# USB Nkey Rollover - if this doesn't work, see here: https://github.com/tmk/tmk_keyboard/wiki/FAQ#nkro-doesnt-work
+BACKLIGHT_ENABLE = yes  # Enable keyboard backlight functionality
+AUDIO_ENABLE = no
+RGBLIGHT_ENABLE = yes