neko/src/component/overlay.vue

235 lines
5.3 KiB
Vue
Raw Normal View History

2020-11-07 05:59:01 +13:00
<template>
<div
ref="overlay"
class="overlay"
tabindex="0"
@click.stop.prevent
@contextmenu.stop.prevent
@wheel.stop.prevent="onWheel"
@mousemove.stop.prevent="onMouseMove"
@mousedown.stop.prevent="onMouseDown"
@mouseup.stop.prevent="onMouseUp"
@mouseenter.stop.prevent="onMouseEnter"
@mouseleave.stop.prevent="onMouseLeave"
2021-01-08 08:21:40 +13:00
@dragenter.stop.prevent="onDrag"
@dragleave.stop.prevent="onDrag"
@dragover.stop.prevent="onDrag"
@drop.stop.prevent="onDrop"
2020-11-07 05:59:01 +13:00
/>
</template>
<style lang="scss" scoped>
.overlay {
position: absolute;
top: 0;
bottom: 0;
width: 100%;
height: 100%;
2020-11-07 08:48:19 +13:00
outline: 0;
2020-11-07 05:59:01 +13:00
}
</style>
<script lang="ts">
2020-12-02 22:45:23 +13:00
import { Vue, Component, Ref, Prop, Watch } from 'vue-property-decorator'
2020-11-07 08:48:19 +13:00
2020-11-29 09:47:16 +13:00
import GuacamoleKeyboard from './utils/guacamole-keyboard'
import { NekoWebRTC } from './internal/webrtc'
2020-11-07 05:59:01 +13:00
@Component({
name: 'neko-overlay',
})
export default class extends Vue {
@Ref('overlay') readonly _overlay!: HTMLElement
private keyboard = GuacamoleKeyboard()
private focused = false
@Prop()
private readonly webrtc!: NekoWebRTC
@Prop()
private readonly screenWidth!: number
@Prop()
private readonly screenHeight!: number
@Prop()
private readonly scrollSensitivity!: number
@Prop()
private readonly scrollInvert!: boolean
@Prop()
private readonly isControling!: boolean
2020-12-02 22:45:23 +13:00
@Prop()
private readonly implicitControl!: boolean
2020-11-07 05:59:01 +13:00
mounted() {
// Initialize Guacamole Keyboard
this.keyboard.onkeydown = (key: number) => {
2020-12-02 22:45:23 +13:00
if (!this.focused) {
return true
}
if (!this.isControling) {
this.implicitControlRequest()
2020-11-07 05:59:01 +13:00
return true
}
this.webrtc.send('keydown', { key })
return false
}
this.keyboard.onkeyup = (key: number) => {
2020-12-02 22:45:23 +13:00
if (!this.focused) {
return
}
if (!this.isControling) {
this.implicitControlRequest()
2020-11-07 05:59:01 +13:00
return
}
this.webrtc.send('keyup', { key })
}
this.keyboard.listenTo(this._overlay)
}
beforeDestroy() {
// Guacamole Keyboard does not provide destroy functions
}
2021-01-08 08:21:40 +13:00
getMousePos(clientX: number, clientY: number) {
2020-11-07 05:59:01 +13:00
const rect = this._overlay.getBoundingClientRect()
2021-01-08 08:21:40 +13:00
return {
x: Math.round((this.screenWidth / rect.width) * (clientX - rect.left)),
y: Math.round((this.screenHeight / rect.height) * (clientY - rect.top)),
}
}
setMousePos(e: MouseEvent) {
this.webrtc.send('mousemove', this.getMousePos(e.clientX, e.clientY))
2020-11-07 05:59:01 +13:00
}
onWheel(e: WheelEvent) {
if (!this.isControling) {
2020-12-02 22:45:23 +13:00
this.implicitControlRequest()
2020-11-07 05:59:01 +13:00
return
}
let x = e.deltaX
let y = e.deltaY
if (this.scrollInvert) {
x *= -1
y *= -1
}
x = Math.min(Math.max(x, -this.scrollSensitivity), this.scrollSensitivity)
y = Math.min(Math.max(y, -this.scrollSensitivity), this.scrollSensitivity)
this.setMousePos(e)
this.webrtc.send('wheel', { x, y })
}
onMouseMove(e: MouseEvent) {
if (!this.isControling) {
2020-12-02 22:45:23 +13:00
this.implicitControlRequest()
2020-11-07 05:59:01 +13:00
return
}
this.setMousePos(e)
}
onMouseDown(e: MouseEvent) {
if (!this.isControling) {
2020-12-02 22:45:23 +13:00
this.implicitControlRequest()
2020-11-07 05:59:01 +13:00
return
}
this.setMousePos(e)
this.webrtc.send('mousedown', { key: e.button + 1 })
}
onMouseUp(e: MouseEvent) {
if (!this.isControling) {
2020-12-02 22:45:23 +13:00
this.implicitControlRequest()
2020-11-07 05:59:01 +13:00
return
}
this.setMousePos(e)
this.webrtc.send('mouseup', { key: e.button + 1 })
}
onMouseEnter(e: MouseEvent) {
this._overlay.focus()
this.focused = true
if (!this.isControling) {
2020-12-02 22:45:23 +13:00
this.implicitControlRequest()
// TODO: Refactor
//syncKeyboardModifierState({
// capsLock: e.getModifierState('CapsLock'),
// numLock: e.getModifierState('NumLock'),
// scrollLock: e.getModifierState('ScrollLock'),
//})
2020-11-07 05:59:01 +13:00
}
2020-12-02 22:45:23 +13:00
}
2020-11-07 05:59:01 +13:00
2020-12-02 22:45:23 +13:00
onMouseLeave(e: MouseEvent) {
2020-11-07 05:59:01 +13:00
this._overlay.blur()
this.focused = false
2020-12-02 22:45:23 +13:00
if (this.isControling) {
this.keyboard.reset()
this.implicitControlRelease()
// TODO: Refactor
//setKeyboardModifierState({
// capsLock: e.getModifierState('CapsLock'),
// numLock: e.getModifierState('NumLock'),
// scrollLock: e.getModifierState('ScrollLock'),
//})
}
}
2021-01-08 08:21:40 +13:00
onDrag(e: DragEvent) {
e.preventDefault()
e.stopPropagation()
}
onDrop(e: DragEvent) {
e.preventDefault()
e.stopPropagation()
let dt = e.dataTransfer
if (!dt) return
let files = [...dt.files]
if (!files) return
this.$emit('drop-files', { ...this.getMousePos(e.clientX, e.clientY), files })
}
2020-12-02 22:45:23 +13:00
isRequesting = false
@Watch('isControling')
onControlChange(isControling: boolean) {
this.isRequesting = false
}
implicitControlRequest() {
if (!this.isRequesting && this.implicitControl) {
this.isRequesting = true
this.$emit('implicit-control-request')
}
}
implicitControlRelease() {
if (this.implicitControl) {
this.$emit('implicit-control-release')
}
2020-11-07 05:59:01 +13:00
}
}
</script>