|
@@ -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)
|