vue-guacamole-client
Version:
A Vue.js based Guacamole client
214 lines (187 loc) • 6.7 kB
JavaScript
/**
* Contains code relevant to handling mouse, keyboard,
* and clipboard input for a Guacamole connection
*/
import Guacamole from 'guacamole-common-js'
export default{
methods: {
/**
* Initializes the mouse event handlers and ties it to a display
*/
initMouse () {
this.mouse = new Guacamole.Mouse(this.client.getDisplay().getElement())
this.mouse.onmousedown = this.mouse.onmouseup = this.mouse.onmousemove = (mouseState) => {
this.updateActivity()
this.client.sendMouseState(mouseState)
}
// let oldEvent = this.mouse.fromClientPosition
// this.mouse.fromClientPosition = function(element, clientX, clientY) {
// console.log("here")
// oldEvent(element, clientX, clientY)
// }
},
/**
* Initializes the keyboard event handlers and ties it to the document
*
* The document is the preferred method for the event handlers,
* but can cause some trouble if not careful. All input for the tab will be
* directed to this connection while these event handlers are in place. When
* wanting to not redirect the input to the VM (when the options drawer is open for instance)
* the event handlers will need to be nullified
*/
initKeyboard () {
this.keyboard = new Guacamole.Keyboard(document);
if (!this.options.showOptionsDrawer && this.viewState !== 'thumbnail') {
this.keyboard.onkeydown = (keysym) => this.client.sendKeyEvent(1, keysym)
this.keyboard.onkeyup = (keysym) => this.client.sendKeyEvent(0, keysym)
} else {
this.keyboard.onkeydown = null
this.keyboard.onkeyup = null
}
},
/**
* Initializes the clipboard event handlers
*
* These event handlers will watch for changes to the VM clipboard and fire when
* those changes are detected. The value of the clipboard is saved in the options object.
*/
initClipboard () {
this.client.onclipboard = (stream, mimetype) => {
// Only text/plain is supported for now
if (mimetype !== 'text/plain') {
stream.sendAck('Only text/plain supported', Guacamole.Status.Code.UNSUPPORTED)
return
}
var reader = new Guacamole.StringReader(stream)
var data = ''
// Append any received data to buffer
reader.ontext = (text) => {
data += text
stream.sendAck('Received', Guacamole.Status.Code.SUCCESS)
}
// Update state when done
reader.onend = () => {
this.options.clipboard = data
}
}
},
/**
* Sets the clipboard of the VM to the value found in the clipboard
* property of the options object
*
* Used to inject clipboard data to the VM
*/
setClipboard () {
const stream = this.client.createClipboardStream()
const writer = new Guacamole.StringWriter(stream)
// Send text chunks
for (let i = 0; i < this.options.clipboard.length; i += 4096) {
writer.sendText(this.options.clipboard.substring(i, i + 4096))
}
// Close stream
writer.sendEnd()
},
/**
* Updates the mouse event listeners to correctly use the current scale of the display
*
* With out this the remote mouse and the local mouse will be offset based on the scale of the display
*/
setScaledMouseState (scale) {
this.display.scale(scale)
this.mouse.onmousedown = this.mouse.onmouseup = this.mouse.onmousemove = (mouseState) => {
// Scale event by current scale
const scaledState = new Guacamole.Mouse.State(
mouseState.x / scale,
mouseState.y / scale,
mouseState.left,
mouseState.middle,
mouseState.right,
mouseState.up,
mouseState.down
)
this.updateActivity()
this.scrollToMouse(mouseState)
this.client.sendMouseState(scaledState)
}
},
/**
* Scrolls the client view such that the mouse cursor is visible.
*
* @param {Guacamole.Mouse.State} mouseState The current mouse
* state.
*/
scrollToMouse (mouseState) {
const displayContainer = this.$refs.displayWrapper
const main = this.$refs.display
// Determine mouse position within view
const mouseViewX = mouseState.x + displayContainer.offsetLeft - main.scrollLeft
const mouseViewY = mouseState.y + displayContainer.offsetTop - main.scrollTop
// Determine viewport dimensions
const viewWidth = main.offsetWidth
const viewHeight = main.offsetHeight
// Determine scroll amounts based on mouse position relative to document
let scrollAmountX
if (mouseViewX > viewWidth) {
scrollAmountX = mouseViewX - viewWidth
} else if (mouseViewX < 0) {
scrollAmountX = mouseViewX
} else {
scrollAmountX = 0
}
let scrollAmountY
if (mouseViewY > viewHeight) {
scrollAmountY = mouseViewY - viewHeight
} else if (mouseViewY < 0) {
scrollAmountY = mouseViewY
} else {
scrollAmountY = 0
}
// Scroll (if necessary) to keep mouse on screen.
main.scrollLeft += scrollAmountX
main.scrollTop += scrollAmountY
}
},
beforeDestroy () {
if (this.keyboard){
this.keyboard.onkeydown = null
this.keyboard.onkeyup = null
}
},
watch: {
/**
* Removes the event handlers for the keyboard when options drawer
* is displayed
*
* Restores keyboard event handlers when options drawer is closed
*/
'options.showOptionsDrawer': function (showOptionsDrawer) {
if (!this.keyboard) return
if (!showOptionsDrawer) {
this.keyboard.onkeydown = (keysym) => this.client.sendKeyEvent(1, keysym)
this.keyboard.onkeyup = (keysym) => this.client.sendKeyEvent(0, keysym)
} else {
this.keyboard.onkeydown = null
this.keyboard.onkeyup = null
}
},
/**
* Removes the event handlers for the keyboard when options drawer
* is displayed
*
* Restores keyboard event handlers when options drawer is closed
*/
'viewState': function (viewState) {
if (!this.keyboard) return
if (!(viewState === 'thumbnail')) {
this.keyboard.onkeydown = (keysym) => {
this.updateActivity()
this.client.sendKeyEvent(1, keysym)
}
this.keyboard.onkeyup = (keysym) => this.client.sendKeyEvent(0, keysym)
} else {
this.keyboard.onkeydown = null
this.keyboard.onkeyup = null
}
}
}
}