From: yasuro@is.s.u-tokyo.ac.jp (KAWATA Yasuro)
Subject: FREE texts for blind-typing exercises
Reply-To: yasuro@is.uec.ac.jp
Organization: Dept. of Infomation Science, Univ. of Tokyo, Japan.
Date: Fri, 16 Oct 1992 06:57:36 GMT

I really don't know where to post this article. If it's not relevant
to the newsgroup, I apologize; please don't fume.

I'm teaching 2nd-year undergraduates the very basic of UNIX system
operation and Pascal programming.  Since I believe learning
blind-typing saves a lot of time in the end, I'd like to make available
for my students a tutoring tool for practicing blind-tying. 

I've found this trr.el, an Emacs Lisp package for this purpose. It's
attached at the end of this article for the interested.  It works
great, but the only problem is its texts are Emacs info! It's a kind
of manual supplied with Emacs distribution package.  It's hardly
appropriate for total beginners.  So I have to prepare such exercise
texts by myself.

Such texts should start from "jjjj ffff jjjj ffff" or something like
that; there's no problem in that. It gets a bit delicate when students
get intermediate level---you have to prepare texts which only uses the
home row and the upper row.  It's not easy to make such texts, is it?

There are a bunch of typing textbooks out there with those examples;
but I doubt it is legally OK to copy them and distribute them.  Then
what about if only for classroom use? Are there any FREE and
copyright-free typing examples?  Are there any easy ways of making (as
natural as possible) English texts which uses certain keys on a
keyboard?  

Any comments are welcome.

Yasuro KAWATA
Univ. of Electro-Comm.
JAPAN
yasuro@is.uec.ac.jp

--> cut --> --> cut --> cut --> cut --> cut --> cut --> cut --> cut -->
;;; trr: a type-writing training program on GNU Emacs.
;;;  Copyright (C) 1992 INAMURA, You
;;;     Author:  INAMURA, You (inamura@icot.or.jp)
;;;	Please send suggestions and corrections to the above address.

;;; trr.el  (Version: 1.0 for GNU Emacs Version 18)

;; This software is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY.  No author or distributor
;; accepts responsibility to anyone for the consequences of using it
;; or for whether it serves any particular purpose or works at all,
;; unless he says so in writing.  Refer to the GNU Emacs General Public
;; License for full details.

;; Everyone is granted permission to copy, modify and redistribute
;; this software, but only under the conditions described in the
;; GNU Emacs General Public License.   A copy of this license is
;; supposed to have been given to you along with this software so you
;; can know your rights and responsibilities.  It should be in a
;; file named COPYING.  Among other things, the copyright notice
;; and this notice must be preserved on all copies.

(defvar trr-eval 0)
(defvar trr-max-eval)
(defvar trr-quit-flag nil)
(defvar trr-number-of-lines)
(defvar trr-correct-char-count)
(defvar trr-whole-char-count)
(defvar trr-steps 0)

(defvar trr-default-text-file (concat Info-directory "emacs-1")
  "Use this file as a default text for the type training.")

(defvar trr-text-file trr-default-text-file
  "Text file for the type training.")

(defvar trr-high-score 0)
(defvar trr-random t "If not nil, select the start point at random")

(defvar trr-text-buffer "* TRR Type Trainer *")
(defvar trr-result-buffer "* TRR Result *")
(defvar trr-graph-buffer "* TRR Eval Graph *")

(defvar trr-buffer-width nil)

(defvar trr-text-buffer-height nil)
(defvar trr-result-buffer-height 5)
(defvar trr-graph-buffer-height nil)

(defvar trr-text-lines nil)

(defvar trr-prev-win-conf nil)

