     isControlKey = (which) ->
       controlKeys.indexOf(which) >= 0
 
-    lostAComma = (initialCommaCount, elem) ->
-      elem.val().replace(/\d/g,"").length < initialCommaCount
-
-    gainedAComma = (initialCommaCount, elem) ->
-      elem.val().replace(/\d/g,"").length > initialCommaCount
+    invalidAction = (elem, event, options) ->
+      invalidKey(event) or invalidZero(elem, event) or maxDigitsReached(elem, options)
+
+    # invalid actions
+    invalidKey = (event) ->
+      isNotDigit(event.which) && isNotControlKey(event.which)
+
+    invalidZero = (elem, event) ->
+      # entering 0 in the first place
+      elem[0].selectionStart == 0 and event.which == 48 
+
+    maxDigitsReached = (elem, options) ->
+      elem.val().length >= options.maxDigits
 
     hasMultipleDecimals = (val) ->
       val? && val.toString().split('.').length > 2

                val

            elem.on 'keyup', (event) ->
              if !isMovementKey(event)
                if event.which == 8
                  newCursorPosition = elem[0].selectionStart
                else
                  if elem.val().length >= options.maxDigits
                    newCursorPosition = elem[0].selectionStart
                  else
                    newCursorPosition = elem[0].selectionStart + 1

                elem.val resetCommas(elem.val())
                elem[0].setSelectionRange(newCursorPosition, newCursorPosition)

              triggerUpdate = ()->
                if scope.grade.raw_score != elem.val()


              # not updating unless value is longer than 4 digits including commas
              # still some issues moving the comma after input/delete
              # need to add support for delete/backspace if comma is present
              # need to exclude entry of zeroes in 
              if scope.rawScoreUpdating == false
                beginUpdate() unless elem.val().length >= options.maxDigits

