Steve Thielemann пре 2 година
родитељ
комит
8c85eb4be9
6 измењених фајлова са 516 додато и 425 уклоњено
  1. 4 2
      door/door_test.go
  2. 2 1
      door/help_test.go
  3. 342 0
      door/input.go
  4. 0 341
      door/input_linux.go
  5. 103 28
      door/input_windows.go
  6. 65 53
      door/write_windows.go

+ 4 - 2
door/door_test.go

@@ -429,7 +429,10 @@ func InputTests(t *testing.T, server net.Conn, d *Door, mode string) {
 
 	expected := "     \x08\x08\x08\x08\x0812345\x07\x07\x07\x07"
 	if result != expected {
-		t.Errorf("Buffer Input(5): Expected %#v, got %#v\n", expected, result)
+		expected = "     \x08\x08\x08\x08\x0812345\x07\x07\x07\x07\x07"
+		if result != expected {
+			t.Errorf("Buffer Input(5): Expected %#v, got %#v\n", expected, result)
+		}
 	}
 	err = server.SetReadDeadline(time.Time{})
 	if err != nil {
@@ -785,7 +788,6 @@ func TestDoorUnicode(t *testing.T) {
 	log.Println("server close")
 
 	server.Close()
-
 	time.Sleep(time.Millisecond)
 
 	_, _, err = d.WaitKey(keyWait)

+ 2 - 1
door/help_test.go

@@ -59,7 +59,8 @@ func clear_socket(socket net.Conn, t *testing.T) string {
 	}
 	r, err = socket.Read(buffer)
 	if err != nil {
-		t.Errorf("socket.Read: %#v", err)
+		// DeadlineExceedError
+		t.Logf("socket.Read: %#v", err)
 	}
 	// t.Errorf("Buffer : %#v\n", buffer[:r])
 	err = socket.SetReadDeadline(time.Time{})

+ 342 - 0
door/input.go

@@ -17,6 +17,348 @@ var ErrDisconnected error = fmt.Errorf("Disconnected")
 
 var DefaultTimeout time.Duration = time.Duration(60) * time.Second
 
+// put the common input routines here
+var readerBuffer []rune
+
+// Translate these extended codes into these Extended values.
+var extendedKeys map[string]Extended = map[string]Extended{
+	"[A":   UP_ARROW,
+	"[B":   DOWN_ARROW,
+	"[C":   RIGHT_ARROW,
+	"[D":   LEFT_ARROW,
+	"[H":   HOME,
+	"[F":   END, // terminal
+	"[K":   END,
+	"[V":   PAGE_UP,
+	"[U":   PAGE_DOWN,
+	"[@":   INSERT,
+	"[2~":  INSERT,    // terminal
+	"[3~":  DELETE,    // terminal
+	"[5~":  PAGE_UP,   // terminal
+	"[6~":  PAGE_DOWN, // terminal
+	"[15~": F5,        // terminal
+	"[17~": F6,        // terminal
+	"[18~": F7,        // terminal
+	"[19~": F8,        // terminal
+	"[20~": F9,        // terminal
+	"[21~": F10,       // terminal
+	"[23~": F11,
+	"[24~": F12, // terminal
+	"OP":   F1,
+	"OQ":   F2,
+	"OR":   F3,
+	"OS":   F4, // syncterm "[1" = F1,F2,F3, and F4)
+	"Ot":   F5, // syncterm
+}
+
+func process(d *Door, newRune bool) {
+	// This is like GetKey
+	var rlen int
+	var r, r2 rune
+	var has2 bool
+	var done bool = false
+
+	for !done {
+		rlen = len(readerBuffer)
+		if rlen == 0 {
+			// Nothing to do here
+			return
+		}
+
+		if DEBUG_INPUT {
+			log.Println("rlen:", rlen, "readerBuffer:", readerBuffer, "newRune:", newRune)
+		}
+
+		r = readerBuffer[0]
+		if rlen >= 2 {
+			r2 = readerBuffer[1]
+			has2 = true
+		} else {
+			r2 = unicode.ReplacementChar
+			has2 = false
+		}
+
+		// if !has2 and !newRune, then we're "done" (received everything,
+		// and there's nothing else coming...)
+
+		// fyneterm CR
+		if r == '\x0a' {
+			if !has2 && !newRune {
+				ArrayPop(&readerBuffer, 1)
+				d.readerChannel <- ReaderData{R: '\x0d', Ex: NOP, Err: nil}
+				return
+			}
+
+			if has2 {
+				ArrayPop(&readerBuffer, 1)
+				if r2 == '\x00' || r2 == '\x0a' {
+					ArrayPop(&readerBuffer, 1)
+				}
+				d.readerChannel <- ReaderData{R: '\x0d', Ex: NOP, Err: nil}
+			} else {
+				// We don't have a 2nd rune, and we haven't timed out.
+				return
+			}
+
+			continue
+		}
+
+		// We get 0x0d, 0x00, or 0x0d 0x0a from syncterm
+		if r == '\x0d' {
+			if !has2 && !newRune {
+				ArrayPop(&readerBuffer, 1)
+				d.readerChannel <- ReaderData{R: r, Ex: NOP, Err: nil}
+				return
+			}
+
+			if has2 {
+				ArrayPop(&readerBuffer, 1)
+				if r2 == '\x00' || r2 == '\x0a' {
+					ArrayPop(&readerBuffer, 1)
+				}
+				d.readerChannel <- ReaderData{R: r, Ex: NOP, Err: nil}
+			} else {
+				return
+			}
+
+			continue
+		}
+
+		if r == '\x00' {
+			// Possibly doorway mode - deprecated?
+			// syncterm does support this.
+
+			if !has2 && !newRune {
+				// timeout
+				ArrayPop(&readerBuffer, 1)
+				d.readerChannel <- ReaderData{R: r, Ex: NOP, Err: nil}
+				return
+			}
+
+			if has2 {
+				ArrayPop(&readerBuffer, 2)
+				switch r2 {
+				case '\x50':
+					d.readerChannel <- ReaderData{0, DOWN_ARROW, nil}
+				case '\x48':
+					d.readerChannel <- ReaderData{0, UP_ARROW, nil}
+				case '\x4b':
+					d.readerChannel <- ReaderData{0, LEFT_ARROW, nil}
+				case 0x4d:
+					d.readerChannel <- ReaderData{0, RIGHT_ARROW, nil}
+				case 0x47:
+					d.readerChannel <- ReaderData{0, HOME, nil}
+				case 0x4f:
+					d.readerChannel <- ReaderData{0, END, nil}
+				case 0x49:
+					d.readerChannel <- ReaderData{0, PAGE_UP, nil}
+				case 0x51:
+					d.readerChannel <- ReaderData{0, PAGE_DOWN, nil}
+				case 0x3b:
+					d.readerChannel <- ReaderData{0, F1, nil}
+				case 0x3c:
+					d.readerChannel <- ReaderData{0, F2, nil}
+				case 0x3d:
+					d.readerChannel <- ReaderData{0, F3, nil}
+				case 0x3e:
+					d.readerChannel <- ReaderData{0, F4, nil}
+				case 0x3f:
+					d.readerChannel <- ReaderData{0, F5, nil}
+				case 0x40:
+					d.readerChannel <- ReaderData{0, F6, nil}
+				case 0x41:
+					d.readerChannel <- ReaderData{0, F7, nil}
+				case 0x42:
+					d.readerChannel <- ReaderData{0, F8, nil}
+				case 0x43:
+					d.readerChannel <- ReaderData{0, F9, nil}
+				case 0x44:
+					d.readerChannel <- ReaderData{0, F10, nil}
+
+				case 0x45:
+					d.readerChannel <- ReaderData{0, F11, nil}
+				case 0x46:
+					d.readerChannel <- ReaderData{0, F12, nil}
+
+				case 0x52:
+					d.readerChannel <- ReaderData{0, INSERT, nil}
+				case 0x53:
+					d.readerChannel <- ReaderData{0, DELETE, nil}
+				default:
+					log.Printf("ERROR Doorway mode: 0x00 %x\n", r2)
+					d.readerChannel <- ReaderData{0, UNKNOWN, nil}
+
+				}
+			} else {
+				return
+			}
+			continue
+		} // end doorway mode
+
+		if r == '\x1b' {
+			// Escape key, or ?
+			// This is a little harder, since we don't know how many we need.
+			if !has2 && !newRune {
+				ArrayPop(&readerBuffer, 1)
+				d.readerChannel <- ReaderData{r, NOP, nil}
+				return
+			}
+
+			if has2 {
+				// We at least have the 2nd one...
+				if r2 == '\x1b' {
+					ArrayPop(&readerBuffer, 1)
+					d.readerChannel <- ReaderData{r, NOP, nil}
+					continue
+				}
+
+				// Can't distinguish between \x1bO and \x1bOP (F1)
+				/*
+					if unicode.IsLetter(r2) {
+						// ALT-KEY
+						if unicode.IsLower(r2) {
+							ArrayPop(&readerBuffer, 2)
+							ex := Extended(int(ALT_a) + int(r2-'a'))
+							d.readerChannel <- ReaderData{0, ex, nil}
+						} else {
+							// Must be upper
+							ArrayPop(&readerBuffer, 2)
+							ex := Extended(int(ALT_A) + int(r2-'A'))
+							d.readerChannel <- ReaderData{0, ex, nil}
+						}
+						continue
+					}
+				*/
+
+				var extended []rune = make([]rune, 0, 10)
+				extended = append(extended, r2)
+				var extlen = 2 // Length of codes to remove on successful match.
+				var pos = 2    // Where we get the next rune from
+				var isMouse bool = false
+				var found bool = false
+
+				if DEBUG_INPUT {
+					log.Println(pos, readerBuffer)
+				}
+
+				for pos < rlen {
+					r2 = readerBuffer[pos]
+
+					pos++
+					extlen++
+
+					extended = append(extended, r2)
+
+					if DEBUG_INPUT {
+						log.Println("0x1b LOOP pos:", pos, "extlen:", extlen, "extended:", string(extended))
+					}
+
+					ext, has := extendedKeys[string(extended)]
+					if has {
+						// Found it!
+						if DEBUG_INPUT {
+							log.Println("Found Extended Match:", ext.String())
+						}
+						ArrayPop(&readerBuffer, extlen)
+						d.readerChannel <- ReaderData{0, ext, nil}
+						found = true
+						break
+					}
+
+					// Mouse codes can also contain letters.
+					if !isMouse && unicode.IsLetter(r2) {
+						// end of extended code, unless mouse!
+						if DEBUG_INPUT {
+							log.Println("not mouse, is letter...")
+						}
+						if string(extended) == "[M" {
+							isMouse = true
+						} else {
+							break
+						}
+					}
+
+					if isMouse && len(extended) == 5 {
+						break
+					}
+				}
+
+				if found {
+					continue
+				}
+
+				if DEBUG_INPUT {
+					log.Println("POS:", pos, "EXLEN:", extlen, "Extended:", extended, "readerBuffer:", readerBuffer)
+					log.Printf("(possible) Extended Code: [%s]", extended_output(extended))
+				}
+
+				var exString string = string(extended)
+				if strings.HasPrefix(exString, "[M") && len(extended) == 5 {
+					// Yes, "valid"
+					ArrayPop(&readerBuffer, extlen)
+					// Mouse Extended - input zero based (I add +1 to X, Y, and button)
+					var mouse Mouse = Mouse{Button: RuneToInt8(extended[2]) - ' ' + 1,
+						X: RuneToInt8(extended[3]) - '!' + 1,
+						Y: RuneToInt8(extended[4]) - '!' + 1}
+					d.AddMouse(mouse)
+					log.Println("Mouse:", mouse)
+					d.readerChannel <- ReaderData{0, MOUSE, nil}
+					continue
+				}
+
+				if strings.HasSuffix(exString, "R") {
+					// yes, "valid"
+					ArrayPop(&readerBuffer, extlen)
+					// Cursor Position information (or Shift-F3)
+					var cursor CursorPos
+					// ^[[1;1R^[[2;3r^[[41;173R
+					// Y;X
+					exString = exString[1 : len(exString)-1] // Remove [ and R
+					pos := SplitToInt(exString, ";")
+					if len(pos) == 2 {
+						cursor.X = pos[1]
+						cursor.Y = pos[0]
+						d.AddCursorPos(cursor)
+						/*
+							d.mcMutex.Lock()
+							d.LastCursor = append(d.LastCursor, cursor)
+							d.mcMutex.Unlock()
+						*/
+						log.Println("Cursor Pos:", cursor)
+						d.readerChannel <- ReaderData{0, CURSOR, nil}
+						continue
+					} else {
+						log.Println("ERROR Cursor Pos:", extended)
+						d.readerChannel <- ReaderData{0, UNKNOWN, nil}
+						continue
+					}
+				}
+
+				// Ok, this LOOKS like something invalid...
+				if !newRune {
+					// Yes, this is invalid.
+					ArrayPop(&readerBuffer, extlen)
+					log.Println("ERROR Extended:", extended)
+					d.readerChannel <- ReaderData{0, UNKNOWN, nil}
+				} else {
+					if DEBUG_INPUT {
+						log.Println("(Possibly) invalid extended:", extended)
+					}
+					return
+				}
+
+			} else {
+				return
+			}
+			continue
+		}
+
+		ArrayPop(&readerBuffer, 1)
+		d.readerChannel <- ReaderData{r, NOP, nil}
+		continue
+	}
+}
+
 func (d *Door) WaitKey(timeout time.Duration) (rune, Extended, error) {
 	/*
 		d.readerMutex.Lock()

+ 0 - 341
door/input_linux.go

@@ -39,347 +39,6 @@ func RuneToInt8(r rune) int8 {
 
 const READ_SIZE = 16 // Size of read buffer
 
-var readerBuffer []rune
-
-// Translate these extended codes into these Extended values.
-var extendedKeys map[string]Extended = map[string]Extended{
-	"[A":   UP_ARROW,
-	"[B":   DOWN_ARROW,
-	"[C":   RIGHT_ARROW,
-	"[D":   LEFT_ARROW,
-	"[H":   HOME,
-	"[F":   END, // terminal
-	"[K":   END,
-	"[V":   PAGE_UP,
-	"[U":   PAGE_DOWN,
-	"[@":   INSERT,
-	"[2~":  INSERT,    // terminal
-	"[3~":  DELETE,    // terminal
-	"[5~":  PAGE_UP,   // terminal
-	"[6~":  PAGE_DOWN, // terminal
-	"[15~": F5,        // terminal
-	"[17~": F6,        // terminal
-	"[18~": F7,        // terminal
-	"[19~": F8,        // terminal
-	"[20~": F9,        // terminal
-	"[21~": F10,       // terminal
-	"[23~": F11,
-	"[24~": F12, // terminal
-	"OP":   F1,
-	"OQ":   F2,
-	"OR":   F3,
-	"OS":   F4, // syncterm "[1" = F1,F2,F3, and F4)
-	"Ot":   F5, // syncterm
-}
-
-func process(d *Door, newRune bool) {
-	// This is like GetKey
-	var rlen int
-	var r, r2 rune
-	var has2 bool
-	var done bool = false
-
-	for !done {
-		rlen = len(readerBuffer)
-		if rlen == 0 {
-			// Nothing to do here
-			return
-		}
-
-		if DEBUG_INPUT {
-			log.Println("rlen:", rlen, "readerBuffer:", readerBuffer, "newRune:", newRune)
-		}
-
-		r = readerBuffer[0]
-		if rlen >= 2 {
-			r2 = readerBuffer[1]
-			has2 = true
-		} else {
-			r2 = unicode.ReplacementChar
-			has2 = false
-		}
-
-		// if !has2 and !newRune, then we're "done" (received everything,
-		// and there's nothing else coming...)
-
-		// fyneterm CR
-		if r == '\x0a' {
-			if !has2 && !newRune {
-				ArrayPop(&readerBuffer, 1)
-				d.readerChannel <- ReaderData{R: '\x0d', Ex: NOP, Err: nil}
-				return
-			}
-
-			if has2 {
-				ArrayPop(&readerBuffer, 1)
-				if r2 == '\x00' || r2 == '\x0a' {
-					ArrayPop(&readerBuffer, 1)
-				}
-				d.readerChannel <- ReaderData{R: '\x0d', Ex: NOP, Err: nil}
-			} else {
-				// We don't have a 2nd rune, and we haven't timed out.
-				return
-			}
-
-			continue
-		}
-
-		// We get 0x0d, 0x00, or 0x0d 0x0a from syncterm
-		if r == '\x0d' {
-			if !has2 && !newRune {
-				ArrayPop(&readerBuffer, 1)
-				d.readerChannel <- ReaderData{R: r, Ex: NOP, Err: nil}
-				return
-			}
-
-			if has2 {
-				ArrayPop(&readerBuffer, 1)
-				if r2 == '\x00' || r2 == '\x0a' {
-					ArrayPop(&readerBuffer, 1)
-				}
-				d.readerChannel <- ReaderData{R: r, Ex: NOP, Err: nil}
-			} else {
-				return
-			}
-
-			continue
-		}
-
-		if r == '\x00' {
-			// Possibly doorway mode - deprecated?
-			// syncterm does support this.
-
-			if !has2 && !newRune {
-				// timeout
-				ArrayPop(&readerBuffer, 1)
-				d.readerChannel <- ReaderData{R: r, Ex: NOP, Err: nil}
-				return
-			}
-
-			if has2 {
-				ArrayPop(&readerBuffer, 2)
-				switch r2 {
-				case '\x50':
-					d.readerChannel <- ReaderData{0, DOWN_ARROW, nil}
-				case '\x48':
-					d.readerChannel <- ReaderData{0, UP_ARROW, nil}
-				case '\x4b':
-					d.readerChannel <- ReaderData{0, LEFT_ARROW, nil}
-				case 0x4d:
-					d.readerChannel <- ReaderData{0, RIGHT_ARROW, nil}
-				case 0x47:
-					d.readerChannel <- ReaderData{0, HOME, nil}
-				case 0x4f:
-					d.readerChannel <- ReaderData{0, END, nil}
-				case 0x49:
-					d.readerChannel <- ReaderData{0, PAGE_UP, nil}
-				case 0x51:
-					d.readerChannel <- ReaderData{0, PAGE_DOWN, nil}
-				case 0x3b:
-					d.readerChannel <- ReaderData{0, F1, nil}
-				case 0x3c:
-					d.readerChannel <- ReaderData{0, F2, nil}
-				case 0x3d:
-					d.readerChannel <- ReaderData{0, F3, nil}
-				case 0x3e:
-					d.readerChannel <- ReaderData{0, F4, nil}
-				case 0x3f:
-					d.readerChannel <- ReaderData{0, F5, nil}
-				case 0x40:
-					d.readerChannel <- ReaderData{0, F6, nil}
-				case 0x41:
-					d.readerChannel <- ReaderData{0, F7, nil}
-				case 0x42:
-					d.readerChannel <- ReaderData{0, F8, nil}
-				case 0x43:
-					d.readerChannel <- ReaderData{0, F9, nil}
-				case 0x44:
-					d.readerChannel <- ReaderData{0, F10, nil}
-
-				case 0x45:
-					d.readerChannel <- ReaderData{0, F11, nil}
-				case 0x46:
-					d.readerChannel <- ReaderData{0, F12, nil}
-
-				case 0x52:
-					d.readerChannel <- ReaderData{0, INSERT, nil}
-				case 0x53:
-					d.readerChannel <- ReaderData{0, DELETE, nil}
-				default:
-					log.Printf("ERROR Doorway mode: 0x00 %x\n", r2)
-					d.readerChannel <- ReaderData{0, UNKNOWN, nil}
-
-				}
-			} else {
-				return
-			}
-			continue
-		} // end doorway mode
-
-		if r == '\x1b' {
-			// Escape key, or ?
-			// This is a little harder, since we don't know how many we need.
-			if !has2 && !newRune {
-				ArrayPop(&readerBuffer, 1)
-				d.readerChannel <- ReaderData{r, NOP, nil}
-				return
-			}
-
-			if has2 {
-				// We at least have the 2nd one...
-				if r2 == '\x1b' {
-					ArrayPop(&readerBuffer, 1)
-					d.readerChannel <- ReaderData{r, NOP, nil}
-					continue
-				}
-
-				// Can't distinguish between \x1bO and \x1bOP (F1)
-				/*
-					if unicode.IsLetter(r2) {
-						// ALT-KEY
-						if unicode.IsLower(r2) {
-							ArrayPop(&readerBuffer, 2)
-							ex := Extended(int(ALT_a) + int(r2-'a'))
-							d.readerChannel <- ReaderData{0, ex, nil}
-						} else {
-							// Must be upper
-							ArrayPop(&readerBuffer, 2)
-							ex := Extended(int(ALT_A) + int(r2-'A'))
-							d.readerChannel <- ReaderData{0, ex, nil}
-						}
-						continue
-					}
-				*/
-
-				var extended []rune = make([]rune, 0, 10)
-				extended = append(extended, r2)
-				var extlen = 2 // Length of codes to remove on successful match.
-				var pos = 2    // Where we get the next rune from
-				var isMouse bool = false
-				var found bool = false
-
-				if DEBUG_INPUT {
-					log.Println(pos, readerBuffer)
-				}
-
-				for pos < rlen {
-					r2 = readerBuffer[pos]
-
-					pos++
-					extlen++
-
-					extended = append(extended, r2)
-
-					if DEBUG_INPUT {
-						log.Println("0x1b LOOP pos:", pos, "extlen:", extlen, "extended:", string(extended))
-					}
-
-					ext, has := extendedKeys[string(extended)]
-					if has {
-						// Found it!
-						if DEBUG_INPUT {
-							log.Println("Found Extended Match:", ext.String())
-						}
-						ArrayPop(&readerBuffer, extlen)
-						d.readerChannel <- ReaderData{0, ext, nil}
-						found = true
-						break
-					}
-
-					// Mouse codes can also contain letters.
-					if !isMouse && unicode.IsLetter(r2) {
-						// end of extended code, unless mouse!
-						if DEBUG_INPUT {
-							log.Println("not mouse, is letter...")
-						}
-						if string(extended) == "[M" {
-							isMouse = true
-						} else {
-							break
-						}
-					}
-
-					if isMouse && len(extended) == 5 {
-						break
-					}
-				}
-
-				if found {
-					continue
-				}
-
-				if DEBUG_INPUT {
-					log.Println("POS:", pos, "EXLEN:", extlen, "Extended:", extended, "readerBuffer:", readerBuffer)
-					log.Printf("(possible) Extended Code: [%s]", extended_output(extended))
-				}
-
-				var exString string = string(extended)
-				if strings.HasPrefix(exString, "[M") && len(extended) == 5 {
-					// Yes, "valid"
-					ArrayPop(&readerBuffer, extlen)
-					// Mouse Extended - input zero based (I add +1 to X, Y, and button)
-					var mouse Mouse = Mouse{Button: RuneToInt8(extended[2]) - ' ' + 1,
-						X: RuneToInt8(extended[3]) - '!' + 1,
-						Y: RuneToInt8(extended[4]) - '!' + 1}
-					d.AddMouse(mouse)
-					log.Println("Mouse:", mouse)
-					d.readerChannel <- ReaderData{0, MOUSE, nil}
-					continue
-				}
-
-				if strings.HasSuffix(exString, "R") {
-					// yes, "valid"
-					ArrayPop(&readerBuffer, extlen)
-					// Cursor Position information (or Shift-F3)
-					var cursor CursorPos
-					// ^[[1;1R^[[2;3r^[[41;173R
-					// Y;X
-					exString = exString[1 : len(exString)-1] // Remove [ and R
-					pos := SplitToInt(exString, ";")
-					if len(pos) == 2 {
-						cursor.X = pos[1]
-						cursor.Y = pos[0]
-						d.AddCursorPos(cursor)
-						/*
-							d.mcMutex.Lock()
-							d.LastCursor = append(d.LastCursor, cursor)
-							d.mcMutex.Unlock()
-						*/
-						log.Println("Cursor Pos:", cursor)
-						d.readerChannel <- ReaderData{0, CURSOR, nil}
-						continue
-					} else {
-						log.Println("ERROR Cursor Pos:", extended)
-						d.readerChannel <- ReaderData{0, UNKNOWN, nil}
-						continue
-					}
-				}
-
-				// Ok, this LOOKS like something invalid...
-				if !newRune {
-					// Yes, this is invalid.
-					ArrayPop(&readerBuffer, extlen)
-					log.Println("ERROR Extended:", extended)
-					d.readerChannel <- ReaderData{0, UNKNOWN, nil}
-				} else {
-					if DEBUG_INPUT {
-						log.Println("(Possibly) invalid extended:", extended)
-					}
-					return
-				}
-
-			} else {
-				return
-			}
-			continue
-		}
-
-		ArrayPop(&readerBuffer, 1)
-		d.readerChannel <- ReaderData{r, NOP, nil}
-		continue
-	}
-}
-
 // go routine Reader for input
 // This "times out" every ReaderTimeval
 func Reader(d *Door) {

+ 103 - 28
door/input_windows.go

@@ -1,14 +1,48 @@
 package door
 
+// #cgo LDFLAGS: -lws2_32
+// #cgo CFLAGS: -Wall
+// #include "input_win.h"
+import "C"
+
 import (
+	"bufio"
+	"bytes"
+	"io"
 	"log"
-	"sync/atomic"
+	"strings"
 	"syscall"
+	"time"
+	"unicode"
+	"unsafe"
 )
 
+var ReaderInterval = time.Duration(200) * time.Millisecond
+var ReaderTimeval syscall.Timeval = syscall.Timeval{Sec: 0, Usec: 200}
+
+// Output a nice string representation of the rune buffer.
+func extended_output(buffer []rune) string {
+	var output string = string(buffer)
+	output = strings.Replace(output, "\x1b", "^[", -1)
+	return output
+}
+
+func RuneToInt8(r rune) int8 {
+	return int8(r)
+}
+
+const READ_SIZE = 16 // Size of read buffer
+
 func Reader(d *Door) {
 	// handle syscall.Handle, readerChannel *chan byte
-	var handle syscall.Handle = syscall.Handle(d.Config.Comm_handle)
+	C.init_wsa()
+
+	var runebuffer bytes.Buffer
+	var runeread = bufio.NewReaderSize(&runebuffer, 1)
+
+	// readerBuffer = make([]rune, 0, READ_SIZE*2)
+	readerbuffer := C.malloc(C.sizeof_char * READ_SIZE)
+	defer C.free(unsafe.Pointer(readerbuffer))
 
 	defer func() {
 		log.Printf("~Reader")
@@ -23,37 +57,78 @@ func Reader(d *Door) {
 		}
 	}()
 
-	var buffer []byte = make([]byte, 1)
-	WSA_Buffer := syscall.WSABuf{Len: 1, Buf: &buffer[0]}
-	read := uint32(0)
-	flags := uint32(0)
+	var r int
 
 	for {
-		err := syscall.WSARecv(handle, &WSA_Buffer, 1, &read, &flags, nil, nil)
-		if err != nil {
-			log.Printf("Reader ERR: %#v\n", err)
-			close(d.readerChannel)
-			if !d.Disconnect() {
-				log.Println("Reader close writerChannel")
-				atomic.StoreInt32(&d.Disconnected, 1)
-				d.closeChannel <- struct{}{}
-				return
-			}
-			break
-		}
+		read := C.windows_read(C.int(d.Config.Comm_handle), (*C.char)(readerbuffer), C.int(READ_SIZE))
+		r = int(read)
+		log.Printf("windows_read: %d\n", r)
 
-		if read == 1 {
-			d.readerChannel <- buffer[0]
-		} else {
-			log.Printf("READ FAILED %d\n", read)
-			close(d.readerChannel)
-			if !d.Disconnect() {
-				log.Println("Reader close writerChannel")
-				atomic.StoreInt32(&d.Disconnected, 1)
-				d.closeChannel <- struct{}{}
-				return
+		if r == -1 {
+			log.Println("window_read -1 (closed)")
+			d.readerMutex.Lock()
+			defer d.readerMutex.Unlock()
+			if !d.ReaderClosed {
+				d.ReaderClosed = true
+				d.Disconnected = true
+				close(d.readerChannel)
 			}
 			return
 		}
+
+		if r == 0 {
+			// timeout
+			process(d, false)
+			continue
+		}
+		gobytes := C.GoBytes(unsafe.Pointer(readerbuffer), read)
+
+		if DEBUG_INPUT {
+			log.Printf("Reader << %d, %#v\n", r, gobytes)
+		}
+
+		runebuffer.Write(gobytes)
+
+		var input rune
+
+		// Is this unicode?
+
+		var err error = nil
+		for err == nil {
+			//RuneRead:
+
+			input, _, err = runeread.ReadRune()
+
+			if err == io.EOF {
+				break // continue
+			}
+			if err != nil {
+				if DEBUG_INPUT {
+					log.Printf("ReadRune: %#v\n", err)
+				}
+				// errors EOF
+				break // continue // break for loop
+			}
+			if input == unicode.ReplacementChar {
+				runeread.UnreadRune()
+				b, _ := runeread.ReadByte()
+				if DEBUG_INPUT {
+					log.Printf("Reader (byte) >> %x\n", b)
+				}
+				readerBuffer = append(readerBuffer, rune(b))
+				// d.readerChannel <- rune(b)
+			} else {
+				if DEBUG_INPUT {
+					log.Printf("Reader >> %x\n", input)
+				}
+				readerBuffer = append(readerBuffer, input)
+				// d.readerChannel <- input
+			}
+			// process(d, true)
+
+		} // goto RuneRead
+
+		process(d, true)
+
 	}
 }

+ 65 - 53
door/write_windows.go

@@ -14,7 +14,8 @@ func Writer(d *Door) {
 	defer d.wg.Done()
 	var Closed bool = false
 
-	for {
+	for output := range d.writerChannel {
+		// for {
 		/*
 			select {
 			case <-d.closeChannel:
@@ -24,73 +25,84 @@ func Writer(d *Door) {
 			default:
 			}
 		*/
-		select {
+		// select {
 		/*
 			case <-d.closeChannel:
 				close(d.writerChannel)
 				log.Println("~Writer")
 				return
 		*/
-		case output, ok := <-d.writerChannel:
-			if !ok {
-				log.Println("closeChannel")
-				d.writerMutex.Lock()
-				if !d.WriterClosed {
-					d.WriterClosed = true
-				}
-				d.writerMutex.Unlock()
-				log.Println("~Writer")
-				return
-			} else {
-				if output == "" {
-					Closed = true
-					continue
-				}
-
-				if Closed {
-					log.Println("Ignoring write output.")
-					continue
-				}
-
-				if strings.HasSuffix(output, RestorePos) {
-					output += Color(d.LastColor...)
-				} else {
-					d.UpdateLastColor(output, &d.LastColor)
-				}
-
-				var l uint32 = uint32(len(output))
-				var buffer []byte = []byte(output)
-				WSA_Buffer := syscall.WSABuf{Len: uint32(l), Buf: &buffer[0]}
-
-				var UitnZero_1 uint32 = uint32(0)
-				var DataWrite uint32 = uint32(0)
-				var err error
-				err = syscall.WSASend(handle, &WSA_Buffer, 1, &DataWrite, UitnZero_1, nil, nil)
-				if err != nil {
-					fmt.Printf("write: %d bytes, error: %#v\n", DataWrite, err)
-				}
-
-				if (err != nil) || (l != DataWrite) {
-					log.Println("CloseChannel")
-					Closed = true
+		/*
+			case output, ok := <-d.writerChannel:
+				if !ok {
+					log.Println("closeChannel")
 					d.writerMutex.Lock()
 					if !d.WriterClosed {
 						d.WriterClosed = true
 					}
 					d.writerMutex.Unlock()
-					/*
-						if !d.Disconnect() {
-							atomic.StoreInt32(&d.Disconnected, 1)
-							close(d.writerChannel)
-						}
-						log.Println("~Writer")
-						return
-					*/
-				}
+					log.Println("~Writer")
+					return
+				} else {
+		*/
+		if output == "" {
+			Closed = true
+			continue
+		}
+
+		if Closed {
+			log.Println("Ignoring write output.")
+			continue
+		}
+
+		if strings.HasSuffix(output, RestorePos) {
+			output += Color(d.LastColor...)
+		} else {
+			d.UpdateLastColor(output, &d.LastColor)
+		}
+
+		var l uint32 = uint32(len(output))
+		var buffer []byte = []byte(output)
+		WSA_Buffer := syscall.WSABuf{Len: uint32(l), Buf: &buffer[0]}
+
+		var UitnZero_1 uint32 = uint32(0)
+		var DataWrite uint32 = uint32(0)
+		var err error
+		err = syscall.WSASend(handle, &WSA_Buffer, 1, &DataWrite, UitnZero_1, nil, nil)
+		if err != nil {
+			fmt.Printf("write: %d bytes, error: %#v\n", DataWrite, err)
+		}
+
+		if (err != nil) || (l != DataWrite) {
+			log.Println("CloseChannel")
+			Closed = true
+			d.writerMutex.Lock()
+			if !d.WriterClosed {
+				d.WriterClosed = true
 			}
+			d.writerMutex.Unlock()
+			/*
+				if !d.Disconnect() {
+					atomic.StoreInt32(&d.Disconnected, 1)
+					close(d.writerChannel)
+				}
+				log.Println("~Writer")
+				return
+			*/
+			// }
+			// }
 		}
 	}
 
+	log.Println("closeChannel")
+	d.writerMutex.Lock()
+	if !d.WriterClosed {
+		d.WriterClosed = true
+	}
+	d.writerMutex.Unlock()
+	log.Println("~Writer")
+	// return
+
 	/*
 		for output := range *writerChannel {
 			l := uint32(len(output))