Entering numbers with cursorkeys

 #!/usr/bin/wish
 # $Id: 14928,v 1.3 2005-11-06 07:00:38 jcw Exp $
 # cprt: C2003 Uwe Klein Habertwedt
 # what: set of bindings and functions to make 
 # what: editing an entry with numbers either int or float
 # what: easy .
 # what: <Up> or <Down> incr or decrement the char left of the cursor
 # what: cursor in the leftmost pos inserts a "+" for <Up> or
 # what: a "-" for <Down> if the first char is [0-9] 
 # what: <Up> and <Down> on the dezimal point of a float multiply/divide
 # what: by 10, <Alt-Up> and <Control-Down> in any position will do 
 # what: the same. ints will stay ints and floats will stay floats.
 # what: scrolling the last char down through "0" changes it 
 # what: to "09" increasing resolution.
 # what: standard editing of an entry widget is not changed
 
 proc debug {args} {
        puts stderr $args
 }
 
 set ::text 12345.6
 
 entry .e -textvariable ::text -font {-size 30}
 pack  .e

 event add <<ReplaceHigher>>    <Key-Up>
 event add <<ReplaceLower>>     <Key-Down>
 event add <<ShiftHigher>>      <Alt-Up>
 event add <<ShiftLower>>       <Alt-Down>
 
 bind .e <<ReplaceHigher>> {
        ReplaceChar %W next 
 }
 bind .e <<ReplaceLower>> {
        ReplaceChar %W prev 
 }
 bind .e <<ShiftHigher>> {
        ShiftDezimal %W next 
 }
 bind .e <<ShiftLower>> {
        ShiftDezimal %W prev 
 }
 
 proc ReplaceChar {win dir args} {
        set var [ $win cget -textvariable ]
        debug var:$var
        upvar $var string
        set ins [ $win index insert ]
        debug ins:$ins
        if {$ins == 0} {
                set char [ string index $string 0 ]
                switch -- $char \
                  { } {
                        debug "char:$char, "
                        # nix
                } {+} {
                        debug "char:$char,+"
                        # nix
                } {-} {
                        debug "char:$char,-"
                        # nix
                } default {
                        debug "char:$char,def"
                        set string " $string" 
                }
                incr ins
        }
        set inse [ expr $ins - 1 ]
        $win selection range $inse $ins
        set len [ string length $string ]
        puts len:$len
        set pos $inse
        if {$ins == 1} {
                set pos start
        } elseif { $ins == $len } {
                set pos end
        } else {
                set pos $inse
        }
        set sel [ string index $string $inse ]
 
        debug sel:$dir,$pos,$sel
 
        switch -glob -- $dir,$pos,$sel \
          {next,*,[0-8]} {
                set nsel [ expr $sel + 1 ]
        } {next,*,9} {
                set nsel 0
        } {next,*, } {
                set nsel +
        } {next,*,+} {
                set nsel 1
        } {next,*,-} {
                set nsel +
        } {next,*,.} {
                debug gotoShiftDezimal
                return [ ShiftDezimal $win $dir ]
        } {prev,*,[1-9]} {
                set nsel [ expr $sel - 1 ]
        } {prev,end,0} {
                set nsel 09
        } {prev,*,0} {
                set nsel 9
        } {prev,*, } {
                set nsel -
        } {prev,*,+} {
                set nsel -
        } {prev,*,.} {
                return [ ShiftDezimal $win $dir ]
        } default {
                set nsel $sel
        }
 
        set string [ string replace $string $inse $inse $nsel ]
 }
 
 proc ShiftDezimal {win dir args} {
        set var [ $win cget -textvariable ]
        debug var:$var
        upvar $var string
        set ostring $string
        if {[catch { expr $string } cerr]} {
                debug nonumber
                return
        }
        if { $string == 0 } {
                debug zero
                return
        }
        switch -- $dir \
          next {
                set string [ expr $string * 10 ]
        } prev {
                set string [ expr $string / 10 ]
        }
        debug "old $ostring new $string"
 }