Explorar o código

Working extended keys.

Steve Thielemann %!s(int64=3) %!d(string=hai) anos
pai
achega
f723a014de
Modificáronse 2 ficheiros con 263 adicións e 8 borrados
  1. 261 6
      door/door.go
  2. 2 2
      testdoor/testdoor.go

+ 261 - 6
door/door.go

@@ -2,6 +2,7 @@ package door
 
 import (
 	"bufio"
+	"container/list"
 	"flag"
 	"fmt"
 	"os"
@@ -46,10 +47,11 @@ type DropfileConfig struct {
 }
 
 type Door struct {
-	config  DropfileConfig
-	READFD  int
-	WRITEFD int
-	TimeOut time.Time // Fixed point in time, when time expires
+	config   DropfileConfig
+	READFD   int
+	WRITEFD  int
+	TimeOut  time.Time // Fixed point in time, when time expires
+	pushback *list.List
 }
 
 // Return the amount of time left as time.Duration
@@ -197,6 +199,7 @@ func (d *Door) detect() {
 // detect terminal capabilities.
 func (d *Door) Init() {
 	var dropfile string
+	d.pushback = list.New()
 
 	flag.StringVar(&dropfile, "d", "", "Path to dropfile")
 	flag.Parse()
@@ -283,7 +286,256 @@ func (d *Door) SleepKey(sleep int64) int {
 	return int(buffer[0])
 }
 
-func (d *Door) Getch() int {
+// Low level read key function.
+// This gets the raw keys from the client, it doesn't handle extended keys,
+// functions, arrows.
+// Return key, or -1 (Timeout/No key available), -2 hangup
+func (d *Door) getch() int {
+	var fdsetRead syscall.FdSet
+	clearAll(&fdsetRead)
+	set(&fdsetRead, d.READFD)
+
+	// 100 Usec seems like a good value, works with QModem in dosbox.
+	timeout := syscall.Timeval{Sec: 0, Usec: 100}
+	v, err := syscall.Select(d.READFD+1, &fdsetRead, nil, nil, &timeout)
+	if v == -1 {
+		// hangup
+		return -2
+	}
+	if v == 0 {
+		// timeout
+		return -1
+	}
+
+	buffer := make([]byte, 1)
+	r, err := syscall.Read(d.READFD, buffer)
+	if r != 1 {
+		fmt.Printf("Read said ready, but didn't read a character %d %v.", r, err)
+		// hangup
+		return -2
+	}
+	return int(buffer[0])
+}
+
+func (d *Door) getkey_or_pushback() int {
+	if d.pushback.Len() != 0 {
+		e := d.pushback.Front()
+		d.pushback.Remove(e)
+		return e.Value.(int)
+	}
+	return d.getch()
+}
+
+const (
+	XKEY_UP_ARROW    = 0x1001
+	XKEY_DOWN_ARROW  = 0x1002
+	XKEY_RIGHT_ARROW = 0x1003
+	XKEY_LEFT_ARROW  = 0x1004
+	XKEY_HOME        = 0x1010
+	XKEY_END         = 0x1011
+	XKEY_PGUP        = 0x1012
+	XKEY_PGDN        = 0x1023
+	XKEY_INSERT      = 0x1024
+	XKEY_DELETE      = 0x7f
+	XKEY_F1          = 0x1021
+	XKEY_F2          = 0x1022
+	XKEY_F3          = 0x1023
+	XKEY_F4          = 0x1024
+	XKEY_F5          = 0x1025
+	XKEY_F6          = 0x1026
+	XKEY_F7          = 0x1027
+	XKEY_F8          = 0x1028
+	XKEY_F9          = 0x1029
+	XKEY_F10         = 0x102a
+	XKEY_F11         = 0x102b
+	XKEY_F12         = 0x102c
+	XKEY_UNKNOWN     = 0x1111
+)
+
+// Return key received, or XKEY_* values.
+// -1 timeout/no key
+// -2 hangup
+// -3 out of time
+func (d *Door) Getkey() int {
+	var c, c2 int
+
+	if d.TimeLeft() < 0 {
+		return -3
+	}
+
+	c = d.getkey_or_pushback()
+
+	if c < 0 {
+		return c
+	}
+
+	// We get 0x0d 0x00, or 0x0d 0x0a from syncterm.
+	if c == 0x0d {
+		c2 = d.getkey_or_pushback()
+		if c2 > 0 {
+			// wasn't an error
+			if c2 != 0x00 && c2 != 0x0a {
+				// wasn't 0x00 or 0x0a
+				d.pushback.PushFront(c2)
+			}
+		}
+		return c
+	}
+
+	if c == 0 {
+		// possibly doorway mode
+		tries := 0
+		c2 = d.getkey_or_pushback()
+		for c2 < 0 {
+			if tries > 7 {
+				return c
+			}
+			c2 = d.getkey_or_pushback()
+			tries++
+		}
+
+		switch c2 {
+		case 0x50:
+			return XKEY_DOWN_ARROW
+		case 0x48:
+			return XKEY_UP_ARROW
+		case 0x4b:
+			return XKEY_LEFT_ARROW
+		case 0x4d:
+			return XKEY_RIGHT_ARROW
+		case 0x47:
+			return XKEY_HOME
+		case 0x4f:
+			return XKEY_END
+		case 0x49:
+			return XKEY_PGUP
+		case 0x51:
+			return XKEY_PGDN
+		case 0x3b:
+			return XKEY_F1
+		case 0x3c:
+			return XKEY_F2
+		case 0x3d:
+			return XKEY_F3
+		case 0x3e:
+			return XKEY_F4
+		case 0x3f:
+			return XKEY_F5
+		case 0x40:
+			return XKEY_F6
+		case 0x41:
+			return XKEY_F7
+		case 0x42:
+			return XKEY_F8
+		case 0x43:
+			return XKEY_F9
+		case 0x44:
+			return XKEY_F10
+		/*
+			case 0x45:
+				return XKEY_F11
+			case 0x46:
+				return XKEY_F12
+		*/
+		case 0x52:
+			return XKEY_INSERT
+		case 0x53:
+			return XKEY_DELETE
+		default:
+			fmt.Printf("ERROR Doorway mode: 0x00 %x\n", c2)
+			return XKEY_UNKNOWN
+		}
+	}
+
+	if c == 0x1b {
+		// Escape key?
+		c2 = d.getkey_or_pushback()
+		if c2 < 0 {
+			// Just escape key
+			return c
+		}
+		var extended string = string(c2)
+
+		c2 = d.getkey_or_pushback()
+		for c2 > 0 {
+			if c2 == 0x1b {
+				d.pushback.PushBack(c2)
+				break
+			}
+			extended += string(c2)
+			c2 = d.getkey_or_pushback()
+		}
+
+		switch extended {
+		case "[A":
+			return XKEY_UP_ARROW
+		case "[B":
+			return XKEY_DOWN_ARROW
+		case "[C":
+			return XKEY_RIGHT_ARROW
+		case "[D":
+			return XKEY_LEFT_ARROW
+		case "[H":
+			return XKEY_HOME
+		case "[F":
+			return XKEY_END // terminal
+		case "[K":
+			return XKEY_END
+		case "[V":
+			return XKEY_PGUP
+		case "[U":
+			return XKEY_PGDN
+		case "[@":
+			return XKEY_INSERT
+		case "[1":
+			// Syncterm is lost, could be F1..F5?
+			fmt.Printf("ERROR (Syncterm) Extended %#v\n", extended)
+			return XKEY_UNKNOWN
+		case "[2~":
+			return XKEY_INSERT // terminal
+		case "[3~":
+			return XKEY_DELETE // terminal
+		case "[5~":
+			return XKEY_PGUP // terminal
+		case "[6~":
+			return XKEY_PGDN // terminal
+		case "[15~":
+			return XKEY_F5 // terminal
+		case "[17~":
+			return XKEY_F6 // terminal
+		case "[18~":
+			return XKEY_F7 // terminal
+		case "[19~":
+			return XKEY_F8 // terminal
+		case "[20~":
+			return XKEY_F9 // terminal
+		case "[21~":
+			return XKEY_F10 // terminal
+		case "[23~":
+			return XKEY_F11
+		case "[24~":
+			return XKEY_F12 // terminal
+		case "OP":
+			return XKEY_F1
+		case "OQ":
+			return XKEY_F2
+		case "OR":
+			return XKEY_F3
+		case "OS":
+			return XKEY_F4
+		case "Ot":
+			return XKEY_F5 // syncterm
+		default:
+			fmt.Printf("ERROR Extended %#v\n", extended)
+			return XKEY_UNKNOWN
+		}
+
+	}
+
+	return c
+}
+
+func (d *Door) WaitKey(secs int64) int {
 	// var fdsetRead, fdsetWrite, fdsete syscall.FdSet
 	var fdsetRead syscall.FdSet
 	// fdsetWrite := syscall.FdSet
@@ -292,7 +544,7 @@ func (d *Door) Getch() int {
 	// clearAll(&fdsete)
 	set(&fdsetRead, d.READFD)
 	// timeout := syscall.Timeval{Sec: 0, Usec: 100}
-	timeout := syscall.Timeval{Sec: 120, Usec: 0}
+	timeout := syscall.Timeval{Sec: secs, Usec: 0}
 	v, err := syscall.Select(d.READFD+1, &fdsetRead, nil, nil, &timeout)
 	if v == -1 {
 		fmt.Println("-1 : ", err)
@@ -303,6 +555,9 @@ func (d *Door) Getch() int {
 		// timeout
 		return -1
 	}
+
+	return d.Getkey()
+
 	// var buffer []byte   -- 0 byte buffer.  doh!
 	buffer := make([]byte, 1)
 	r, err := syscall.Read(d.READFD, buffer)

+ 2 - 2
testdoor/testdoor.go

@@ -14,7 +14,7 @@ func main() {
 	bold := door.Color(1, 37, 40)
 	bolder := door.ColorText("BLI BOLD YEL ON BLUE")
 	d.Write("Welcome to " + bolder + "door32.sys" + reset + door.CRNL + "..." + door.CRNL)
-	key := d.Getch()
+	key := d.WaitKey(120)
 	message := fmt.Sprintf("Key %s%d / %x%s"+door.CRNL, bold, key, key, reset)
 	d.Write(message)
 	b := door.Box{20, 1}
@@ -33,7 +33,7 @@ func main() {
 	d.Write(message)
 
 	d.Write("Returning you to the BBS..." + door.CRNL)
-	d.SleepKey(3)
+	d.WaitKey(3)
 
 	left = d.TimeLeft()