(autoload 'picture-move-up "picture" "" nil)
(autoload 'picture-move-down "picture" "" nil)

(defun trr (&optional raw)
  "TRR type trainer. If called with optional argument RAW (universal argument),
the text file is read in as it is.  Otherwise, the text file is filled to
fit with the size of current Emacs' window."
  (interactive "P")
  (setq trr-prev-win-conf (current-window-configuration))
  (setq trr-quit-flag nil)
  (delete-other-windows)
  (trr-prepare-buffers raw)
  (unwind-protect
      (let ((random-steps (if trr-random
			      (if (> trr-number-of-lines 1)
				  (% (trr-random-num) 
				     (/ trr-number-of-lines 2))
				0)
			    (min (* trr-steps trr-text-lines)
				 (/ trr-number-of-lines 2))))
	    (next-step 3)
	    (started nil))
	(forward-line (* next-step random-steps))
	(recenter 0)
	(while (and (not trr-quit-flag)
		    (if (not started)
			(if (y-or-n-p "Are you ready? ")
			    t
			  (if (y-or-n-p "Really want to exit? ")
			      nil
			    t))
		      (if (y-or-n-p "Continue? ")
			  t
			(if (y-or-n-p "Really want to exit? ")
			    nil
			  t))))
	  (if (not started)
	      (setq started t)
	    (forward-line (1- next-step)))
	  (save-excursion
	    (narrow-to-region
	     (point)
	     (progn
	       (forward-line (* next-step trr-text-lines))
	       (point))))
	  (forward-line 1)
	  (setq trr-correct-char-count 0)
	  (setq trr-whole-char-count 0)
	  (trr-one-session)
	  (widen)))
    (trr-finish)))

(defun trr-prepare-buffers (&optional raw)
  (if (< (window-height) 13)
      (error
       "Emacs window should have at least 14 rows to run this program!!"))
  (let ((height (- (window-height) 5)))
    (setq trr-text-buffer-height
	  (1+ (if (> height 19)
		  (- (/ height 2)
		     (% (/ height 2) 3))
		(- (- height 5)
		   (% (- height 5) 3)))))
    (setq trr-graph-buffer-height
	  (- height trr-text-buffer-height)))
  (setq trr-text-lines (/ (1- trr-text-buffer-height) 3))
  (setq trr-buffer-width (window-width))
  (set-buffer (get-buffer-create trr-text-buffer))
  (if (not (zerop (buffer-size)))
      (erase-buffer))
  (trr-read-file raw)
  (switch-to-buffer trr-text-buffer)
  (split-window (get-buffer-window (current-buffer))
		trr-text-buffer-height)
  (set-buffer (get-buffer-create trr-result-buffer))
  (erase-buffer)
  (insert "Elapsed Time        |  \n"
	  "Mistype Ratio       |  \n"
	  "Strokes/Minute      |  \n"
	  "Evaluation          |  ")
  (switch-to-buffer-other-window trr-result-buffer)
  (split-window (get-buffer-window (current-buffer))
		5)
  (other-window 1)
  (switch-to-buffer (get-buffer-create trr-graph-buffer))
  (trr-make-eval-graph)
  (recenter -1)
  (other-window 1))


(defun trr-finish ()
  (interactive)
  (if (get-buffer trr-text-buffer)
      (kill-buffer trr-text-buffer))
  (if (get-buffer trr-result-buffer)
      (kill-buffer trr-result-buffer))
  (if (get-buffer trr-graph-buffer)
      (kill-buffer trr-graph-buffer))
  (set-buffer (get-file-buffer 
	       (expand-file-name "~/.trrrc")))
  (if (buffer-modified-p) (save-buffer))
  (kill-buffer (current-buffer))
  (set-window-configuration trr-prev-win-conf))

(defun trr-one-session ()
  (if (eobp) t
    (let ((inhibit-quit 't)
	  (echo-keystrokes 0)
	  (lines (/ (count-lines (point-min) (point-max))
		    3))
	  (text-pos (save-excursion
		      (forward-line -1)
		      (point)))
	  (started nil)
	  ch start end)
      (setq ch (read-char))
      (setq start (current-time-string))
      (while (and (> lines 0)
		  (/= ch 3))   ;; if ch = ^C then quit
	(setq trr-whole-char-count (1+ trr-whole-char-count))
	(if (= ch (char-after text-pos))
	    (progn
	      (setq trr-correct-char-count (+ trr-correct-char-count 1))
	      (setq text-pos (1+ text-pos))
	      (if (/= ch 13)
		  (progn
		    (insert-char ch 1)
		    (setq ch (read-char)))
		(insert-char 13 1)         ; cr mark
		(setq lines (1- lines))
		(if (/= lines 0)
		    (progn (forward-line 3)
			   (setq text-pos (save-excursion
					    (forward-line -1) (point)))
			   (setq ch (read-char))))))
	  (if (= ch 10)
	      (insert " ")
	    (if (= ch 12)
		(redraw-display)
	      (if (= ch 7)
		  (setq quit-flag 'nil)))
	    (insert-char ch 1))
	  (backward-char 1)
	  (while (and (/= ch (char-after text-pos))
		      (/= ch  3))
	    (setq ch (read-char))
	    (delete-char 1)
	    (if (= ch 10)
		(insert " ")
	      (if (= ch 12)
		  (redraw-display)
		(if (= ch 7)
		    (setq quit-flag 'nil)))
	      (insert-char ch 1))
	    (backward-char 1))
	  (picture-move-down 1)
	  (insert "^")
	  (forward-line -1)
	  (end-of-line)
	  (backward-delete-char 1)
	  (setq text-pos (1+ text-pos))
	  (if (/= ch 13)
	      (if (= ch 3)
		  (setq lines 0)
		(insert-char ch 1)        ; blink or reverse mode, if possible
		(setq ch (read-char)))
	    (setq lines (1- lines))
	    (insert-char 13 1)             ; cr mark
	    (if (/= lines 0)
		(progn (forward-line 3)
		       (setq text-pos (save-excursion
				       (forward-line -1) (point)))
		       (setq ch (read-char)))))))
      (setq end (current-time-string))
      (recenter -2)
      (if (= ch 3)			; if ch = '^C' then quit immediately
	  (setq trr-quit-flag t)
	(setq trr-quit-flag nil)
	(trr-check-elapsed-time start end
				trr-whole-char-count
				trr-correct-char-count)))))

(defun trr-check-elapsed-time (s e w crct)
  (let* (diff
	 (started-from (trr-convert-time-string-to-second s))
	 (ended-at (trr-convert-time-string-to-second e))
	 (elapsed (- ended-at started-from)))
    (if (< ended-at started-from)
	(setq elapsed (+ elapsed 86400)))
    (other-window 1)
    (erase-buffer)
    (insert (format "Elapsed Time        |  %d sec\n" elapsed)
	    (format "Mistype Ratio       |  %d.%d %s (%d / %d)\n"
		    (/ (* 100 (setq diff (- w crct))) w)
		    (% (/ (* 10000 diff) w) 100) "%" diff w)
	    (format "Strokes/Minute      |  %d\n" (/ (* w 60) elapsed))
	    (format "Evaluation          |  %d"
		    (setq trr-eval (/ (* crct 60) elapsed)))
	    (if (>= trr-eval (* 10 (1+ trr-steps)))
		(progn (setq pass 't) "    Pass")
	      (setq pass 'nil) "   Re-try"))
    (goto-char (point-min))
    (other-window 1)
    (if (> trr-eval trr-max-eval)
	(progn
	  (setq trr-max-eval trr-eval)
	  (save-excursion
	    (set-buffer (get-file-buffer (expand-file-name "~/.trrrc")))
	    (goto-char (point-max))
	    (if (not pass)
		(delete-region (point) (progn (forward-line -1) (point))))
	    (insert (int-to-string trr-eval) "\n")
	    (setq trr-steps (1+ trr-steps)))
	  (trr-write-graph))
      (if pass
	  (progn
	    (save-excursion
	      (set-buffer (get-file-buffer (expand-file-name "~/.trrrc")))
	      (goto-char (point-max))
	      (insert (int-to-string trr-eval) "\n"))
	    (setq trr-steps (1+ trr-steps))
	    (if (> trr-steps (* trr-horizontal-steps trr-scale-x))
		(trr-write-graph)
	      (trr-update-graph)))))
    (other-window 1)))

(defun trr-update-graph()
  (save-excursion
    (goto-char (point-min))
    (delete-region (point)
		   (progn (end-of-line) (point)))
    (insert (int-to-string (1+ trr-steps)) " Step")
    (center-region (point-min) (point)))
  (save-excursion
    (if (>= trr-graph-steps 2)
	(let ((inter (max 1 (/ trr-scale-x 4))))
	  (if (= 0 (% trr-steps inter))
	      (progn
		(let ((height (/ trr-eval (* 5 trr-scale-y)))
		      (times (max 1 (/ 4 trr-scale-x))))
		  (forward-char (/ (* trr-steps times) inter))
		  (if (> (- trr-eval (* height (* 5 trr-scale-y)))
			 (/ (* 5 trr-scale-y) 2))
		      (setq height (1+ height)))
		  (picture-move-up (1+ height))
		  (insert "*"))))))))

(defun trr-convert-time-string-to-second (st)
  (let ((hr (string-to-int (substring st 11 13))) ; $@2?;~!)(J
	(min (string-to-int (substring st 14 16))) ; $@2?J,!)(J
	(sec (string-to-int (substring st 17 19)))) ; $@2?IC!)(J
    (+ sec (* 60 (+ min (* 60 hr))))))
  
(defun trr-read-file (&optional raw)
  (message "Reading TRR text file...")
  (if (not raw)
      (let ((fill-column (- trr-buffer-width 3)))
	(call-process "sed"  trr-text-file t nil
		      "-e" "/^$/d"
		      "-e" "s/	/ /g"
		      "-e" "s/   */  /g")
	(fill-region (point-min) (point-max)))
    (call-process "sed" trr-text-file t nil
		  "/^[	 ]*$/d")
    (untabify (point-min) (point-max)))
  (setq trr-number-of-lines (count-lines (point-min) (point-max)))
  (goto-char (point-min))
  (while (not (eobp))
    (end-of-line)
    (insert-char 13 1)
    (insert "\n\n")
    (forward-line 1))
  (goto-char (point-min))
  (message "Reading TRR text file... done."))

(defun trr-make-eval-graph ()
  (message "Creating evaluation graph ...")
  (setq trr-max-eval 0)
  (find-file (expand-file-name "~/.trrrc"))
  (setq trr-steps (count-lines (point-min) (point-max)))
  (goto-char (point-min))
  (let (score)
    (while (not (eobp))
      (setq score (string-to-int
		    (buffer-substring (point)
				      (progn (end-of-line) (point)))))
      (if (> score trr-max-eval)
	  (setq trr-max-eval score))
      (forward-line 1)))
  (bury-buffer)
  (trr-write-graph)
  (message "Creating evaluation graph ... done."))

(defun trr-write-graph ()
  (erase-buffer)
  (setq trr-graph-steps (/ (- trr-graph-buffer-height 6) 2)
	trr-horizontal-steps (/ (- trr-buffer-width 8) 4)
	trr-scale-x (let ((i trr-horizontal-steps))
		      (while (< i trr-steps)
			(setq i (* i 2)))
		      (/ i trr-horizontal-steps))
	trr-scale-y (1+ (/ (1- trr-max-eval) 
			   (* (if (> trr-graph-steps 0) trr-graph-steps 1)
			      10)))
	fill-column trr-buffer-width)
  (insert (int-to-string (1+ trr-steps)) " Step\n"
	  "Max Evaluation$@!'(J" (int-to-string trr-max-eval) "\n")
  (center-region (point-min) (point-max))
  (if (< trr-graph-steps 2)
      t
    (let ((i trr-graph-steps))
      (while (> i 0)
	(insert "     |\n" (format "%4d" (* i 10 trr-scale-y)) " +\n")
	(setq i (1- i)))
      (insert "     |\n" "   0 +-")
      (while (< i trr-horizontal-steps)
	(insert "--+-")
	(setq i (1+ i)))
      (insert "\n" "     0")
      (setq i 1)
      (while (<= i trr-horizontal-steps)
	(insert (format "%4d" (* i trr-scale-x)))
	(setq i (1+ i))))
    (goto-char (point-max))
    (beginning-of-line)
    (forward-char 5)
    (let ((cur-buf (current-buffer))
	  (res-buf (get-file-buffer (expand-file-name "~/.trrrc")))
	  (times (max 1 (/ 4 trr-scale-x)))
	  (inter (max 1 (/ trr-scale-x 4)))
	  (i 1)
	  data height)
      (save-excursion
	(set-buffer res-buf)
	(goto-char (point-min))
	(while (and (= (forward-line (- inter 1)) 0)
		    (not (eobp)))
	  (setq height (/ (setq data 
				(string-to-int
				 (buffer-substring (point)
						   (progn
						     (forward-line 1)
						     (point)))))
			  (* 5 trr-scale-y)))
	  (if (> (- data (* height (* 5 trr-scale-y)))
		 (/ (* 5 trr-scale-y) 2))
	      (setq height (1+ height)))
	  (set-buffer cur-buf)
	  (forward-char times)
	  (save-excursion
	    (picture-move-up (1+ height))
	    (insert "*"))
	  (setq i (1+ i))
	  (set-buffer res-buf))))))

(defun trr-random-num ()
  (let ((num (/ (random t) 10)))
    (if (> num 0) num (- num))))