kopia lustrzana https://github.com/browsh-org/browsh
Just some simple refactoring and tidying up
rodzic
653eb6b1d7
commit
8acb1bcb96
|
@ -32,7 +32,11 @@ var desktopYFloat float32
|
|||
var roundedDesktopX int
|
||||
var roundedDesktopY int
|
||||
|
||||
// Dimensions of hiptext output
|
||||
// Channels to control the background xzoom go routine
|
||||
var stopXZoomChannel = make(chan struct{})
|
||||
var xZoomStoppedChannel = make(chan struct{})
|
||||
|
||||
// Dimensions of hiptext output, can be slightly different from terminal dimensions
|
||||
var hipWidth int
|
||||
var hipHeight int
|
||||
|
||||
|
@ -41,6 +45,23 @@ var panStartingX float32
|
|||
var panStartingY float32
|
||||
|
||||
func initialise() {
|
||||
setupLogging()
|
||||
log("Starting...")
|
||||
setupTermbox()
|
||||
calculateHipDimensions()
|
||||
C.xzoom_init()
|
||||
xzoomBackground()
|
||||
}
|
||||
|
||||
func setupTermbox() {
|
||||
err := termbox.Init()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
termbox.SetInputMode(termbox.InputMouse)
|
||||
}
|
||||
|
||||
func setupLogging() {
|
||||
dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
@ -50,8 +71,19 @@ func initialise() {
|
|||
if _, err := os.Stat(logfile); err == nil {
|
||||
os.Truncate(logfile, 0)
|
||||
}
|
||||
log("Starting...")
|
||||
calculateHipDimensions()
|
||||
}
|
||||
|
||||
func log(msg string) {
|
||||
f, oErr := os.OpenFile(logfile, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
|
||||
if oErr != nil {
|
||||
panic(oErr)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
msg = msg + "\n"
|
||||
if _, wErr := f.WriteString(msg); wErr != nil {
|
||||
panic(wErr)
|
||||
}
|
||||
}
|
||||
|
||||
// Hiptext needs to render the aspect ratio faithfully. So firstly it tries to fill
|
||||
|
@ -78,19 +110,6 @@ func min(a float32, b float32) float32 {
|
|||
return b
|
||||
}
|
||||
|
||||
func log(msg string) {
|
||||
f, oErr := os.OpenFile(logfile, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
|
||||
if oErr != nil {
|
||||
panic(oErr)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
msg = msg + "\n"
|
||||
if _, wErr := f.WriteString(msg); wErr != nil {
|
||||
panic(wErr)
|
||||
}
|
||||
}
|
||||
|
||||
func getXGrab() int {
|
||||
return int(C.xgrab)
|
||||
}
|
||||
|
@ -121,6 +140,7 @@ func roundToInt(value32 float32) int {
|
|||
}
|
||||
|
||||
// Whether the current input event includes a depressed CTRL key.
|
||||
// Waiting for this PR: https://github.com/nsf/termbox-go/pull/126
|
||||
func ctrlPressed() bool {
|
||||
return curev.Mod&termbox.ModCtrl != 0
|
||||
}
|
||||
|
@ -152,9 +172,7 @@ func mouseButtonStr(k termbox.Key) []string {
|
|||
return []string{"click", "4"}
|
||||
case termbox.MouseWheelDown:
|
||||
if ctrlPressed() {
|
||||
if C.magnification > 1 {
|
||||
zoom("out")
|
||||
}
|
||||
zoom("out")
|
||||
return []string{"noop"}
|
||||
}
|
||||
return []string{"click", "5"}
|
||||
|
@ -169,24 +187,33 @@ func zoom(direction string) {
|
|||
if direction == "in" {
|
||||
C.magnification++
|
||||
} else {
|
||||
C.magnification--
|
||||
if C.magnification > 1 {
|
||||
C.magnification--
|
||||
}
|
||||
}
|
||||
C.width[C.SRC] = (C.WIDTH + C.magnification - 1) / C.magnification;
|
||||
C.height[C.SRC] = (C.HEIGHT + C.magnification - 1) / C.magnification;
|
||||
|
||||
// Move the viewport so that the mouse is still over the same part of
|
||||
// the desktop.
|
||||
moveViewportForZoom(oldZoom)
|
||||
keepViewportInDesktop()
|
||||
}
|
||||
|
||||
// Move the viewport so that the mouse is still over the same part of
|
||||
// the desktop.
|
||||
func moveViewportForZoom(oldZoom C.int) {
|
||||
factor := float32(oldZoom) / float32(C.magnification)
|
||||
magnifiedRelativeX := factor * (desktopXFloat - float32(C.xgrab))
|
||||
magnifiedRelativeY := factor * (desktopYFloat - float32(C.ygrab))
|
||||
C.xgrab = C.int(desktopXFloat - magnifiedRelativeX)
|
||||
C.ygrab = C.int(desktopYFloat - magnifiedRelativeY)
|
||||
|
||||
keepViewportInDesktop()
|
||||
}
|
||||
|
||||
func keepViewportInDesktop() {
|
||||
// Manage the viewport size
|
||||
manageViewportSize()
|
||||
manageViewportPosition()
|
||||
}
|
||||
|
||||
func manageViewportSize() {
|
||||
if C.width[C.SRC] < 1 {
|
||||
C.width[C.SRC] = 1
|
||||
}
|
||||
|
@ -199,8 +226,9 @@ func keepViewportInDesktop() {
|
|||
if C.height[C.SRC] > C.HEIGHT {
|
||||
C.height[C.SRC] = C.HEIGHT
|
||||
}
|
||||
}
|
||||
|
||||
// Manage the viewport position
|
||||
func manageViewportPosition() {
|
||||
if C.xgrab > (C.WIDTH - C.width[C.SRC]) {
|
||||
C.xgrab = C.WIDTH - C.width[C.SRC]
|
||||
}
|
||||
|
@ -219,42 +247,44 @@ func keepViewportInDesktop() {
|
|||
// is being pressed at the same time.
|
||||
func modStr(m termbox.Modifier) string {
|
||||
var out []string
|
||||
if m&termbox.ModAlt != 0 {
|
||||
out = append(out, "Alt")
|
||||
}
|
||||
if m&termbox.ModMotion != 0 {
|
||||
if mouseMotion() {
|
||||
out = append(out, "Motion")
|
||||
}
|
||||
// Depends on this PR: https://github.com/nsf/termbox-go/pull/126
|
||||
if m&termbox.ModCtrl != 0 {
|
||||
if ctrlPressed() {
|
||||
out = append(out, "Ctrl")
|
||||
}
|
||||
|
||||
return strings.Join(out, " ")
|
||||
}
|
||||
|
||||
func mouseEvent() {
|
||||
log(
|
||||
fmt.Sprintf(
|
||||
"EventMouse: x: %d, y: %d, b: %s, mod: %s",
|
||||
curev.MouseX, curev.MouseY, mouseButtonStr(curev.Key), modStr(curev.Mod)))
|
||||
func isPanning() bool {
|
||||
return ctrlPressed() && mouseMotion() && lastMouseButton == "1"
|
||||
}
|
||||
|
||||
func mouseEvent() {
|
||||
// Figure out where the mouse is on the actual real desktop.
|
||||
// Note that the zomming and panning code effectively keep the mouse in the exact same position relative
|
||||
// to the desktop, so mousemove *should* have no effect.
|
||||
setCurrentDesktopCoords()
|
||||
|
||||
// Always move the mouse first so that button presses are correct. This is because we're not constantly
|
||||
// updating the mouse position, *unless* a drag event is happening. This saves bandwidth. Also, mouse
|
||||
// movement isn't supported on all terminals.
|
||||
xdotool("mousemove", fmt.Sprintf("%d", roundedDesktopX), fmt.Sprintf("%d", roundedDesktopY))
|
||||
|
||||
if ctrlPressed() && mouseMotion() && lastMouseButton == "1" {
|
||||
if isPanning() {
|
||||
pan()
|
||||
} else {
|
||||
panNeedsSetup = true
|
||||
// Pressing of CTRL indicates that the user is panning or zooming, so there is no need to send
|
||||
// button presses.
|
||||
// TODO: What about CTRL+leftbutton to open new tab!?
|
||||
if !ctrlPressed() {
|
||||
xdotool(mouseButtonStr(curev.Key)...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func pan() {
|
||||
if panNeedsSetup {
|
||||
panStartingX = desktopXFloat
|
||||
|
@ -268,40 +298,59 @@ func pan() {
|
|||
|
||||
// Convert terminal coords into desktop coords
|
||||
func setCurrentDesktopCoords() {
|
||||
var xOffset float32
|
||||
var yOffset float32
|
||||
hipWidthFloat := float32(hipWidth)
|
||||
hipHeightFloat := float32(hipHeight)
|
||||
eventX := float32(curev.MouseX)
|
||||
eventY := float32(curev.MouseY)
|
||||
width := float32(C.width[C.SRC])
|
||||
height := float32(C.height[C.SRC])
|
||||
xOffset = float32(C.xgrab)
|
||||
yOffset = float32(C.ygrab)
|
||||
xOffset := float32(C.xgrab)
|
||||
yOffset := float32(C.ygrab)
|
||||
desktopXFloat = (eventX * (width / hipWidthFloat)) + xOffset
|
||||
desktopYFloat = (eventY * (height / hipHeightFloat)) + yOffset
|
||||
roundedDesktopX = roundToInt(desktopXFloat)
|
||||
roundedDesktopY = roundToInt(desktopYFloat)
|
||||
log(
|
||||
fmt.Sprintf(
|
||||
"setCurrentDesktopCoords: tw: %d, th: %d, dx: %d, dy: %d, mag: %d",
|
||||
hipHeightFloat, hipWidthFloat, eventX, width, C.magnification))
|
||||
roundedDesktopX = roundToInt(desktopXFloat)
|
||||
roundedDesktopY = roundToInt(desktopYFloat)
|
||||
hipHeightFloat, hipWidthFloat, desktopXFloat, desktopYFloat, C.magnification))
|
||||
}
|
||||
|
||||
// Convert a keyboard event into an xdotool command
|
||||
// See: http://wiki.linuxquestions.org/wiki/List_of_Keysyms_Recognised_by_Xmodmap
|
||||
func keyEvent() {
|
||||
var key string
|
||||
var command string
|
||||
log(fmt.Sprintf("EventKey: k: %d, c: %c, mod: %s", curev.Key, curev.Ch, modStr(curev.Mod)))
|
||||
|
||||
key := getSpecialKeyPress()
|
||||
|
||||
if curev.Key == 0 {
|
||||
key = fmt.Sprintf("%c", curev.Ch)
|
||||
command = "type"
|
||||
} else {
|
||||
command = "key"
|
||||
}
|
||||
|
||||
// What is this? It always appears when the program starts :/
|
||||
badkey := fmt.Sprintf("%s", curev.Ch) == "%!s(int32=0)" && curev.Key == 0
|
||||
|
||||
if key == "" || badkey {
|
||||
log(fmt.Sprintf("No key found for keycode: %d"))
|
||||
return
|
||||
}
|
||||
|
||||
xdotool(command, key)
|
||||
}
|
||||
|
||||
func getSpecialKeyPress() string {
|
||||
var key string
|
||||
switch curev.Key {
|
||||
case termbox.KeyEnter:
|
||||
key = "Return"
|
||||
key = "Return"
|
||||
case termbox.KeyBackspace, termbox.KeyBackspace2:
|
||||
key = "BackSpace"
|
||||
key = "BackSpace"
|
||||
case termbox.KeySpace:
|
||||
key = "Space"
|
||||
key = "Space"
|
||||
case termbox.KeyF1:
|
||||
key = "F1"
|
||||
case termbox.KeyF2:
|
||||
|
@ -349,23 +398,7 @@ func keyEvent() {
|
|||
case termbox.KeyCtrlL:
|
||||
key = "ctrl+l"
|
||||
}
|
||||
|
||||
if curev.Key == 0 {
|
||||
key = fmt.Sprintf("%c", curev.Ch)
|
||||
command = "type"
|
||||
} else {
|
||||
command = "key"
|
||||
}
|
||||
|
||||
// What is this? It always appears when the program starts :/
|
||||
badkey := fmt.Sprintf("%s", curev.Ch) == "%!s(int32=0)" && curev.Key == 0
|
||||
|
||||
if key == "" || badkey {
|
||||
log(fmt.Sprintf("No key found for keycode: %d"))
|
||||
return
|
||||
}
|
||||
|
||||
xdotool(command, key)
|
||||
return key
|
||||
}
|
||||
|
||||
func parseInput() {
|
||||
|
@ -373,56 +406,42 @@ func parseInput() {
|
|||
case termbox.EventKey:
|
||||
keyEvent()
|
||||
case termbox.EventMouse:
|
||||
log(
|
||||
fmt.Sprintf(
|
||||
"EventMouse: x: %d, y: %d, b: %s, mod: %s",
|
||||
curev.MouseX, curev.MouseY, mouseButtonStr(curev.Key), modStr(curev.Mod)))
|
||||
mouseEvent()
|
||||
case termbox.EventNone:
|
||||
log("EventNone")
|
||||
}
|
||||
}
|
||||
|
||||
// a channel to tell it to stop
|
||||
var stopchan = make(chan struct{})
|
||||
// a channel to signal that it's stopped
|
||||
var stoppedchan = make(chan struct{})
|
||||
|
||||
// Run the xzoom window in a background go routine
|
||||
func xzoomBackground(){
|
||||
go func(){ // work in background
|
||||
// close the stoppedchan when this func
|
||||
// exits
|
||||
defer close(stoppedchan)
|
||||
// TODO: do setup work
|
||||
defer func(){
|
||||
// TODO: do teardown work
|
||||
}()
|
||||
go func(){
|
||||
defer close(xZoomStoppedChannel)
|
||||
for {
|
||||
select {
|
||||
default:
|
||||
C.loop()
|
||||
C.do_iteration()
|
||||
time.Sleep(40 * time.Millisecond) // 25fps
|
||||
case <-stopchan:
|
||||
// stop
|
||||
case <-stopXZoomChannel:
|
||||
// Gracefully close the xzoom go routine
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func main() {
|
||||
C.xzoom_init()
|
||||
xzoomBackground()
|
||||
|
||||
err := termbox.Init()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer func() {
|
||||
termbox.Close()
|
||||
close(stopchan)
|
||||
<-stoppedchan
|
||||
}()
|
||||
termbox.SetInputMode(termbox.InputMouse)
|
||||
initialise()
|
||||
parseInput()
|
||||
func teardown(){
|
||||
termbox.Close()
|
||||
close(stopXZoomChannel)
|
||||
<-xZoomStoppedChannel
|
||||
}
|
||||
|
||||
// I'm afraid I don't understand most of what this does :/
|
||||
// TODO: if anyone can shed some light on this. Add some comments, refactor it...
|
||||
func mainLoop() {
|
||||
data := make([]byte, 0, 64)
|
||||
for {
|
||||
if cap(data)-len(data) < 32 {
|
||||
|
@ -451,3 +470,11 @@ func main() {
|
|||
parseInput()
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
initialise()
|
||||
defer func() {
|
||||
teardown()
|
||||
}()
|
||||
mainLoop()
|
||||
}
|
||||
|
|
7
run.sh
7
run.sh
|
@ -9,7 +9,7 @@ export DISPLAY=:0
|
|||
DESKTOP_RES="$DESKTOP_WIDTH"x"$DESKTOP_HEIGHT"
|
||||
UDP_URI='udp://127.0.0.1:1234'
|
||||
|
||||
# Create an X desktop in memory without actually displaying it on a real screen
|
||||
# Create an X desktop in memory without actually displaying it on a real screen.
|
||||
# Double the width to make room for the xzoom window, which is actually what
|
||||
# ffmpeg will stream;
|
||||
# ---------------------------------
|
||||
|
@ -29,6 +29,7 @@ sleep 1
|
|||
|
||||
# Convert the X framebuffer desktop into a video stream, but only stream the
|
||||
# right hand side where the xzoom window is.
|
||||
# TODO: Can latency be reduced further? Can flicker be reduced, in order to reduce bandwidth?
|
||||
ffmpeg \
|
||||
-f x11grab \
|
||||
-s $DESKTOP_RES \
|
||||
|
@ -44,11 +45,11 @@ ffmpeg \
|
|||
sleep 1
|
||||
|
||||
# Intercept STDIN (mouse and keypresses) and forward to the X framebuffer via xdotool
|
||||
(./interfacer/interfacer <&3 > ./logs/interface.log 2>&1 &) 3<&0
|
||||
(./interfacer/interfacer <&3 > ./logs/interfacer.log 2>&1 &) 3<&0
|
||||
|
||||
# Hiptext renders images and videos into text characters displayable in a terminal.
|
||||
# It complains unless you specify the exact path to the font, seems like a bug to me.
|
||||
# TODO: support variable width, ideally dynamic sizing
|
||||
# TODO: support dynamic sizing
|
||||
hiptext \
|
||||
-font /usr/share/fonts/ttf-dejavu/DejaVuSansMono.ttf \
|
||||
$UDP_URI \
|
||||
|
|
|
@ -120,11 +120,6 @@ void recreate_images_on_zoom() {
|
|||
old_magnification = magnification;
|
||||
}
|
||||
|
||||
void loop() {
|
||||
recreate_images_on_zoom();
|
||||
update_zoom_window_with_desktop();
|
||||
}
|
||||
|
||||
int xzoom_init() {
|
||||
XSetWindowAttributes xswa;
|
||||
XGCValues gcv;
|
||||
|
@ -163,3 +158,8 @@ int xzoom_init() {
|
|||
&gcv);
|
||||
allocate_images();
|
||||
}
|
||||
|
||||
void do_iteration() {
|
||||
recreate_images_on_zoom();
|
||||
update_zoom_window_with_desktop();
|
||||
}
|
||||
|
|
Ładowanie…
Reference in New Issue