We talked about a “location” to be defined later. It’s time now to define it. Here’s the structure:

(defstruct (location) (row nil) ;; 1-offset row number (column nil) ;; 1-offset column number (shift :UNSHIFTED) (width 1) (category-1 nil) (category-2 nil))

The row and column are just the 1-offset locations on the calculator keypad, with the 1,1 entry being the upper-left key on the calculator. The shift field indicates whether the function is associated with one of the three shift keys. These keys allow a single operation key to have up to four different behaviours, depending on whether or not a shift key was pressed before the key itself. The three keys have colours that match the label colour on the key. They are f (yellow), g (blue), and h (black). The width indicator is because the ENTER key is double-width, so we want to be able to indicate that in the key layout. The category fields are there for use in non-GUI interfaces. For a command-line interface with button names laid out above, it makes sense to group like functions together for clarity. In that way, we can say that the sine function is in the :TRIGONOMETRY category-1, and the inverse sine is in the :TRIGONOMETRY category-1 and :INVERSE category-2.

So, what do our key definitions look like now? Here’s a set of 5, the arithmetic operations down the left side of the keypad:

(define-op-key (:location (make-location :row 5 :col 1 :category-1 :ARITHMETIC) :abbreviation "-" :documentation "Subtracts X from Y") X <- (- Y X)) (define-op-key (:location (make-location :row 6 :col 1 :category-1 :ARITHMETIC) :abbreviation "+" :documentation "Adds X to Y") X <- (+ Y X)) (define-op-key (:location (make-location :row 7 :col 1 :category-1 :ARITHMETIC) :abbreviation "*" :documentation "Multiplies Y by X") X <- (* Y X)) (define-op-key (:location (make-location :row 8 :col 1 :category-1 :ARITHMETIC) :abbreviation "/" :documentation "Divides Y by X") X <- (/ Y X)) (define-op-key (:location (make-location :row 8 :col 1 :shift :H-BLACK :category-1 :ARITHMETIC) :abbreviation "!" :documentation "Computes X factorial") (assert (and (integerp X) (>= X 0))) (let ((result 1)) (dotimes (i X) (setf result (* result (1+ i)))) X <- result))

The code in this state is checked into the github repository under the tag “v2014-10-23”.