neko/src/component/internal/control.ts
Miroslav Šedivý 4918c62c9a
Add support for touch gestures (#40)
* implement control using webrtc.

* overlay to use NekoControl.

* WIP.

* add is_host to control state.

* control use webrtc only if hosting.

* add proper links to 3rd party code.

* fix button events for gestureHandler.

* lint.

* fix implicit control gain for touch events.
2023-07-07 14:59:54 +02:00

131 lines
3.8 KiB
TypeScript

import Vue from 'vue'
import * as EVENT from '../types/events'
import * as message from '../types/messages'
import EventEmitter from 'eventemitter3'
import { NekoConnection } from './connection'
import { Control } from '../types/state'
export interface NekoControlEvents {
['overlay.click']: (e: MouseEvent) => void
['overlay.contextmenu']: (e: MouseEvent) => void
}
export interface ControlPos {
x: number
y: number
}
export class NekoControl extends EventEmitter<NekoControlEvents> {
// eslint-disable-next-line
constructor(
private readonly _connection: NekoConnection,
private readonly _state: Control,
) {
super()
}
get useWebrtc() {
// we want to use webrtc if we're connected and we're the host
// because webrtc is faster and it doesn't request control
// in contrast to the websocket
return this._connection.webrtc.connected && this._state.is_host
}
public lock() {
Vue.set(this._state, 'locked', true)
}
public unlock() {
Vue.set(this._state, 'locked', false)
}
public request() {
this._connection.websocket.send(EVENT.CONTROL_REQUEST)
}
public release() {
this._connection.websocket.send(EVENT.CONTROL_RELEASE)
}
public move(pos: ControlPos) {
if (this.useWebrtc) {
this._connection.webrtc.send('mousemove', pos)
} else {
this._connection.websocket.send(EVENT.CONTROL_MOVE, pos as message.ControlPos)
}
}
// TODO: rename pos to delta, and add a new pos parameter
public scroll(pos: ControlPos) {
if (this.useWebrtc) {
this._connection.webrtc.send('wheel', pos)
} else {
this._connection.websocket.send(EVENT.CONTROL_SCROLL, pos as message.ControlPos)
}
}
// buttonpress ensures that only one button is pressed at a time
public buttonPress(code: number, pos?: ControlPos) {
this._connection.websocket.send(EVENT.CONTROL_BUTTONPRESS, { code, ...pos } as message.ControlButton)
}
public buttonDown(code: number, pos?: ControlPos) {
if (this.useWebrtc) {
if (pos) this._connection.webrtc.send('mousemove', pos)
this._connection.webrtc.send('mousedown', { key: code })
} else {
this._connection.websocket.send(EVENT.CONTROL_BUTTONDOWN, { code, ...pos } as message.ControlButton)
}
}
public buttonUp(code: number, pos?: ControlPos) {
if (this.useWebrtc) {
if (pos) this._connection.webrtc.send('mousemove', pos)
this._connection.webrtc.send('mouseup', { key: code })
} else {
this._connection.websocket.send(EVENT.CONTROL_BUTTONUP, { code, ...pos } as message.ControlButton)
}
}
// keypress ensures that only one key is pressed at a time
public keyPress(keysym: number, pos?: ControlPos) {
this._connection.websocket.send(EVENT.CONTROL_KEYPRESS, { keysym, ...pos } as message.ControlKey)
}
public keyDown(keysym: number, pos?: ControlPos) {
if (this.useWebrtc) {
if (pos) this._connection.webrtc.send('mousemove', pos)
this._connection.webrtc.send('keydown', { key: keysym })
} else {
this._connection.websocket.send(EVENT.CONTROL_KEYDOWN, { keysym, ...pos } as message.ControlKey)
}
}
public keyUp(keysym: number, pos?: ControlPos) {
if (this.useWebrtc) {
if (pos) this._connection.webrtc.send('mousemove', pos)
this._connection.webrtc.send('keyup', { key: keysym })
} else {
this._connection.websocket.send(EVENT.CONTROL_KEYUP, { keysym, ...pos } as message.ControlKey)
}
}
public cut() {
this._connection.websocket.send(EVENT.CONTROL_CUT)
}
public copy() {
this._connection.websocket.send(EVENT.CONTROL_COPY)
}
public paste(text?: string) {
this._connection.websocket.send(EVENT.CONTROL_PASTE, { text } as message.ClipboardData)
}
public selectAll() {
this._connection.websocket.send(EVENT.CONTROL_SELECT_ALL)
}
}