OSD Calculator
First of all, my english is pretty horrible so sorry of that.
About a half year ago I got an idea when I was using photoshop and got annoyed when I needed everytime to open my calculator to calculate simple calculations. And because I don't use so much numpad I made calculator in numpad. I did this script then and never shared because I didn't use it after all a lot of and I thought nobody doesn't need this and I had couple problems with it. But now I thought that why not. Maybe AHK community gets something out of this.
Basic idea is that whole numpad area is your calculator and you can type in your screen calculation and press enter to get your answer. When your num lock is on, calculator is on and if you want to reset the calculator you just switch calculator off and on (like those cheap simple calculators what you can buy from any market). You can type numbers, basic operations (+, -, *, /) and decimals. You can copy and paste stuff too (Ctrl+C and V) in calculator and from calculator. You can change your font color too.
Features:
- Calculate basic calculations fast and easy
- Decimals works
- Copy and paste your numbers
- Change your font color!
Code:
/* OSD Calculator By Argande102 Thanks to: Laszlo's Monster script (http://www.autohotkey.com/board/topic/15675-monster-evaluate-math-expressions-in-strings/) */ OperatorPass := false CopyPaste := true usercolor = black screeny := A_ScreenHeight/100*80 Gui +LastFound +AlwaysOnTop +ToolWindow -Caption Gui, Color, FFFFFF Gui, Font, s60 q3 Gui, Add, Text, vDisplayText c%usercolor% XCenter YCenter W%A_ScreenWidth% Center WinSet, TransColor, FFFFFF 150 Gui, Show, xCenter y%screeny% W%A_ScreenWidth% NoActivate Menu, tray, NoStandard Menu, tray, add, Font Color, FontColor Menu, tray, add, Exit SetNumlockState, On return ~NumLock:: Suspend Math = Gui, Hide OperatorPass := false CopyPaste := 1 return Numpad0:: Math := Math "0" GuiControl,, DisplayText, %Math% Gui, Show SetTimer, Closetext, 60000 OperatorPass := true CopyPaste := 0 return Numpad1:: Math := Math "1" GuiControl,, DisplayText, %Math% Gui, Show SetTimer, Closetext, 60000 OperatorPass := true CopyPaste := 0 return Numpad2:: Math := Math "2" GuiControl,, DisplayText, %Math% Gui, Show SetTimer, Closetext, 60000 OperatorPass := true CopyPaste := 0 return Numpad3:: Math := Math "3" GuiControl,, DisplayText, %Math% Gui, Show SetTimer, Closetext, 60000 OperatorPass := true CopyPaste := 0 return Numpad4:: Math := Math "4" GuiControl,, DisplayText, %Math% Gui, Show SetTimer, Closetext, 60000 OperatorPass := true CopyPaste := 0 return Numpad5:: Math := Math "5" GuiControl,, DisplayText, %Math% Gui, Show SetTimer, Closetext, 60000 OperatorPass := true CopyPaste := 0 return Numpad6:: Math := Math "6" GuiControl,, DisplayText, %Math% Gui, Show SetTimer, Closetext, 60000 OperatorPass := true CopyPaste := 0 return Numpad7:: Math := Math "7" GuiControl,, DisplayText, %Math% Gui, Show SetTimer, Closetext, 60000 OperatorPass := true CopyPaste := 0 return Numpad8:: Math := Math "8" GuiControl,, DisplayText, %Math% Gui, Show SetTimer, Closetext, 60000 OperatorPass := true CopyPaste := 0 return Numpad9:: Math := Math "9" GuiControl,, DisplayText, %Math% Gui, Show SetTimer, Closetext, 60000 OperatorPass := true CopyPaste := 0 return NumpadDot:: if (DotPass = false) return Math := Math "." GuiControl,, DisplayText, %Math% Gui, Show SetTimer, Closetext, 60000 OperatorPass := true CopyPaste := 0 DotPass := false return NumpadDiv:: if (OperatorPass = false) { SoundPlay, *1 return } Math := Math " / " GuiControl,, DisplayText, %Math% Gui, Show SetTimer, Closetext, 60000 OperatorPass := false CopyPaste := 1 DotPass := true return NumpadMult:: if (OperatorPass = false) { SoundPlay, *1 return } Math := Math " * " GuiControl,, DisplayText, %Math% Gui, Show SetTimer, Closetext, 60000 OperatorPass := false CopyPaste := 1 DotPass := true return NumpadAdd:: if (OperatorPass = false) { SoundPlay, *1 return } Math := Math " + " GuiControl,, DisplayText, %Math% Gui, Show SetTimer, Closetext, 60000 OperatorPass := false CopyPaste := 1 DotPass := true return NumpadSub:: if (OperatorPass = false) { SoundPlay, *1 return } Math := Math " - " GuiControl,, DisplayText, %Math% Gui, Show SetTimer, Closetext, 60000 OperatorPass := false CopyPaste := 1 DotPass := true return NumpadEnter:: if (OperatorPass = false) { SoundPlay, *1 return } StringReplace, Math, Math, %A_SPACE%, , All Math := Eval(Math) GuiControl,, DisplayText, %Math% Gui, Show SetTimer, Closetext, 10000 OperatorPass := true CopyPaste := 2 DotPass := true return ~^c:: if (CopyPaste = 2) Clipboard := Math SetTimer, Closetext, 60000 return ~^v:: if (CopyPaste = 1) { StringReplace, Check, Clipboard, %A_SPACE%, , All RegExMatch(Check, "[^1234567890+\-*.]", Check2) if (Check2 != "") return Check := RegExReplace(Check, "(,|\.)", ".", ReplacementCount) if ReplacementCount > 1 return Math := Math Check } GuiControl,, DisplayText, %Math% Gui, Show OperatorPass := true CopyPaste := 0 SetTimer, Closetext, 60000 return ; ############################################################################################# ; ; # http://www.autohotkey.com/board/topic/15675-monster-evaluate-math-expressions-in-strings/ # ; ; ############################################################################################# ; Eval(x) { ; non-recursive PRE/POST PROCESSING: I/O forms, numbers, ops, ";" Local FORM, FormF, FormI, i, W, y, y1, y2, y3, y4 FormI := A_FormatInteger, FormF := A_FormatFloat SetFormat Integer, D ; decimal intermediate results! RegExMatch(x, "\$(b|h|x|)(\d*[eEgG]?)", y) FORM := y1, W := y2 ; HeX, Bin, .{digits} output format SetFormat FLOAT, 0.16e ; Full intermediate float precision StringReplace x, x, %y% ; remove $.. Loop If RegExMatch(x, "i)(.*)(0x[a-f\d]*)(.*)", y) x := y1 . y2+0 . y3 ; convert hex numbers to decimal Else Break Loop If RegExMatch(x, "(.*)'([01]*)(.*)", y) x := y1 . FromBin(y2) . y3 ; convert binary numbers to decimal: sign = first bit Else Break x := RegExReplace(x,"(^|[^.\d])(\d+)(e|E)","$1$2.$3") ; add missing '.' before E (1e3 -> 1.e3) ; literal scientific numbers between ‘ and ’ chars x := RegExReplace(x,"(\d*\.\d*|\d)([eE][+-]?\d+)","‘$1$2’") StringReplace x, x,`%, \, All ; % -> \ (= MOD) StringReplace x, x, **,@, All ; ** -> @ for easier process StringReplace x, x, +, ±, All ; ± is addition x := RegExReplace(x,"(‘[^’]*)±","$1+") ; ...not inside literal numbers StringReplace x, x, -, ¬, All ; ¬ is subtraction x := RegExReplace(x,"(‘[^’]*)¬","$1-") ; ...not inside literal numbers Loop Parse, x, `; y := Eval1(A_LoopField) ; work on pre-processed sub expressions ; return result of last sub-expression (numeric) If FORM = b ; convert output to binary y := W ? ToBinW(Round(y),W) : ToBin(Round(y)) Else If (FORM="h" or FORM="x") { SetFormat Integer, Hex ; convert output to hex y := Round(y) + 0 } Else { W := W="" ? "0.6g" : "0." . W ; Set output form, Default = 6 decimal places SetFormat FLOAT, %W% y += 0.0 } SetFormat Integer, %FormI% ; restore original formats SetFormat FLOAT, %FormF% Return y } Eval1(x) { ; recursive PREPROCESSING of :=, vars, (..) [decimal, no ";"] Local i, y, y1, y2, y3 ; save function definition: f(x) := expr If RegExMatch(x, "(\S*?)\((.*?)\)\s*:=\s*(.*)", y) { f%y1%__X := y2, f%y1%__F := y3 Return } ; execute leftmost ":=" operator of a := b := ... If RegExMatch(x, "(\S*?)\s*:=\s*(.*)", y) { y := "x" . y1 ; user vars internally start with x to avoid name conflicts Return %y% := Eval1(y2) } ; here: no variable to the left of last ":=" x := RegExReplace(x,"([\)’.\w]\s+|[\)’])([a-z_A-Z]+)","$1«$2»") ; op -> «op» x := RegExReplace(x,"\s+") ; remove spaces, tabs, newlines x := RegExReplace(x,"([a-z_A-Z]\w*)\(","'$1'(") ; func( -> 'func'( to avoid atan|tan conflicts x := RegExReplace(x,"([a-z_A-Z]\w*)([^\w'»’]|$)","%x$1%$2") ; VAR -> %xVAR% x := RegExReplace(x,"(‘[^’]*)%x[eE]%","$1e") ; in numbers %xe% -> e x := RegExReplace(x,"‘|’") ; no more need for number markers Transform x, Deref, %x% ; dereference all right-hand-side %var%-s Loop { ; find last innermost (..) If RegExMatch(x, "(.*)\(([^\(\)]*)\)(.*)", y) x := y1 . Eval@(y2) . y3 ; replace (x) with value of x Else Break } Return Eval@(x) } Eval@(x) { ; EVALUATE PRE-PROCESSED EXPRESSIONS [decimal, NO space, vars, (..), ";", ":="] Local i, y, y1, y2, y3, y4 If x is number ; no more operators left Return x ; execute rightmost ?,: operator RegExMatch(x, "(.*)(\?|:)(.*)", y) IfEqual y2,?, Return Eval@(y1) ? Eval@(y3) : "" IfEqual y2,:, Return ((y := Eval@(y1)) = "" ? Eval@(y3) : y) StringGetPos i, x, ||, R ; execute rightmost || operator IfGreaterOrEqual i,0, Return Eval@(SubStr(x,1,i)) || Eval@(SubStr(x,3+i)) StringGetPos i, x, &&, R ; execute rightmost && operator IfGreaterOrEqual i,0, Return Eval@(SubStr(x,1,i)) && Eval@(SubStr(x,3+i)) ; execute rightmost =, <> operator RegExMatch(x, "(.*)(?<![\<\>])(\<\>|=)(.*)", y) IfEqual y2,=, Return Eval@(y1) = Eval@(y3) IfEqual y2,<>, Return Eval@(y1) <> Eval@(y3) ; execute rightmost <,>,<=,>= operator RegExMatch(x, "(.*)(?<![\<\>])(\<=?|\>=?)(?![\<\>])(.*)", y) IfEqual y2,<, Return Eval@(y1) < Eval@(y3) IfEqual y2,>, Return Eval@(y1) > Eval@(y3) IfEqual y2,<=, Return Eval@(y1) <= Eval@(y3) IfEqual y2,>=, Return Eval@(y1) >= Eval@(y3) ; execute rightmost user operator (low precedence) RegExMatch(x, "i)(.*)«(.*?)»(.*)", y) If IsFunc(y2) Return %y2%(Eval@(y1),Eval@(y3)) ; predefined relational ops StringGetPos i, x, |, R ; execute rightmost | operator IfGreaterOrEqual i,0, Return Eval@(SubStr(x,1,i)) | Eval@(SubStr(x,2+i)) StringGetPos i, x, ^, R ; execute rightmost ^ operator IfGreaterOrEqual i,0, Return Eval@(SubStr(x,1,i)) ^ Eval@(SubStr(x,2+i)) StringGetPos i, x, &, R ; execute rightmost & operator IfGreaterOrEqual i,0, Return Eval@(SubStr(x,1,i)) & Eval@(SubStr(x,2+i)) ; execute rightmost <<, >> operator RegExMatch(x, "(.*)(\<\<|\>\>)(.*)", y) IfEqual y2,<<, Return Eval@(y1) << Eval@(y3) IfEqual y2,>>, Return Eval@(y1) >> Eval@(y3) ; execute rightmost +- (not unary) operator RegExMatch(x, "(.*[^!\~±¬\@\*/\\])(±|¬)(.*)", y) ; lower precedence ops already handled IfEqual y2,±, Return Eval@(y1) + Eval@(y3) IfEqual y2,¬, Return Eval@(y1) - Eval@(y3) ; execute rightmost */% operator RegExMatch(x, "(.*)(\*|/|\\)(.*)", y) IfEqual y2,*, Return Eval@(y1) * Eval@(y3) IfEqual y2,/, Return Eval@(y1) / Eval@(y3) IfEqual y2,\, Return Mod(Eval@(y1),Eval@(y3)) ; execute rightmost power StringGetPos i, x, @, R IfGreaterOrEqual i,0, Return Eval@(SubStr(x,1,i)) ** Eval@(SubStr(x,2+i)) ; execute rightmost function, unary operator If !RegExMatch(x,"(.*)(!|±|¬|~|'(.*)')(.*)", y) Return x ; no more function (y1 <> "" only at multiple unaries: --+-) IfEqual y2,!,Return Eval@(y1 . !y4) ; unary ! IfEqual y2,±,Return Eval@(y1 . y4) ; unary + IfEqual y2,¬,Return Eval@(y1 . -y4) ; unary - (they behave like functions) IfEqual y2,~,Return Eval@(y1 . ~y4) ; unary ~ If IsFunc(y3) Return Eval@(y1 . %y3%(y4)) ; built-in and predefined functions(y4) Return Eval@(y1 . Eval1(RegExReplace(f%y3%__F, f%y3%__X, y4))) ; LAST: user defined functions } ToBin(n) { ; Binary representation of n. 1st bit is SIGN: -8 -> 1000, -1 -> 1, 0 -> 0, 8 -> 01000 Return n=0||n=-1 ? -n : ToBin(n>>1) . n&1 } ToBinW(n,W=8) { ; LS W-bits of Binary representation of n Loop %W% ; Recursive (slower): Return W=1 ? n&1 : ToBinW(n>>1,W-1) . n&1 b := n&1 . b, n >>= 1 Return b } FromBin(bits) { ; Number converted from the binary "bits" string, 1st bit is SIGN n = 0 Loop Parse, bits n += n + A_LoopField Return n - (SubStr(bits,1,1)<<StrLen(bits)) } Sgn(x) { Return (x>0)-(x<0) } MIN(a,b) { Return a<b ? a : b } MAX(a,b) { Return a<b ? b : a } GCD(a,b) { ; Euclidean GCD Return b=0 ? Abs(a) : GCD(b, mod(a,b)) } Choose(n,k) { ; Binomial coefficient p := 1, i := 0, k := k < n-k ? k : n-k Loop %k% ; Recursive (slower): Return k = 0 ? 1 : Choose(n-1,k-1)*n//k p *= (n-i)/(k-i), i+=1 ; FOR INTEGERS: p *= n-i, p //= ++i Return Round(p) } Fib(n) { ; n-th Fibonacci number (n < 0 OK, iterative to avoid globals) a := 0, b := 1 Loop % abs(n)-1 c := b, b += a, a := c Return n=0 ? 0 : n>0 || n&1 ? b : -b } fac(n) { ; n! Return n<2 ? 1 : n*fac(n-1) } Closetext: Math = Gui, Hide return FontColor: lastcolor := usercolor InputBox, usercolor, Font Color, Insert color literally (e.g. black) or in HEX (HTML Color Code) format without "#" sign.`nWhite doesn't work.`n`nLast color was: %usercolor%. if usercolor = { usercolor := lastcolor return } if Errorlevel = 0 { Gui, Font, c%usercolor% GuiControl, Font, DisplayText return } usercolor := lastcolor return Exit: ExitApp
After all, really simple script.
Notes:
- Copy and paste works but it has some own problems e.g. when you paste something it's pasting that in calculator and outside of the calculator.
- Position is now only one place.
- White color doesn't work. I use it as transparency color so if you put white, whole text is gone. I think it's fixable but I leave it now.
- I'm not the best at AHK so there isn't extremely compact code here and maybe useless stuff too.
If you have any good fixes and tips, tell me!