/* KeyStats class calculates statistics on typing text using a keyboard displays a summary of the statistics author: JAM (Jon A. Maxwell) email: jmaxwell@acm.vt.edu date: Mar 20 1998 */ import java.awt.*; import java.util.Vector; public class KeyStats extends Panel { // labels (xxxL description, xxxD data) Label distanceL, distanceD; Label sameHandL, sameHandD; Label sameFingerL, sameFingerD; Label totalKeysL, totalKeysD; Label rowL[], rowD[]; Label fingerL, fingerD; Vector allLabels; // data used to display stats double distanceTotal; int rowTotal[] = new int[Keyboard.ROWS]; int lhTotal[] = new int[5]; //fingers on lh int rhTotal[] = new int[5]; int sameHandTotal; int sameFingerTotal; int keysTotal; // Constructor: setup gui public KeyStats() { allLabels = new Vector(); // make labels distanceL = makeLabel("Distance:",Label.RIGHT); distanceD = makeLabel("",Label.RIGHT); sameHandL = makeLabel("Same hand:",Label.RIGHT); sameHandD = makeLabel("",Label.RIGHT); sameFingerL = makeLabel("Same finger:",Label.RIGHT); sameFingerD = makeLabel("",Label.RIGHT); totalKeysL = makeLabel("Total keys:",Label.RIGHT); totalKeysD = makeLabel("", Label.RIGHT); rowL = new Label[4]; rowL[0] = makeLabel("Number row:", Label.RIGHT); rowL[1] = makeLabel("Top row:", Label.RIGHT); rowL[2] = makeLabel("Home row:", Label.RIGHT); rowL[3] = makeLabel("Bottom row:", Label.RIGHT); rowD = new Label[4]; for (int i=0; i<4; i++) rowD[i] = makeLabel("",Label.RIGHT); fingerL = makeLabel("Finger:",Label.RIGHT); fingerD = makeLabel("",Label.LEFT); // label fonts Font labelFont = new Font("Dialog", Font.PLAIN, 12); for (int i=0; i < allLabels.size(); i++) { try { Label l = (Label) allLabels.elementAt(i); l.setFont(labelFont); } catch (ArrayIndexOutOfBoundsException a) {System.err.println(a);} } Font fingerFont = new Font("Courier", Font.PLAIN, 10); fingerD.setFont(fingerFont); // suggest how to get this layout with gridbag! (or something) // labels for left column Panel leftLabelP = new Panel(); leftLabelP.setLayout(new GridLayout(4,1)); leftLabelP.add(distanceL); leftLabelP.add(sameHandL); leftLabelP.add(sameFingerL); leftLabelP.add(totalKeysL); // data labels for left column Panel leftDataP = new Panel(); leftDataP.setLayout(new GridLayout(4,1)); leftDataP.add(distanceD); leftDataP.add(sameHandD); leftDataP.add(sameFingerD); leftDataP.add(totalKeysD); // labels for right column Panel rightLabelP = new Panel(); rightLabelP.setLayout(new GridLayout(4,1)); for (int i=0; i<4; i++) rightLabelP.add(rowL[i]); // data labels for right column Panel rightDataP = new Panel(); rightDataP.setLayout(new GridLayout(4,1)); for (int i=0; i<4; i++) rightDataP.add(rowD[i]); // left column (labels + data) Panel leftColumnP = new Panel(); leftColumnP.setLayout(new BorderLayout()); leftColumnP.add("West", leftLabelP); leftColumnP.add("Center", leftDataP); // right column (label + data) Panel rightColumnP = new Panel(); rightColumnP.setLayout(new BorderLayout()); rightColumnP.add("West", rightLabelP); rightColumnP.add("Center", rightDataP); // Panel bothColumnsP = new Panel(); bothColumnsP.setLayout(new GridLayout(1,2)); bothColumnsP.add(leftColumnP); bothColumnsP.add(rightColumnP); // finger area Panel fingerP = new Panel(); fingerP.setLayout(new FlowLayout(FlowLayout.LEFT)); fingerP.add(fingerL); fingerP.add(fingerD); setLayout(new BorderLayout()); add("Center", bothColumnsP); add("South", fingerP); } // new Label() and add it to the list of all labels private Label makeLabel(String s, int flags) { Label label = new Label(s,flags); allLabels.addElement(label); return label; } // size of KeyStats panel Dimension size = new Dimension(290,120); public Dimension preferredSize() { return size; } public Dimension minimumSize() { return size; } // calculate stats variables void calculate(String text, Keyboard keyboard) { // reset counters distanceTotal = sameHandTotal = sameFingerTotal = keysTotal = 0; for (int i=0; i < Keyboard.ROWS; i++) rowTotal[i] = 0; for (int i=0; i < 5; i++) { lhTotal[i] = rhTotal[i] = 0; } // double distancePrev = 0.0; int row, col; int rowPrev = -1, colPrev = -1; Finger finger; Finger fingerPrev = null; int fingerNum; int fingerNumPrev = -1; for (int i=0; i < text.length(); i++) { Point k = keyboard.locate(text.charAt(i)); if (k == null) continue; row = k.y; col = k.x; finger = keyboard.closestFinger(row, col); fingerNum = finger.getFingerNum(); // keysTotal keysTotal++; // rowTotal rowTotal[row]++; // rhTotal if (finger.getHand() == Finger.RIGHTHAND) rhTotal[fingerNum]++; // lhTotal if (finger.getHand() == Finger.LEFTHAND) lhTotal[fingerNum]++; // sameHandTotal if (null != fingerPrev) // repeated key doesn't count toward same hand if (row != rowPrev || col != colPrev) if (finger.getHand() == fingerPrev.getHand()) // thumb doesn't count as either hand if (fingerNum != Finger.THUMB && fingerNumPrev != Finger.THUMB) sameHandTotal++; // sameFingerTotal if (null != fingerPrev) // repeated key doesn't count toward same finger // (and so thumb won't ever count since it only hits space) if (row != rowPrev || col != colPrev) if (finger == fingerPrev) sameFingerTotal++; // distanceTotal double distance = keyboard.distanceTo(row, col); if (finger != fingerPrev) { distanceTotal += distancePrev; // prev finger moves back to home distanceTotal += distance; // and this finger moves to key } else { // same finger, so it moves from prev key to this key // note that distancePrev is always the distance from home row // finger to previous key not the distance between these two distanceTotal += keyboard.distanceTo(row,col,rowPrev, colPrev); } // set prev from current distancePrev = distance; fingerPrev = finger; fingerNumPrev = fingerNum; rowPrev = row; colPrev = col; } // for each char displayStats(); } // convert stats into labels private void displayStats() { // total non-space (row 5) keys int top4rowTotal = rowTotal[0] + rowTotal[1] + rowTotal[2] + rowTotal[3]; // keysTotal totalKeysD.setText(Integer.toString(keysTotal)); // row percents // percent of non-space keys for (int i=0; i<4; i++) { if (top4rowTotal > 0) rowD[i].setText( toPercent((double)rowTotal[i]/top4rowTotal,5) ); else rowD[i].setText("0%"); } // finger percents: lhTotal, rhTotal // percent of non-space keys if (top4rowTotal > 0) { String s = ""; for (int i=0; i<4; i++) {s = s.concat(truncLeft(" "+Integer.toString(100*lhTotal[i]/top4rowTotal),3)+"%");} s = s.concat(" -- "); for (int i=0; i<4; i++) {s = s.concat(truncLeft(" "+Integer.toString(100*rhTotal[i]/top4rowTotal),3)+"%");} fingerD.setText(s); } else { fingerD.setText(" 0% 0% 0% 0% -- 0% 0% 0% 0%"); } // distanceTotal distanceD.setText( trunc(Double.toString(distanceTotal),5) + "m"); // same hand percent, same finger percent // percent of non-space keys if (top4rowTotal > 0) { sameHandD.setText( toPercent((double)sameHandTotal/top4rowTotal,5) ); sameFingerD.setText( toPercent((double)sameFingerTotal/top4rowTotal,5) ); } else { sameHandD.setText( "0%" ); sameFingerD.setText( "0%" ); } } // make a len-digit percent from a ratio private String toPercent(double r, int len) { return (trunc(Double.toString(100.0 * r),len) + "%"); } // truncate a string at len length or less private String trunc(String s, int len) { int l = s.length(); if (len < l) { try { return s.substring(0,len); } catch (StringIndexOutOfBoundsException e) {System.err.println(e);} } return s; } // tuncate (from left) a string to len length or less private String truncLeft(String s, int len) { int l = s.length(); if (len < l) { try { return s.substring(l-len); } catch (StringIndexOutOfBoundsException e) {System.err.println(e);} } return s; } }