Edit in JSFiddle

if (typeof String.prototype.startsWith != 'function') {
    String.prototype.startsWith = function (str) {
        return this.substring(0, str.length) === str;
    }
};


function setSelectionRange(input, selectionStart, selectionEnd) {
  if (input.setSelectionRange) {
    input.focus();
    input.setSelectionRange(selectionStart, selectionEnd);
  }
  else if (input.createTextRange) {
    var range = input.createTextRange();
    range.collapse(true);
    range.moveEnd('character', selectionEnd);
    range.moveStart('character', selectionStart);
    range.select();
  }
}

function setCaretToPos (input, pos) {
  setSelectionRange(input, pos, pos);
}

(function ($) {
    var cleanInput = function (value) {
    		value = value || '0';
        value = value == "-" ? "0" : value;
    		console.log("dirty str: " + value);
        var isNegative = value.startsWith('(') || value.startsWith('-');
				var cleanStr = value.replace(/[^0-9.]/g, '');
        console.log("cleaned str:" + cleanStr);
        var result = parseFloat(cleanStr) * (isNegative? -1 : 1);
				console.log("cleaned: " + result);
        return result == Number.NaN ? 0 : result;
    }

    var formatInput = function (value) {
        toks = value.toFixed(2).replace('-', '').split('.');
        var display = '$' + $.map(toks[0].split('').reverse(), function (elm, i) {
            return [(i % 3 == 0 && i > 0 ? ',' : ''), elm];
        }).reverse().join('') + '.' + toks[1];

				
        display = value < 0 ? '(' + display + ')' : display;
        console.log("formatted: " + display);
        return display;
    }

    ko.bindingHandlers.money = {
        init: function (elm, valueAccessor) {
            $(elm).keydown(
            function(e){
            -1!==$.inArray(e.keyCode,[46,8,9,27,13,110,190])||/65|67|86|88/.test(e.keyCode)&&(!0===e.ctrlKey||!0===e.metaKey)||35<=e.keyCode&&40>=e.keyCode||(e.shiftKey||48>e.keyCode||57<e.keyCode)&&(96>e.keyCode||105<e.keyCode)&&e.preventDefault();
            
            
            console.log("e.keycode="+e.keyCode);
            // prevent putting dashes anywhere but first position
     					if($.inArray(e.keyCode, [189,173]) >= 0) {              

            console.log("e.keycode="+e.keyCode);
                  elm.value = elm.value.startsWith("-") ? elm.value : ("-" + elm.value);             
                  setCaretToPos(elm, 1);
              	}                   
            
            }).keyup(function (e) {
                	
            		valueAccessor()(cleanInput(elm.value));
            }).focus(function () {
            		elm.value = valueAccessor()();
								
            }).blur(function() {
            		elm.value = formatInput(valueAccessor()());
            }).addClass('money');
        },
        update: function (elm, valueAccessor, allBindingsAccessor) {
            var value =ko.utils.unwrapObservable(valueAccessor())
            $elm = $(elm),
            method = $elm.is(":input") ? "val" : "html";
            if(!$elm.is(":focus"))
							$elm[method](formatInput(value));
            $elm.toggleClass('negative', value < 0);
        }
    };
})(jQuery);


//Not part of the custom binding, just wiring the viewModel up to the bindings.
$(function(){
    var viewModel={
        Cash:ko.observable(-1234.56)
    };
    ko.applyBindings(viewModel);
});
    
    <body class='ui-widget'>
        <header class='ui-widget-header'>
            <h1>Give me all of your money</h1>
            <br />
            <h2> All your hugs and kisses too</h2>
        </header>
        <div class='ui-widget-content'>
            <p>
                <label>How Much?</label> <input type="text" data-bind="money:Cash" /> or? <input type="text" data-bind="value:Cash" /></p>
            <p>
                <label>Non inputs too!</label> <span data-bind="money:Cash" /></p>
            <p>
                <label>Normal binding:</label> <span data-bind="text:Cash" /></p>
        </div>
    </body>
.money {text-align:right}
.money.negative{color:#f00}

External resources loaded into this fiddle: