Explorar el Código

Added Enable/Disable Mouse. MouseMode.

Use DEBUG_INPUT to remove input debug log output.
Steve Thielemann hace 2 años
padre
commit
0bf0a0fb0f
Se han modificado 6 ficheros con 154 adiciones y 59 borrados
  1. 39 0
      door/door.go
  2. 12 0
      door/fifobuffer.go
  3. 2 1
      door/input.go
  4. 25 10
      door/input_linux.go
  5. 55 48
      door/line.go
  6. 21 0
      door/utilities.go

+ 39 - 0
door/door.go

@@ -74,6 +74,16 @@ type Mouse struct {
 	Y      int8
 }
 
+type MouseMode int
+
+const (
+	Off      MouseMode = 0
+	X10                = 9
+	Normal             = 1000
+	Button             = 1002
+	AnyEvent           = 1003
+)
+
 /*
 door32.sys:
 
@@ -132,6 +142,7 @@ type Door struct {
 	mcMutex        sync.Mutex  // Lock for LastMouse, LastCursor
 	wg             sync.WaitGroup
 	tio_default    *term.State // Terminal State to restore
+	Mouse          MouseMode   // Mouse mode enabled
 }
 
 func (d *Door) SafeWriterClose() {
@@ -154,12 +165,39 @@ func (d *Door) AddMouse(mouse Mouse) {
 	defer d.mcMutex.Unlock()
 	d.LastMouse = append(d.LastMouse, mouse)
 }
+
 func (d *Door) GetMouse() (Mouse, bool) {
 	d.mcMutex.Lock()
 	defer d.mcMutex.Unlock()
 	return ArrayDelete(&d.LastMouse, 0)
 }
 
+/*
+Enable mouse support
+9 : X10 Support
+1000: Normal
+1002: Button Event
+1003: Any-Event
+*/
+func (d *Door) EnableMouse(mode MouseMode) {
+	if d.Mouse != Off {
+		// Disable current mode first
+		d.DisableMouse()
+	}
+	d.Mouse = mode
+	if d.Mouse != Off {
+		d.Write(fmt.Sprintf("\x1b[?%dh", int(d.Mouse)))
+	}
+}
+
+// Disable mouse support
+func (d *Door) DisableMouse() {
+	if d.Mouse != Off {
+		d.Write(fmt.Sprintf("\x1b[?%dl", int(d.Mouse)))
+	}
+	d.Mouse = Off
+}
+
 func (d *Door) GetCursorPos() (CursorPos, bool) {
 	d.mcMutex.Lock()
 	defer d.mcMutex.Unlock()
@@ -421,6 +459,7 @@ func (d *Door) Close() {
 		}
 	}()
 
+	d.DisableMouse()
 	log.Println("Closing...")
 	// d.closeChannel <- struct{}{}
 	close(d.writerChannel)

+ 12 - 0
door/fifobuffer.go

@@ -2,19 +2,30 @@ package door
 
 import "log"
 
+// A First-In-First-Out buffer using generics.
 type FIFOBuffer[T any] struct {
 	data  []T
 	index int
 }
 
+/*
+Construct new buffer.
+
+buffer := NewFIFOBuffer[rune](5)
+
+This would construct a buffer that will hold
+rune type, with a buffer size of 5.
+*/
 func NewFIFOBuffer[T any](maxsize int) FIFOBuffer[T] {
 	return FIFOBuffer[T]{data: make([]T, maxsize)}
 }
 
+// Is buffer empty?
 func (f *FIFOBuffer[T]) Empty() bool {
 	return f.index == 0
 }
 
