diff --git a/docs/en/calculator.md b/docs/en/calculator.md new file mode 100644 index 000000000..008a26b68 --- /dev/null +++ b/docs/en/calculator.md @@ -0,0 +1,40 @@ +# Calculator + +This extension adds a basic 4-function (+,-.*,/) calculator used with an attached display. + +## Adding the calculator extension + +You'll need to make sure you have a [display](Display.md) working first. Then import the calculator functions: + +`from kmk.extensions.calculator import Calc, InitCalc` + +Initialise the calculator, point it to the display, and tell it the layer you want your calculator functions associated with. For example, if your display is called "display" and your calculator buttons are going to be on layer 1, use: + +`InitCalc(display,1)` + +This will prepare a "calculator ready" screen on that layer. + +Now you need to create the keys for your calculator. Normally there will be 17 of these: one for each digit, one for each arithmetic function, one for the decimal point, one for the equals/enter button, one to clear, and one to send the current result to the connected computer. Each one needs to be pointed to the display and layer like the init function above: + +``` +KC_C0 = Calc("0",display,1) +KC_C1 = Calc("1",display,1) +KC_C2 = Calc("2",display,1) +KC_C3 = Calc("3",display,1) +KC_C4 = Calc("4",display,1) +KC_C5 = Calc("5",display,1) +KC_C6 = Calc("6",display,1) +KC_C7 = Calc("7",display,1) +KC_C8 = Calc("8",display,1) +KC_C9 = Calc("9",display,1) +KC_CEQ = Calc("=",display,1) +KC_CADD = Calc("+",display,1) +KC_CSUB = Calc("-",display,1) +KC_CMUL = Calc("*",display,1) +KC_CDIV = Calc("/",display,1) +KC_CPT = Calc(".",display,1) +KC_CCL = Calc("c",display,1) #clear +KC_CSND = Calc("s",display,1) #send result +``` + +Now you can add these new keycodes to your keymap and you'll have a working desktop calculator! diff --git a/docs/en/extensions.md b/docs/en/extensions.md index a285127b0..e4a0b1717 100644 --- a/docs/en/extensions.md +++ b/docs/en/extensions.md @@ -19,3 +19,4 @@ extensions are - [SpaceMouse Status](spacemouse_status.md): Exposes host-side LED status of the SpaceMouse HID. - [Status LED](extension_statusled.md): Indicates which layer you are on with an array of single leds. - [Stringy Keymaps](extension_stringy_keymaps): Enables referring to keys by `'NAME'` rather than `KC.NAME` +- [Calculator](calculator.md): Adds a simple standalone 4-function calculator diff --git a/kmk/extensions/calculator.py b/kmk/extensions/calculator.py new file mode 100644 index 000000000..7c80e0245 --- /dev/null +++ b/kmk/extensions/calculator.py @@ -0,0 +1,114 @@ +from kmk.extensions.display import Display, TextEntry, ImageEntry + +from kmk.keys import Key + +from kmk.kmk_keyboard import KMKKeyboard +from kmk.keys import KC + +import time + +from kmk.modules.macros import Macros + +macros=Macros() + + +binary = { + '+','-','*','/' +} + +equation = "" +entry = "" +result = "" +op = None + +class Calc(Key): + def __init__(self, key, display, layer): + self.key = key + self.display = display + self.layer = layer + return + + def on_press(self, keyboard, coord_int=None): + global entry + global result + global op + global binary + global equation + + if len(self.key) == 1 and self.key in "0123456789": + if result is not "": + entry = "" + result = "" + entry = entry + self.key + equation = equation + self.key + print("equation: " + equation) + self.display.entries = [TextEntry(equation,x=10,y=10,y_anchor="T",layer=self.layer)] + + elif self.key == "." and not "." in entry: + if entry == "": + entry = "0" + entry = entry + self.key + equation = equation + self.key + self.display.entries = [TextEntry(equation,x=10,y=10,y_anchor="T",layer=self.layer)] + + elif self.key == "c": + entry = "" + equation = "" + result = "" + op = None + self.display.entries= [TextEntry("= Calculator Ready =",x=64,y=10,x_anchor="M",layer=self.layer)] + + elif self.key == "=": + if equation == "" and op is not None: + equation = str(result) + op + str(entry) + print("evaluating equation: " + equation) + result = eval(equation) + self.display.entries=[TextEntry(equation,x=10,y=10,y_anchor="T",layer=self.layer), + TextEntry(format_number(str(result)),x=118,y=54,x_anchor="R",y_anchor="B",layer=self.layer)] + equation = "" + + elif self.key in binary and equation is not "" and equation[-1:] not in binary: + self.display.entries=[TextEntry(equation,x=10,y=10,y_anchor="T",layer=self.layer)] + if entry is not "": + entry = "" + elif equation == "": + equation = format_number(str(result)) + equation = equation + self.key + op = self.key + self.display.entries=[TextEntry(equation,x=10,y=10,y_anchor="T",layer=self.layer)] + + elif self.key in binary and result is not "": + equation = str(result) + self.key + self.display.entries = [TextEntry(equation,x=10,y=10,y_anchor="T",layer=self.layer)] + + elif self.key == "s" and result is not "": + keyboard.tap_key(KC.MACRO(format_number(str(result)))) + + self.display.render(self.layer) + + def on_release(self, keyboard, coord_int=None): + return + + def do_binary_op(self): + global number1 + global number2 + global op + global binary + if op and number2 is not None: + number1 = binary[op][0](number1, number2) + print("number1 is now " + str(number1)) + +class InitCalc: + def __init__(self,display,layer): + display.entries += [TextEntry("= Calculator Ready =",x=64,y=10,x_anchor="M",layer=layer)] + +def format_number(num_str): + if "." in num_str: + parts = num_str.split(".") + integer_part = parts[0] + decimal_part = parts[1].rstrip("0") + if decimal_part: + return f"{integer_part}.{decimal_part}" + else: + return integer_part + return num_str