mirror of
https://github.com/m1k1o/neko.git
synced 2024-07-24 14:40:50 +12:00
do not use ref where not needed.
This commit is contained in:
parent
93125abfd7
commit
3a96d2611e
@ -38,16 +38,16 @@ const props = defineProps<{
|
||||
}>()
|
||||
|
||||
const overlay = ref<HTMLCanvasElement | null>(null)
|
||||
const ctx = ref<CanvasRenderingContext2D | null>(null)
|
||||
const canvasScale = ref(window.devicePixelRatio)
|
||||
|
||||
let ctx: CanvasRenderingContext2D | null = null
|
||||
let canvasScale = window.devicePixelRatio
|
||||
let unsubscribePixelRatioChange = null as (() => void) | null
|
||||
|
||||
onMounted(() => {
|
||||
// get canvas overlay context
|
||||
const canvas = overlay.value
|
||||
if (canvas != null) {
|
||||
ctx.value = canvas.getContext('2d')
|
||||
ctx = canvas.getContext('2d')
|
||||
|
||||
// synchronize intrinsic with extrinsic dimensions
|
||||
const { width, height } = canvas.getBoundingClientRect()
|
||||
@ -58,7 +58,7 @@ onMounted(() => {
|
||||
onPixelRatioChange()
|
||||
|
||||
// store last drawing points
|
||||
last_points.value = {}
|
||||
last_points = {}
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
@ -79,7 +79,7 @@ function onPixelRatioChange() {
|
||||
media.removeEventListener('change', onPixelRatioChange)
|
||||
}
|
||||
|
||||
canvasScale.value = window.devicePixelRatio
|
||||
canvasScale = window.devicePixelRatio
|
||||
onCanvasSizeChange(props.canvasSize)
|
||||
}
|
||||
|
||||
@ -91,42 +91,42 @@ function onCanvasSizeChange({ width, height }: Dimension) {
|
||||
watch(() => props.canvasSize, onCanvasSizeChange)
|
||||
|
||||
function canvasResize({ width, height }: Dimension) {
|
||||
overlay.value!.width = width * canvasScale.value
|
||||
overlay.value!.height = height * canvasScale.value
|
||||
ctx.value?.setTransform(canvasScale.value, 0, 0, canvasScale.value, 0, 0)
|
||||
overlay.value!.width = width * canvasScale
|
||||
overlay.value!.height = height * canvasScale
|
||||
ctx?.setTransform(canvasScale, 0, 0, canvasScale, 0, 0)
|
||||
}
|
||||
|
||||
// start as undefined to prevent jumping
|
||||
const last_animation_time = ref<number>(0)
|
||||
let last_animation_time = 0
|
||||
// current animation progress (0-1)
|
||||
const percent = ref<number>(0)
|
||||
let percent = 0
|
||||
// points to be animated for each session
|
||||
const points = ref<SessionCursors[]>([])
|
||||
let points: SessionCursors[] = []
|
||||
// last points coordinates for each session
|
||||
const last_points = ref<Record<string, Cursor>>({})
|
||||
let last_points: Record<string, Cursor> = {}
|
||||
|
||||
function canvasAnimateFrame(now: number = NaN) {
|
||||
// request another frame
|
||||
if (percent.value <= 1) window.requestAnimationFrame(canvasAnimateFrame)
|
||||
if (percent <= 1) window.requestAnimationFrame(canvasAnimateFrame)
|
||||
|
||||
// calc elapsed time since last loop
|
||||
const elapsed = now - last_animation_time.value
|
||||
const elapsed = now - last_animation_time
|
||||
|
||||
// skip if fps is set and elapsed time is less than fps
|
||||
if (props.fps > 0 && elapsed < 1000 / props.fps) return
|
||||
|
||||
// calc current animation progress
|
||||
const delta = elapsed / POS_INTERVAL_MS
|
||||
last_animation_time.value = now
|
||||
last_animation_time = now
|
||||
|
||||
// skip very first delta to prevent jumping
|
||||
if (isNaN(delta)) return
|
||||
|
||||
// set the animation position
|
||||
percent.value += delta
|
||||
percent += delta
|
||||
|
||||
// draw points for current frame
|
||||
canvasDrawPoints(percent.value)
|
||||
canvasDrawPoints(percent)
|
||||
}
|
||||
|
||||
function canvasDrawPoints(percent: number = 1) {
|
||||
@ -134,7 +134,7 @@ function canvasDrawPoints(percent: number = 1) {
|
||||
canvasClear()
|
||||
|
||||
// draw current position
|
||||
for (const p of points.value) {
|
||||
for (const p of points) {
|
||||
const { x, y } = getMovementXYatPercent(p.cursors, percent)
|
||||
canvasDrawCursor(x, y, p.id)
|
||||
}
|
||||
@ -147,7 +147,7 @@ function canvasUpdateCursors() {
|
||||
let unchanged = 0
|
||||
|
||||
// create points for animation
|
||||
points.value = []
|
||||
points = []
|
||||
for (const { id, cursors } of props.cursors) {
|
||||
if (
|
||||
// if there are no positions
|
||||
@ -166,8 +166,8 @@ function canvasUpdateCursors() {
|
||||
|
||||
// add last cursor position to cursors (if available)
|
||||
let pos = { id } as SessionCursors
|
||||
if (id in last_points.value) {
|
||||
const last_point = last_points.value[id]
|
||||
if (id in last_points) {
|
||||
const last_point = last_points[id]
|
||||
|
||||
// if cursor did not move considerably
|
||||
if (
|
||||
@ -191,14 +191,14 @@ function canvasUpdateCursors() {
|
||||
}
|
||||
|
||||
new_last_points[id] = new_last_point
|
||||
points.value.push(pos)
|
||||
points.push(pos)
|
||||
}
|
||||
|
||||
// apply new last points
|
||||
last_points.value = new_last_points
|
||||
last_points = new_last_points
|
||||
|
||||
// no cursors to animate
|
||||
if (points.value.length == 0) {
|
||||
if (points.length == 0) {
|
||||
canvasClear()
|
||||
return
|
||||
}
|
||||
@ -211,8 +211,8 @@ function canvasUpdateCursors() {
|
||||
}
|
||||
|
||||
// start animation if not running
|
||||
const p = percent.value
|
||||
percent.value = 0
|
||||
const p = percent
|
||||
percent = 0
|
||||
if (p > 1 || !p) {
|
||||
canvasAnimateFrame()
|
||||
}
|
||||
@ -222,17 +222,19 @@ watch(() => props.hostId, canvasUpdateCursors)
|
||||
watch(() => props.cursors, canvasUpdateCursors)
|
||||
|
||||
function canvasDrawCursor(x: number, y: number, id: string) {
|
||||
if (!ctx) return
|
||||
|
||||
// get intrinsic dimensions
|
||||
const { width, height } = props.canvasSize
|
||||
x = Math.round((x / props.screenSize.width) * width)
|
||||
y = Math.round((y / props.screenSize.height) * height)
|
||||
|
||||
// reset transformation, X and Y will be 0 again
|
||||
ctx.value!.setTransform(canvasScale.value, 0, 0, canvasScale.value, 0, 0)
|
||||
ctx.setTransform(canvasScale, 0, 0, canvasScale, 0, 0)
|
||||
|
||||
// use custom draw function, if available
|
||||
if (props.cursorDraw) {
|
||||
props.cursorDraw(ctx.value!, x, y, id)
|
||||
props.cursorDraw(ctx, x, y, id)
|
||||
return
|
||||
}
|
||||
|
||||
@ -240,23 +242,25 @@ function canvasDrawCursor(x: number, y: number, id: string) {
|
||||
const cursorTag = props.sessions[id]?.profile.name || ''
|
||||
|
||||
// draw inactive cursor tag
|
||||
ctx.value!.font = '14px Arial, sans-serif'
|
||||
ctx.value!.textBaseline = 'top'
|
||||
ctx.value!.shadowColor = 'black'
|
||||
ctx.value!.shadowBlur = 2
|
||||
ctx.value!.lineWidth = 2
|
||||
ctx.value!.fillStyle = 'black'
|
||||
ctx.value!.strokeText(cursorTag, x, y)
|
||||
ctx.value!.shadowBlur = 0
|
||||
ctx.value!.fillStyle = 'white'
|
||||
ctx.value!.fillText(cursorTag, x, y)
|
||||
ctx.font = '14px Arial, sans-serif'
|
||||
ctx.textBaseline = 'top'
|
||||
ctx.shadowColor = 'black'
|
||||
ctx.shadowBlur = 2
|
||||
ctx.lineWidth = 2
|
||||
ctx.fillStyle = 'black'
|
||||
ctx.strokeText(cursorTag, x, y)
|
||||
ctx.shadowBlur = 0
|
||||
ctx.fillStyle = 'white'
|
||||
ctx.fillText(cursorTag, x, y)
|
||||
}
|
||||
|
||||
function canvasClear() {
|
||||
if (!ctx) return
|
||||
|
||||
// reset transformation, X and Y will be 0 again
|
||||
ctx.value?.setTransform(canvasScale.value, 0, 0, canvasScale.value, 0, 0)
|
||||
ctx.setTransform(canvasScale, 0, 0, canvasScale, 0, 0)
|
||||
|
||||
const { width, height } = props.canvasSize
|
||||
ctx.value?.clearRect(0, 0, width, height)
|
||||
ctx.clearRect(0, 0, width, height)
|
||||
}
|
||||
</script>
|
||||
|
@ -266,7 +266,7 @@ const events = new NekoMessages(connection, state)
|
||||
// Public methods
|
||||
/////////////////////////////
|
||||
|
||||
function setUrl(url: string) {
|
||||
function setUrl(url?: string) {
|
||||
if (!url) {
|
||||
url = location.href
|
||||
}
|
||||
@ -302,7 +302,7 @@ function setUrl(url: string) {
|
||||
}
|
||||
|
||||
watch(() => props.server, (url) => {
|
||||
url && setUrl(url)
|
||||
setUrl(url)
|
||||
}, { immediate: true })
|
||||
|
||||
async function authenticate(token?: string) {
|
||||
@ -641,15 +641,15 @@ function onScreenSyncChange() {
|
||||
|
||||
watch(() => state.screen.sync.enabled, onScreenSyncChange)
|
||||
|
||||
const syncScreenSizeTimeout = ref(0)
|
||||
let syncScreenSizeTimeout = 0
|
||||
|
||||
function syncScreenSize() {
|
||||
if (syncScreenSizeTimeout.value) {
|
||||
window.clearTimeout(syncScreenSizeTimeout.value)
|
||||
if (syncScreenSizeTimeout) {
|
||||
window.clearTimeout(syncScreenSizeTimeout)
|
||||
}
|
||||
syncScreenSizeTimeout.value = window.setTimeout(() => {
|
||||
syncScreenSizeTimeout = window.setTimeout(() => {
|
||||
const multiplier = state.screen.sync.multiplier || window.devicePixelRatio
|
||||
syncScreenSizeTimeout.value = 0
|
||||
syncScreenSizeTimeout = 0
|
||||
const { offsetWidth, offsetHeight } = component.value!
|
||||
setScreenSize(
|
||||
Math.round(offsetWidth * multiplier),
|
||||
|
@ -76,15 +76,15 @@ const INACTIVE_CURSOR_INTERVAL = 1000 / 4 // in ms, 4fps
|
||||
|
||||
const overlay = ref<HTMLCanvasElement | null>(null)
|
||||
const textarea = ref<HTMLTextAreaElement | null>(null)
|
||||
const ctx = ref<CanvasRenderingContext2D | null>(null)
|
||||
|
||||
const canvasScale = ref(window.devicePixelRatio)
|
||||
let ctx: CanvasRenderingContext2D | null = null
|
||||
let canvasScale = window.devicePixelRatio
|
||||
|
||||
const keyboard = ref<KeyboardInterface | null>(null)
|
||||
const gestureHandler = ref<GestureHandler | null>(null)
|
||||
const textInput = ref('')
|
||||
let keyboard: KeyboardInterface = NewKeyboard()
|
||||
let gestureHandler: GestureHandler = new GestureHandlerInit()
|
||||
|
||||
const focused = ref(false)
|
||||
const textInput = ref('')
|
||||
|
||||
// props and emits
|
||||
|
||||
@ -124,10 +124,7 @@ onMounted(() => {
|
||||
window.addEventListener('mouseup', onMouseUp, true)
|
||||
|
||||
// get canvas overlay context
|
||||
const _ctx = overlay.value?.getContext('2d')
|
||||
if (_ctx != null) {
|
||||
ctx.value = _ctx
|
||||
}
|
||||
ctx = overlay.value!.getContext('2d')
|
||||
|
||||
// synchronize intrinsic with extrinsic dimensions
|
||||
const { width, height } = overlay.value?.getBoundingClientRect() || { width: 0, height: 0 }
|
||||
@ -140,8 +137,7 @@ onMounted(() => {
|
||||
let noKeyUp = {} as Record<number, boolean>
|
||||
|
||||
// Initialize Keyboard
|
||||
keyboard.value = NewKeyboard()
|
||||
keyboard.value.onkeydown = (key: number) => {
|
||||
keyboard.onkeydown = (key: number) => {
|
||||
key = keySymsRemap(key)
|
||||
|
||||
if (!props.isControling) {
|
||||
@ -151,7 +147,7 @@ onMounted(() => {
|
||||
|
||||
// ctrl+v is aborted
|
||||
if (ctrlKey != 0 && key == KeyTable.XK_v) {
|
||||
keyboard.value!.release(ctrlKey)
|
||||
keyboard!.release(ctrlKey)
|
||||
noKeyUp[key] = true
|
||||
return true
|
||||
}
|
||||
@ -163,7 +159,7 @@ onMounted(() => {
|
||||
props.control.keyDown(key)
|
||||
return isCtrlKey
|
||||
}
|
||||
keyboard.value.onkeyup = (key: number) => {
|
||||
keyboard.onkeyup = (key: number) => {
|
||||
key = keySymsRemap(key)
|
||||
|
||||
if (key in noKeyUp) {
|
||||
@ -176,10 +172,7 @@ onMounted(() => {
|
||||
|
||||
props.control.keyUp(key)
|
||||
}
|
||||
keyboard.value.listenTo(textarea.value!)
|
||||
|
||||
// Initialize GestureHandler
|
||||
gestureHandler.value = new GestureHandlerInit()
|
||||
keyboard.listenTo(textarea.value!)
|
||||
|
||||
// bind touch handler using @Watch on supportedTouchEvents
|
||||
// because we need to know if touch events are supported
|
||||
@ -196,10 +189,7 @@ onMounted(() => {
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
window.removeEventListener('mouseup', onMouseUp, true)
|
||||
|
||||
if (keyboard.value) {
|
||||
keyboard.value.removeListener()
|
||||
}
|
||||
keyboard.removeListener()
|
||||
|
||||
// unbind touch handler
|
||||
unbindTouchHandler()
|
||||
@ -216,8 +206,8 @@ onBeforeUnmount(() => {
|
||||
clearInactiveCursorInterval()
|
||||
|
||||
// stop pixel ratio change listener
|
||||
if (unsubscribePixelRatioChange.value) {
|
||||
unsubscribePixelRatioChange.value()
|
||||
if (unsubscribePixelRatioChange) {
|
||||
unsubscribePixelRatioChange()
|
||||
}
|
||||
})
|
||||
|
||||
@ -280,23 +270,23 @@ function onTouchHandler(ev: TouchEvent) {
|
||||
//
|
||||
|
||||
function bindGestureHandler() {
|
||||
gestureHandler.value?.attach(textarea.value!)
|
||||
gestureHandler.attach(textarea.value!)
|
||||
textarea.value?.addEventListener('gesturestart', onGestureHandler)
|
||||
textarea.value?.addEventListener('gesturemove', onGestureHandler)
|
||||
textarea.value?.addEventListener('gestureend', onGestureHandler)
|
||||
}
|
||||
|
||||
function unbindGestureHandler() {
|
||||
gestureHandler.value?.detach()
|
||||
gestureHandler.detach()
|
||||
textarea.value?.removeEventListener('gesturestart', onGestureHandler)
|
||||
textarea.value?.removeEventListener('gesturemove', onGestureHandler)
|
||||
textarea.value?.removeEventListener('gestureend', onGestureHandler)
|
||||
}
|
||||
|
||||
const gestureLastTapTime = ref<number | null>(null)
|
||||
const gestureFirstDoubleTapEv = ref<any | null>(null)
|
||||
const gestureLastMagnitudeX = ref(0)
|
||||
const gestureLastMagnitudeY = ref(0)
|
||||
let gestureLastTapTime: number | null = null
|
||||
let gestureFirstDoubleTapEv: any | null = null
|
||||
let gestureLastMagnitudeX = 0
|
||||
let gestureLastMagnitudeY = 0
|
||||
|
||||
function _handleTapEvent(ev: any, code: number) {
|
||||
let pos = getMousePos(ev.detail.clientX, ev.detail.clientY)
|
||||
@ -305,23 +295,23 @@ function _handleTapEvent(ev: any, code: number) {
|
||||
// hit the same spot, so slightly adjust coordinates
|
||||
|
||||
if (
|
||||
gestureLastTapTime.value !== null &&
|
||||
Date.now() - gestureLastTapTime.value < DOUBLE_TAP_TIMEOUT &&
|
||||
gestureFirstDoubleTapEv.value?.detail.type === ev.detail.type
|
||||
gestureLastTapTime !== null &&
|
||||
Date.now() - gestureLastTapTime < DOUBLE_TAP_TIMEOUT &&
|
||||
gestureFirstDoubleTapEv?.detail.type === ev.detail.type
|
||||
) {
|
||||
const dx = gestureFirstDoubleTapEv.value.detail.clientX - ev.detail.clientX
|
||||
const dy = gestureFirstDoubleTapEv.value.detail.clientY - ev.detail.clientY
|
||||
const dx = gestureFirstDoubleTapEv.detail.clientX - ev.detail.clientX
|
||||
const dy = gestureFirstDoubleTapEv.detail.clientY - ev.detail.clientY
|
||||
const distance = Math.hypot(dx, dy)
|
||||
|
||||
if (distance < DOUBLE_TAP_THRESHOLD) {
|
||||
pos = getMousePos(gestureFirstDoubleTapEv.value.detail.clientX, gestureFirstDoubleTapEv.value.detail.clientY)
|
||||
pos = getMousePos(gestureFirstDoubleTapEv.detail.clientX, gestureFirstDoubleTapEv.detail.clientY)
|
||||
} else {
|
||||
gestureFirstDoubleTapEv.value = ev
|
||||
gestureFirstDoubleTapEv = ev
|
||||
}
|
||||
} else {
|
||||
gestureFirstDoubleTapEv.value = ev
|
||||
gestureFirstDoubleTapEv = ev
|
||||
}
|
||||
gestureLastTapTime.value = Date.now()
|
||||
gestureLastTapTime = Date.now()
|
||||
|
||||
props.control.buttonDown(code, pos)
|
||||
props.control.buttonUp(code, pos)
|
||||
@ -361,12 +351,12 @@ function onGestureHandler(ev: any) {
|
||||
break
|
||||
|
||||
case 'twodrag':
|
||||
gestureLastMagnitudeX.value = ev.detail.magnitudeX
|
||||
gestureLastMagnitudeY.value = ev.detail.magnitudeY
|
||||
gestureLastMagnitudeX = ev.detail.magnitudeX
|
||||
gestureLastMagnitudeY = ev.detail.magnitudeY
|
||||
props.control.move(pos)
|
||||
break
|
||||
case 'pinch':
|
||||
gestureLastMagnitudeX.value = Math.hypot(ev.detail.magnitudeX, ev.detail.magnitudeY)
|
||||
gestureLastMagnitudeX = Math.hypot(ev.detail.magnitudeX, ev.detail.magnitudeY)
|
||||
props.control.move(pos)
|
||||
break
|
||||
}
|
||||
@ -387,21 +377,21 @@ function onGestureHandler(ev: any) {
|
||||
// We don't know if the mouse was moved so we need to move it
|
||||
// every update.
|
||||
props.control.move(pos)
|
||||
while (ev.detail.magnitudeY - gestureLastMagnitudeY.value > GESTURE_SCRLSENS) {
|
||||
while (ev.detail.magnitudeY - gestureLastMagnitudeY > GESTURE_SCRLSENS) {
|
||||
props.control.scroll({ delta_x: 0, delta_y: 1 })
|
||||
gestureLastMagnitudeY.value += GESTURE_SCRLSENS
|
||||
gestureLastMagnitudeY += GESTURE_SCRLSENS
|
||||
}
|
||||
while (ev.detail.magnitudeY - gestureLastMagnitudeY.value < -GESTURE_SCRLSENS) {
|
||||
while (ev.detail.magnitudeY - gestureLastMagnitudeY < -GESTURE_SCRLSENS) {
|
||||
props.control.scroll({ delta_x: 0, delta_y: -1 })
|
||||
gestureLastMagnitudeY.value -= GESTURE_SCRLSENS
|
||||
gestureLastMagnitudeY -= GESTURE_SCRLSENS
|
||||
}
|
||||
while (ev.detail.magnitudeX - gestureLastMagnitudeX.value > GESTURE_SCRLSENS) {
|
||||
while (ev.detail.magnitudeX - gestureLastMagnitudeX > GESTURE_SCRLSENS) {
|
||||
props.control.scroll({ delta_x: 1, delta_y: 0 })
|
||||
gestureLastMagnitudeX.value += GESTURE_SCRLSENS
|
||||
gestureLastMagnitudeX+= GESTURE_SCRLSENS
|
||||
}
|
||||
while (ev.detail.magnitudeX - gestureLastMagnitudeX.value < -GESTURE_SCRLSENS) {
|
||||
while (ev.detail.magnitudeX - gestureLastMagnitudeX < -GESTURE_SCRLSENS) {
|
||||
props.control.scroll({ delta_x: -1, delta_y: 0 })
|
||||
gestureLastMagnitudeX.value -= GESTURE_SCRLSENS
|
||||
gestureLastMagnitudeX-= GESTURE_SCRLSENS
|
||||
}
|
||||
break
|
||||
case 'pinch':
|
||||
@ -410,14 +400,14 @@ function onGestureHandler(ev: any) {
|
||||
// every update.
|
||||
props.control.move(pos)
|
||||
magnitude = Math.hypot(ev.detail.magnitudeX, ev.detail.magnitudeY)
|
||||
if (Math.abs(magnitude - gestureLastMagnitudeX.value) > GESTURE_ZOOMSENS) {
|
||||
while (magnitude - gestureLastMagnitudeX.value > GESTURE_ZOOMSENS) {
|
||||
if (Math.abs(magnitude - gestureLastMagnitudeX) > GESTURE_ZOOMSENS) {
|
||||
while (magnitude - gestureLastMagnitudeX > GESTURE_ZOOMSENS) {
|
||||
props.control.scroll({ delta_x: 0, delta_y: 1, control_key: true })
|
||||
gestureLastMagnitudeX.value += GESTURE_ZOOMSENS
|
||||
gestureLastMagnitudeX+= GESTURE_ZOOMSENS
|
||||
}
|
||||
while (magnitude - gestureLastMagnitudeX.value < -GESTURE_ZOOMSENS) {
|
||||
while (magnitude - gestureLastMagnitudeX < -GESTURE_ZOOMSENS) {
|
||||
props.control.scroll({ delta_x: 0, delta_y: -1, control_key: true })
|
||||
gestureLastMagnitudeX.value -= GESTURE_ZOOMSENS
|
||||
gestureLastMagnitudeX-= GESTURE_ZOOMSENS
|
||||
}
|
||||
}
|
||||
break
|
||||
@ -500,12 +490,12 @@ function sendMousePos(e: MouseEvent) {
|
||||
if (props.webrtc.connected) {
|
||||
props.webrtc.send('mousemove', pos)
|
||||
} // otherwise, no events are sent
|
||||
cursorPosition.value = pos
|
||||
cursorPosition = pos
|
||||
}
|
||||
|
||||
const wheelX = ref(0)
|
||||
const wheelY = ref(0)
|
||||
const wheelTimeStamp = ref(0)
|
||||
let wheelX = 0
|
||||
let wheelY = 0
|
||||
let wheelTimeStamp = 0
|
||||
|
||||
// negative sensitivity can be acheived using increased step value
|
||||
const wheelStep = computed(() => {
|
||||
@ -550,12 +540,12 @@ function onWheel(e: WheelEvent) {
|
||||
}
|
||||
|
||||
// when the last scroll was more than 250ms ago
|
||||
const firstScroll = e.timeStamp - wheelTimeStamp.value > 250
|
||||
const firstScroll = e.timeStamp - wheelTimeStamp > 250
|
||||
|
||||
if (firstScroll) {
|
||||
wheelX.value = 0
|
||||
wheelY.value = 0
|
||||
wheelTimeStamp.value = e.timeStamp
|
||||
wheelX = 0
|
||||
wheelY = 0
|
||||
wheelTimeStamp = e.timeStamp
|
||||
}
|
||||
|
||||
let dx = e.deltaX
|
||||
@ -566,32 +556,32 @@ function onWheel(e: WheelEvent) {
|
||||
dy *= WHEEL_LINE_HEIGHT
|
||||
}
|
||||
|
||||
wheelX.value += dx
|
||||
wheelY.value += dy
|
||||
wheelX += dx
|
||||
wheelY += dy
|
||||
|
||||
let x = 0
|
||||
if (Math.abs(wheelX.value) >= wheelStep.value || firstScroll) {
|
||||
if (wheelX.value < 0) {
|
||||
if (Math.abs(wheelX) >= wheelStep.value || firstScroll) {
|
||||
if (wheelX < 0) {
|
||||
x = wheelSensitivity.value * -1
|
||||
} else if (wheelX.value > 0) {
|
||||
} else if (wheelX > 0) {
|
||||
x = wheelSensitivity.value
|
||||
}
|
||||
|
||||
if (!firstScroll) {
|
||||
wheelX.value = 0
|
||||
wheelX = 0
|
||||
}
|
||||
}
|
||||
|
||||
let y = 0
|
||||
if (Math.abs(wheelY.value) >= wheelStep.value || firstScroll) {
|
||||
if (wheelY.value < 0) {
|
||||
if (Math.abs(wheelY) >= wheelStep.value || firstScroll) {
|
||||
if (wheelY < 0) {
|
||||
y = wheelSensitivity.value * -1
|
||||
} else if (wheelY.value > 0) {
|
||||
} else if (wheelY > 0) {
|
||||
y = wheelSensitivity.value
|
||||
}
|
||||
|
||||
if (!firstScroll) {
|
||||
wheelY.value = 0
|
||||
wheelY = 0
|
||||
}
|
||||
}
|
||||
|
||||
@ -606,12 +596,12 @@ function onWheel(e: WheelEvent) {
|
||||
})
|
||||
}
|
||||
|
||||
const lastMouseMove = ref(0)
|
||||
let lastMouseMove = 0
|
||||
|
||||
function onMouseMove(e: MouseEvent) {
|
||||
// throttle mousemove events
|
||||
if (e.timeStamp - lastMouseMove.value < MOUSE_MOVE_THROTTLE) return
|
||||
lastMouseMove.value = e.timeStamp
|
||||
if (e.timeStamp - lastMouseMove < MOUSE_MOVE_THROTTLE) return
|
||||
lastMouseMove = e.timeStamp
|
||||
|
||||
if (props.isControling) {
|
||||
sendMousePos(e)
|
||||
@ -622,10 +612,10 @@ function onMouseMove(e: MouseEvent) {
|
||||
}
|
||||
}
|
||||
|
||||
const isMouseDown = ref(false)
|
||||
let isMouseDown = false
|
||||
|
||||
function onMouseDown(e: MouseEvent) {
|
||||
isMouseDown.value = true
|
||||
isMouseDown = true
|
||||
|
||||
if (!props.isControling) {
|
||||
implicitControlRequest(e)
|
||||
@ -639,8 +629,8 @@ function onMouseDown(e: MouseEvent) {
|
||||
|
||||
function onMouseUp(e: MouseEvent) {
|
||||
// only if we are the one who started the mouse down
|
||||
if (!isMouseDown.value) return
|
||||
isMouseDown.value = false
|
||||
if (!isMouseDown) return
|
||||
isMouseDown = false
|
||||
|
||||
if (!props.isControling) {
|
||||
implicitControlRequest(e)
|
||||
@ -668,7 +658,7 @@ function onMouseEnter(e: MouseEvent) {
|
||||
function onMouseLeave(e: MouseEvent) {
|
||||
if (props.isControling) {
|
||||
// save current keyboard modifiers state
|
||||
keyboardModifiers.value = getModifierState(e)
|
||||
keyboardModifiers = getModifierState(e)
|
||||
}
|
||||
|
||||
focused.value = false
|
||||
@ -703,13 +693,13 @@ async function onDrop(e: DragEvent) {
|
||||
// inactive cursor position
|
||||
//
|
||||
|
||||
const inactiveCursorInterval = ref<number | null>(null)
|
||||
const inactiveCursorPosition = ref<CursorPosition | null>(null)
|
||||
let inactiveCursorInterval: number | null = null
|
||||
let inactiveCursorPosition: CursorPosition | null = null
|
||||
|
||||
function clearInactiveCursorInterval() {
|
||||
if (inactiveCursorInterval.value) {
|
||||
window.clearInterval(inactiveCursorInterval.value)
|
||||
inactiveCursorInterval.value = null
|
||||
if (inactiveCursorInterval) {
|
||||
window.clearInterval(inactiveCursorInterval)
|
||||
inactiveCursorInterval = null
|
||||
}
|
||||
}
|
||||
|
||||
@ -718,7 +708,7 @@ function restartInactiveCursorInterval() {
|
||||
clearInactiveCursorInterval()
|
||||
|
||||
if (props.inactiveCursors && focused.value && !props.isControling) {
|
||||
inactiveCursorInterval.value = window.setInterval(sendInactiveMousePos, INACTIVE_CURSOR_INTERVAL)
|
||||
inactiveCursorInterval = window.setInterval(sendInactiveMousePos, INACTIVE_CURSOR_INTERVAL)
|
||||
}
|
||||
}
|
||||
|
||||
@ -728,14 +718,14 @@ watch(() => props.isControling, restartInactiveCursorInterval)
|
||||
|
||||
function saveInactiveMousePos(e: MouseEvent) {
|
||||
const pos = getMousePos(e.clientX, e.clientY)
|
||||
inactiveCursorPosition.value = pos
|
||||
inactiveCursorPosition = pos
|
||||
}
|
||||
|
||||
function sendInactiveMousePos() {
|
||||
if (inactiveCursorPosition.value && props.webrtc.connected) {
|
||||
if (inactiveCursorPosition && props.webrtc.connected) {
|
||||
// not using NekoControl here, because inactive cursors are
|
||||
// treated differently than moving the mouse while controling
|
||||
props.webrtc.send('mousemove', inactiveCursorPosition.value)
|
||||
props.webrtc.send('mousemove', inactiveCursorPosition)
|
||||
} // if webrtc is not connected, we don't need to send anything
|
||||
}
|
||||
|
||||
@ -743,12 +733,12 @@ function sendInactiveMousePos() {
|
||||
// keyboard modifiers
|
||||
//
|
||||
|
||||
const keyboardModifiers = ref<KeyboardModifiers | null>(null)
|
||||
let keyboardModifiers: KeyboardModifiers | null = null
|
||||
|
||||
function updateKeyboardModifiers(e: MouseEvent) {
|
||||
const mods = getModifierState(e)
|
||||
const newMods = Object.values(mods).join()
|
||||
const oldMods = Object.values(keyboardModifiers.value || {}).join()
|
||||
const oldMods = Object.values(keyboardModifiers || {}).join()
|
||||
|
||||
// update keyboard modifiers only if they changed
|
||||
if (newMods !== oldMods) {
|
||||
@ -762,25 +752,26 @@ function updateKeyboardModifiers(e: MouseEvent) {
|
||||
|
||||
const cursorImage = ref<CursorImage | null>(null)
|
||||
const cursorElement = new Image()
|
||||
const cursorPosition = ref<CursorPosition | null>(null)
|
||||
const cursorLastTime = ref(0)
|
||||
const canvasRequestedFrame = ref(false)
|
||||
const canvasRenderTimeout = ref<number | null>(null)
|
||||
|
||||
const unsubscribePixelRatioChange = ref<(() => void) | null>(null)
|
||||
let cursorPosition: CursorPosition | null = null
|
||||
let cursorLastTime = 0
|
||||
let canvasRequestedFrame = false
|
||||
let canvasRenderTimeout: number | null = null
|
||||
|
||||
let unsubscribePixelRatioChange: (() => void) | null = null
|
||||
|
||||
function onPixelRatioChange() {
|
||||
if (unsubscribePixelRatioChange.value) {
|
||||
unsubscribePixelRatioChange.value()
|
||||
if (unsubscribePixelRatioChange) {
|
||||
unsubscribePixelRatioChange()
|
||||
}
|
||||
|
||||
const media = window.matchMedia(`(resolution: ${window.devicePixelRatio}dppx)`)
|
||||
media.addEventListener('change', onPixelRatioChange)
|
||||
unsubscribePixelRatioChange.value = () => {
|
||||
unsubscribePixelRatioChange = () => {
|
||||
media.removeEventListener('change', onPixelRatioChange)
|
||||
}
|
||||
|
||||
canvasScale.value = window.devicePixelRatio
|
||||
canvasScale = window.devicePixelRatio
|
||||
onCanvasSizeChange(props.canvasSize)
|
||||
}
|
||||
|
||||
@ -793,7 +784,7 @@ watch(() => props.canvasSize, onCanvasSizeChange)
|
||||
|
||||
function onCursorPosition(data: CursorPosition) {
|
||||
if (!props.isControling) {
|
||||
cursorPosition.value = data
|
||||
cursorPosition = data
|
||||
canvasRequestRedraw()
|
||||
}
|
||||
}
|
||||
@ -807,30 +798,32 @@ function onCursorImage(data: CursorImage) {
|
||||
}
|
||||
|
||||
function canvasResize({ width, height }: Dimension) {
|
||||
overlay.value!.width = width * canvasScale.value
|
||||
overlay.value!.height = height * canvasScale.value
|
||||
ctx.value!.setTransform(canvasScale.value, 0, 0, canvasScale.value, 0, 0)
|
||||
if (!ctx || !overlay.value) return
|
||||
|
||||
overlay.value.width = width * canvasScale
|
||||
overlay.value.height = height * canvasScale
|
||||
ctx.setTransform(canvasScale, 0, 0, canvasScale, 0, 0)
|
||||
}
|
||||
|
||||
function canvasRequestRedraw() {
|
||||
if (canvasRequestedFrame.value) return
|
||||
if (canvasRequestedFrame) return
|
||||
|
||||
if (props.fps > 0) {
|
||||
if (canvasRenderTimeout.value) {
|
||||
window.clearTimeout(canvasRenderTimeout.value)
|
||||
canvasRenderTimeout.value = null
|
||||
if (canvasRenderTimeout) {
|
||||
window.clearTimeout(canvasRenderTimeout)
|
||||
canvasRenderTimeout = null
|
||||
}
|
||||
|
||||
const now = Date.now()
|
||||
if (now - cursorLastTime.value < 1000 / props.fps) {
|
||||
canvasRenderTimeout.value = window.setTimeout(canvasRequestRedraw, 1000 / props.fps)
|
||||
if (now - cursorLastTime < 1000 / props.fps) {
|
||||
canvasRenderTimeout = window.setTimeout(canvasRequestRedraw, 1000 / props.fps)
|
||||
return
|
||||
}
|
||||
|
||||
cursorLastTime.value = now
|
||||
cursorLastTime = now
|
||||
}
|
||||
|
||||
canvasRequestedFrame.value = true
|
||||
canvasRequestedFrame = true
|
||||
window.requestAnimationFrame(() => {
|
||||
if (props.isControling) {
|
||||
canvasClear()
|
||||
@ -838,7 +831,7 @@ function canvasRequestRedraw() {
|
||||
canvasRedraw()
|
||||
}
|
||||
|
||||
canvasRequestedFrame.value = false
|
||||
canvasRequestedFrame = false
|
||||
})
|
||||
}
|
||||
|
||||
@ -846,7 +839,7 @@ watch(() => props.hostId, canvasRequestRedraw)
|
||||
watch(() => props.cursorDraw, canvasRequestRedraw)
|
||||
|
||||
function canvasRedraw() {
|
||||
if (!cursorPosition.value || !props.screenSize || !cursorImage.value) return
|
||||
if (!ctx || !cursorPosition || !props.screenSize || !cursorImage.value) return
|
||||
|
||||
// clear drawings
|
||||
canvasClear()
|
||||
@ -858,20 +851,20 @@ function canvasRedraw() {
|
||||
const { width, height } = props.canvasSize
|
||||
|
||||
// reset transformation, X and Y will be 0 again
|
||||
ctx.value!.setTransform(canvasScale.value, 0, 0, canvasScale.value, 0, 0)
|
||||
ctx.setTransform(canvasScale, 0, 0, canvasScale, 0, 0)
|
||||
|
||||
// get cursor position
|
||||
let x = Math.round((cursorPosition.value.x / props.screenSize.width) * width)
|
||||
let y = Math.round((cursorPosition.value.y / props.screenSize.height) * height)
|
||||
let x = Math.round((cursorPosition.x / props.screenSize.width) * width)
|
||||
let y = Math.round((cursorPosition.y / props.screenSize.height) * height)
|
||||
|
||||
// use custom draw function, if available
|
||||
if (props.cursorDraw) {
|
||||
props.cursorDraw(ctx.value!, x, y, cursorElement, cursorImage.value, props.hostId)
|
||||
props.cursorDraw(ctx, x, y, cursorElement, cursorImage.value, props.hostId)
|
||||
return
|
||||
}
|
||||
|
||||
// draw cursor image
|
||||
ctx.value!.drawImage(
|
||||
ctx.drawImage(
|
||||
cursorElement,
|
||||
x - cursorImage.value.x,
|
||||
y - cursorImage.value.y,
|
||||
@ -885,63 +878,65 @@ function canvasRedraw() {
|
||||
x += cursorImage.value.width
|
||||
y += cursorImage.value.height
|
||||
|
||||
ctx.value!.font = '14px Arial, sans-serif'
|
||||
ctx.value!.textBaseline = 'top'
|
||||
ctx.value!.shadowColor = 'black'
|
||||
ctx.value!.shadowBlur = 2
|
||||
ctx.value!.lineWidth = 2
|
||||
ctx.value!.fillStyle = 'black'
|
||||
ctx.value!.strokeText(cursorTag, x, y)
|
||||
ctx.value!.shadowBlur = 0
|
||||
ctx.value!.fillStyle = 'white'
|
||||
ctx.value!.fillText(cursorTag, x, y)
|
||||
ctx.font = '14px Arial, sans-serif'
|
||||
ctx.textBaseline = 'top'
|
||||
ctx.shadowColor = 'black'
|
||||
ctx.shadowBlur = 2
|
||||
ctx.lineWidth = 2
|
||||
ctx.fillStyle = 'black'
|
||||
ctx.strokeText(cursorTag, x, y)
|
||||
ctx.shadowBlur = 0
|
||||
ctx.fillStyle = 'white'
|
||||
ctx.fillText(cursorTag, x, y)
|
||||
}
|
||||
}
|
||||
|
||||
function canvasClear() {
|
||||
if (!ctx) return
|
||||
|
||||
// reset transformation, X and Y will be 0 again
|
||||
ctx.value!.setTransform(canvasScale.value, 0, 0, canvasScale.value, 0, 0)
|
||||
ctx.setTransform(canvasScale, 0, 0, canvasScale, 0, 0)
|
||||
|
||||
const { width, height } = props.canvasSize
|
||||
ctx.value!.clearRect(0, 0, width, height)
|
||||
ctx.clearRect(0, 0, width, height)
|
||||
}
|
||||
|
||||
//
|
||||
// implicit hosting
|
||||
//
|
||||
|
||||
const reqMouseDown = ref<MouseEvent | null>(null)
|
||||
const reqMouseUp = ref<MouseEvent | null>(null)
|
||||
let reqMouseDown: MouseEvent | null = null
|
||||
let reqMouseUp: MouseEvent | null = null
|
||||
|
||||
function onControlChange(isControling: boolean) {
|
||||
keyboardModifiers.value = null
|
||||
keyboardModifiers = null
|
||||
|
||||
if (isControling && reqMouseDown.value) {
|
||||
updateKeyboardModifiers(reqMouseDown.value)
|
||||
onMouseDown(reqMouseDown.value)
|
||||
if (isControling && reqMouseDown) {
|
||||
updateKeyboardModifiers(reqMouseDown)
|
||||
onMouseDown(reqMouseDown)
|
||||
}
|
||||
|
||||
if (isControling && reqMouseUp.value) {
|
||||
onMouseUp(reqMouseUp.value)
|
||||
if (isControling && reqMouseUp) {
|
||||
onMouseUp(reqMouseUp)
|
||||
}
|
||||
|
||||
canvasRequestRedraw()
|
||||
|
||||
reqMouseDown.value = null
|
||||
reqMouseUp.value = null
|
||||
reqMouseDown = null
|
||||
reqMouseUp = null
|
||||
}
|
||||
|
||||
watch(() => props.isControling, onControlChange)
|
||||
|
||||
function implicitControlRequest(e: MouseEvent) {
|
||||
if (props.implicitControl && e.type === 'mousedown') {
|
||||
reqMouseDown.value = e
|
||||
reqMouseUp.value = null
|
||||
reqMouseDown = e
|
||||
reqMouseUp = null
|
||||
props.control.request()
|
||||
}
|
||||
|
||||
if (props.implicitControl && e.type === 'mouseup') {
|
||||
reqMouseUp.value = e
|
||||
reqMouseUp = e
|
||||
}
|
||||
}
|
||||
|
||||
@ -956,15 +951,15 @@ function implicitControlRelease() {
|
||||
// mobile keyboard
|
||||
//
|
||||
|
||||
const kbdShow = ref(false)
|
||||
const kbdOpen = ref(false)
|
||||
let kbdShow = false
|
||||
let kbdOpen = false
|
||||
|
||||
function mobileKeyboardShow() {
|
||||
// skip if not a touch device
|
||||
if (!props.hasMobileKeyboard) return
|
||||
|
||||
kbdShow.value = true
|
||||
kbdOpen.value = false
|
||||
kbdShow = true
|
||||
kbdOpen = false
|
||||
|
||||
textarea.value!.focus()
|
||||
window.visualViewport?.addEventListener('resize', onVisualViewportResize)
|
||||
@ -975,8 +970,8 @@ function mobileKeyboardHide() {
|
||||
// skip if not a touch device
|
||||
if (!props.hasMobileKeyboard) return
|
||||
|
||||
kbdShow.value = false
|
||||
kbdOpen.value = false
|
||||
kbdShow = false
|
||||
kbdOpen = false
|
||||
|
||||
emit('mobileKeyboardOpen', false)
|
||||
window.visualViewport?.removeEventListener('resize', onVisualViewportResize)
|
||||
@ -986,10 +981,10 @@ function mobileKeyboardHide() {
|
||||
// visual viewport resize event is fired when keyboard is opened or closed
|
||||
// android does not blur textarea when keyboard is closed, so we need to do it manually
|
||||
function onVisualViewportResize() {
|
||||
if (!kbdShow.value) return
|
||||
if (!kbdShow) return
|
||||
|
||||
if (!kbdOpen.value) {
|
||||
kbdOpen.value = true
|
||||
if (!kbdOpen) {
|
||||
kbdOpen = true
|
||||
} else {
|
||||
mobileKeyboardHide()
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user