+// Push item into buffer.
 func (f *FIFOBuffer[T]) Push(value T) {
 	if f.index >= len(f.data) {
 		log.Panicf("Exceeded FIFOBuffer index %d size %d %#v", f.index, len(f.data), f.data)
@@ -23,6 +34,7 @@ func (f *FIFOBuffer[T]) Push(value T) {
 	f.index++
 }
 
+// Pop element from buffer.
 func (f *FIFOBuffer[T]) Pop() T {
 	if f.index == 0 {
 		log.Panicf("Pop from empty FIFOBuffer (size %d).", len(f.data))

+ 2 - 1
door/input.go

@@ -9,7 +9,8 @@ import (
 	"unicode"
 )
 
-const DEBUG_INPUT = true
+// For debugging input reader routines.
+const DEBUG_INPUT = false
 
 var ErrInactivity error = fmt.Errorf("Inactivity")
 var ErrTimeout error = fmt.Errorf("Timeout")

+ 25 - 10
door/input_linux.go

@@ -86,7 +86,9 @@ func process(d *Door, newRune bool) {
 			return
 		}
 
-		log.Println("rlen:", rlen, "readerBuffer:", readerBuffer, "newRune:", newRune)
+		if DEBUG_INPUT {
+			log.Println("rlen:", rlen, "readerBuffer:", readerBuffer, "newRune:", newRune)
+		}
 
 		r = readerBuffer[0]
 		if rlen >= 2 {
@@ -256,7 +258,9 @@ func process(d *Door, newRune bool) {
 				var isMouse bool = false
 				var found bool = false
 
-				log.Println(pos, readerBuffer)
+				if DEBUG_INPUT {
+					log.Println(pos, readerBuffer)
+				}
 
 				for pos < rlen {
 					r2 = readerBuffer[pos]
@@ -266,12 +270,16 @@ func process(d *Door, newRune bool) {
 
 					extended = append(extended, r2)
 
-					log.Println("0x1b LOOP pos:", pos, "extlen:", extlen, "extended:", string(extended))
+					if DEBUG_INPUT {
+						log.Println("0x1b LOOP pos:", pos, "extlen:", extlen, "extended:", string(extended))
+					}
 
 					ext, has := extendedKeys[string(extended)]
 					if has {
 						// Found it!
-						log.Println("Found Extended Match:", ext.String())
+						if DEBUG_INPUT {
+							log.Println("Found Extended Match:", ext.String())
+						}
 						ArrayPop(&readerBuffer, extlen)
 						d.readerChannel <- ReaderData{0, ext, nil}
 						found = true
@@ -281,7 +289,9 @@ func process(d *Door, newRune bool) {
 					// Mouse codes can also contain letters.
 					if !isMouse && unicode.IsLetter(r2) {
 						// end of extended code, unless mouse!
-						log.Println("not mouse, is letter...")
+						if DEBUG_INPUT {
+							log.Println("not mouse, is letter...")
+						}
 						if string(extended) == "[M" {
 							isMouse = true
 						} else {
@@ -298,9 +308,10 @@ func process(d *Door, newRune bool) {
 					continue
 				}
 
-				log.Println("POS:", pos, "EXLEN:", extlen, "Extended:", extended, "readerBuffer:", readerBuffer)
-
-				log.Printf("(possible) Extended Code: [%s]", extended_output(extended))
+				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 {
@@ -350,7 +361,9 @@ func process(d *Door, newRune bool) {
 					log.Println("ERROR Extended:", extended)
 					d.readerChannel <- ReaderData{0, UNKNOWN, nil}
 				} else {
-					log.Println("(Possibly) invalid extended:", extended)
+					if DEBUG_INPUT {
+						log.Println("(Possibly) invalid extended:", extended)
+					}
 					return
 				}
 
@@ -463,7 +476,9 @@ func Reader(d *Door) {
 				break // continue
 			}
 			if err != nil {
-				log.Printf("ReadRune: %#v\n", err)
+				if DEBUG_INPUT {
+					log.Printf("ReadRune: %#v\n", err)
+				}
 				// errors EOF
 				break // continue // break for loop
 			}

+ 55 - 48
door/line.go

@@ -11,68 +11,72 @@ door.Line - Display a line of text
 
 Example:
 
-    var basicLine door.Line = {Text: "Welcome",
-	    DefaultColor: door.Color("BRIGHT YELLOW"),
-	}
+	    var basicLine door.Line = {Text: "Welcome",
+		    DefaultColor: door.Color("BRIGHT YELLOW"),
+		}
 
-    d.Write(basicLine.Output() + door.Reset + door.CRNL)
+	    d.Write(basicLine.Output() + door.Reset + door.CRNL)
 
 This outputs Welcome in Bright/Bold Yellow.
 
 Example Render:
 
-    var renderAlphaDigit func(string) string = func(text string) string {
-		var r door.Render{Text: text}
-		var alpha string = door.ColorText("BOLD YELLOW")
-		var digit string = door.ColorText("BOLD GREEN")
-		var other string = door.Reset
-		for _, letter := range text {
-			if unicode.IsAlpha(letter) {
-				r.Append(alpha, 1)
-			} else {
-				if unicode.IsDigit(letter) {
-					r.Append(digit, 1)
+	    var renderAlphaDigit func(string) string = func(text string) string {
+			var r door.Render{Text: text}
+			var alpha string = door.ColorText("BOLD YELLOW")
+			var digit string = door.ColorText("BOLD GREEN")
+			var other string = door.Reset
+			for _, letter := range text {
+				if unicode.IsAlpha(letter) {
+					r.Append(alpha, 1)
 				} else {
-					r.Append(other, 1)
+					if unicode.IsDigit(letter) {
+						r.Append(digit, 1)
+					} else {
+						r.Append(other, 1)
+					}
 				}
 			}
+			return r.Result
 		}
-		return r.Result
-	}
-	var renderLine door.Line = {Text: "Render - 12345",
-		RenderF: renderAlphaDigit,
-	}
-	d.Write(renderLine.Output() + door.Reset + door.CRNL)
+		var renderLine door.Line = {Text: "Render - 12345",
+			RenderF: renderAlphaDigit,
+		}
+		d.Write(renderLine.Output() + door.Reset + door.CRNL)
 
 This outputs "Render" in Yellow, "12345" in Green, and " - " in White.
 
 Example Update:
 
-	var updateTime() string {
-		var now time.Time = time.Now()
-		var result string = now.Format("3:04:05 PM")
-        return result
-	}
-	var timeLine door.Line = {Text: updateTime(),
-		UpdateF: updateTime,
-	}
-	d.Write(timeLine.Output() + door.CRNL)
-	time.Sleep(time.Second)
-
-	// Check timeLine for update
-	if timeLine.Update() {
-		// Yes, there's an update to the time, output it.
+		var updateTime() string {
+			var now time.Time = time.Now()
+			var result string = now.Format("3:04:05 PM")
+	        return result
+		}
+		var timeLine door.Line = {Text: updateTime(),
+			UpdateF: updateTime,
+		}
 		d.Write(timeLine.Output() + door.CRNL)
-	}
+		time.Sleep(time.Second)
 
-	if timeLine.Update() {
-		// This isn't called.  There were no changes.
-		d.Write(timeLine.Output() + door.CRNL)
-	}
+		// Check timeLine for update
+		if timeLine.Update() {
+			// Yes, there's an update to the time, output it.
+			d.Write(timeLine.Output() + door.CRNL)
+		}
+
+		if timeLine.Update() {
+			// This isn't called.  There were no changes.
+			d.Write(timeLine.Output() + door.CRNL)
+		}
 
 This outputs the Current time in 12 hour format.  It pauses for a second,
 and outputs the new time.
 */
+
+/*
+Line of text to display.
+*/
 type Line struct {
 	Text         string              // Text to be displayed
 	DefaultColor string              // Default Color to use
@@ -99,17 +103,19 @@ func (l *Line) Update() bool {
 	return false
 }
 
+// If a line Width has been set, make sure we match it.
 func (l *Line) LineLength(text *string) {
-	var length int
 	if l.Width == 0 {
 		return
 	}
-
-	if Unicode {
-		length = len([]rune(*text))
-	} else {
-		length = len([]byte(*text))
-	}
+	var length int = StringLen(*text)
+	/*
+		if Unicode {
+			length = len([]rune(*text))
+		} else {
+			length = len([]byte(*text))
+		}
+	*/
 	if length > l.Width {
 		log.Printf("ERROR: Line Width %d: Have %d\n", l.Width, length)
 	} else {
@@ -136,6 +142,7 @@ func (l *Line) Output() string {
 door.Render - Helper for Line RenderF (Render Function)
 
 Example:
+
 	// RenderStatus - KEY_COLOR[key] COLON_COLOR[:] VALUE_COLOR[value]
 	func RenderStatus(text string) string {
 		var r door.Render = Render{Line: text}

+ 21 - 0
door/utilities.go

@@ -8,6 +8,8 @@ import (
 )
 
 // https://siongui.github.io/2016/03/23/go-utf8-string-width/
+
+// Return width of Unicode rune.
 func UnicodeWidth(r rune) int {
 	p := width.LookupRune(r)
 	if p.Kind() == width.EastAsianWide {
@@ -16,6 +18,7 @@ func UnicodeWidth(r rune) int {
 	return 1
 }
 
+// Delete an item from an array, returning item and true on success.
 func ArrayDelete[T any](stack *[]T, pos int) (T, bool) {
 	var result T
 	/*
@@ -33,6 +36,7 @@ func ArrayDelete[T any](stack *[]T, pos int) (T, bool) {
 	return result, true
 }
 
+// Pop items from head of array, return true on success.
 func ArrayPop[T any](stack *[]T, count int) bool {
 	/*
 	   https://stackoverflow.com/questions/33834742/remove-and-adding-elements-to-array-in-go-lang
@@ -49,6 +53,7 @@ func ArrayPop[T any](stack *[]T, count int) bool {
 	return true
 }
 
+// Split string on separator, returning []int
 func SplitToInt(input string, sep string) []int {
 	var result []int
 	for _, number := range strings.Split(input, sep) {
@@ -59,3 +64,19 @@ func SplitToInt(input string, sep string) []int {
 	}
 	return result
 }
+
+// In unicode, a single character isn't always 1 char wide.
+// This finds the actual length.
+
+// Calculate the length of the given line, dealing with unicode.
+func StringLen(s string) int {
+	if Unicode {
+		var len int
+		for _, r := range s {
+			len += UnicodeWidth(r)
+		}
+		return len
+	} else {
+		return len([]byte(s))
+	}
+}