         }
     }
     
-    func layoutCharacterWithSidesRow(row: [Key], modelToView: [Key:KeyboardKey], keyWidth: CGFloat, gapWidth: CGFloat, otherKeyRatio: CGFloat, frame: CGRect) {
+    func layoutCharacterWithSidesRow(row: [Key], modelToView: [Key:KeyboardKey], keyWidth: CGFloat, gapWidth: CGFloat, m: CGFloat, c: CGFloat, frame: CGRect) {
         let numCharacters = row.count - 2
         let keySpace = CGFloat(numCharacters) * keyWidth + CGFloat(numCharacters - 1) * gapWidth
         let sideSpace = (frame.width - keySpace) / CGFloat(2)
-        let specialCharacterWidth = sideSpace * otherKeyRatio
+        
+        var specialCharacterWidth = sideSpace * m + c
+        specialCharacterWidth = max(specialCharacterWidth, keyWidth)
         let specialCharacterGap = sideSpace - specialCharacterWidth
         
         var currentOrigin = frame.origin.x

                return currentMax
            }()
            
            // measurement
            var sideEdges = (isLandscape ? layoutConstants.sideEdgesPortrait(bounds.width) : layoutConstants.sideEdgesLandscape)
            
            // measurement
            let bottomEdge = sideEdges
            
            let normalKeyboardSize = bounds.width - CGFloat(2) * sideEdges
            
            // measurement
            let shrunkKeyboardSize = layoutConstants.keyboardShrunkSize(normalKeyboardSize)
            
            sideEdges += ((normalKeyboardSize - shrunkKeyboardSize) / CGFloat(2))

            // measurement
            let topEdge: CGFloat = ((isLandscape ? layoutConstants.topEdgeLandscape : layoutConstants.topEdgePortrait(bounds.width)) + self.topBanner)
            
            // measurement
            let rowGap: CGFloat = (isLandscape ? layoutConstants.rowGapLandscape : layoutConstants.rowGapPortrait(bounds.width))
            let lastRowGap: CGFloat = (isLandscape ? rowGap : layoutConstants.rowGapPortraitLastRow(bounds.width))
            let rowGapTotal = CGFloat(numRows - 1 - 1) * rowGap + lastRowGap
            
            // measurement
            let keyGap: CGFloat = (isLandscape ? layoutConstants.keyGapLandscape(bounds.width, rowCharacterCount: mostKeysInRow) : layoutConstants.keyGapPortrait(bounds.width, rowCharacterCount: mostKeysInRow))
            
            // measurement
            let keyHeight: CGFloat = {
                let totalGaps = bottomEdge + topEdge + rowGapTotal
                return (bounds.height - totalGaps) / CGFloat(numRows)
            }()
            
            // measurement
            let letterKeyWidth: CGFloat = {
                let totalGaps = (sideEdges * CGFloat(2)) + (keyGap * CGFloat(mostKeysInRow - 1))
                return (bounds.width - totalGaps) / CGFloat(mostKeysInRow)
            }()
            
            for (r, row) in enumerate(page.rows) {
                let rowGapCurrentTotal = (r == page.rows.count - 1 ? rowGapTotal : CGFloat(r) * rowGap)
                let frame = CGRectMake(sideEdges, topEdge + (CGFloat(r) * keyHeight) + rowGapCurrentTotal, bounds.width - CGFloat(2) * sideEdges, keyHeight)
                self.handleRow(row, keyGaps: keyGap, letterKeyWidth: letterKeyWidth, frame: frame)
            }
        }
    }
    
    // quick heuristics for default keyboard rows
    // feel free to extend this method (calling super) with your own row layouts
    func handleRow(row: [Key], keyGaps: CGFloat, letterKeyWidth: CGFloat, frame: CGRect) {
        
        // basic character row: only typable characters
        if row[0].type == Key.KeyType.Character {

            
        // character row with side buttons: shift, backspace, etc.
        else if row[1].type == Key.KeyType.Character {
            self.layoutCharacterWithSidesRow(row, modelToView: self.modelToView, keyWidth: letterKeyWidth, gapWidth: keyGaps, m: m, c: c, frame: frame)
        }
            
        // bottom row with things like space, return, etc.
