mirror of
https://gitee.com/gfdgd-xi/deep-wine-runner
synced 2025-09-04 18:32:22 +08:00
Some checks are pending
Auto Building Wine Runner(rpm) / Explore-GitHub-Actions (push) Waiting to run
Auto Building Wine Runner(deb) / Explore-GitHub-Actions (push) Waiting to run
Building Wine Runner Off-line Pages(arm64) / Explore-GitHub-Actions (push) Waiting to run
Building Wine Runner Off-line Pages(amd64) / Explore-GitHub-Actions (push) Waiting to run
691 lines
20 KiB
Python
691 lines
20 KiB
Python
"""
|
|
Qt Widget for displaying VNC framebuffer using RFB protocol
|
|
|
|
(c) zocker-160 2024
|
|
licensed under GPLv3
|
|
"""
|
|
|
|
import logging
|
|
import time
|
|
|
|
from PyQt5.QtCore import (
|
|
QSize,
|
|
Qt,
|
|
pyqtSignal,
|
|
QSemaphore
|
|
)
|
|
from PyQt5.QtGui import (
|
|
QImage,
|
|
QPaintEvent,
|
|
QPainter,
|
|
QColor,
|
|
QBrush,
|
|
QPixmap,
|
|
QResizeEvent,
|
|
QKeyEvent,
|
|
QMouseEvent
|
|
)
|
|
|
|
from PyQt5.QtWidgets import (
|
|
QWidget,
|
|
QLabel,
|
|
QWidget,
|
|
QOpenGLWidget
|
|
)
|
|
|
|
from qvncwidget.rfb import RFBClient
|
|
from qvncwidget.rfbhelpers import RFBPixelformat, RFBInput
|
|
|
|
log = logging.getLogger("QVNCWidget")
|
|
|
|
class QVNCWidget(QWidget, RFBClient):
|
|
|
|
onInitialResize = pyqtSignal(QSize)
|
|
|
|
def __init__(self, parent: QWidget,
|
|
host: str, port = 5900, password: str = None,
|
|
readOnly = False):
|
|
super().__init__(
|
|
parent=parent,
|
|
host=host, port=port, password=password
|
|
)
|
|
self.readOnly = readOnly
|
|
|
|
self.backbuffer: QImage = None
|
|
self.frontbuffer: QImage = None
|
|
|
|
self.setMouseTracking(not self.readOnly)
|
|
self.setMinimumSize(1, 1) # make window scalable
|
|
|
|
self.mouseButtonMask = 0
|
|
|
|
def start(self):
|
|
self.startConnection()
|
|
|
|
def stop(self):
|
|
self.closeConnection()
|
|
|
|
def onConnectionMade(self):
|
|
log.info("VNC handshake done")
|
|
|
|
self.setPixelFormat(RFBPixelformat.getRGB32())
|
|
|
|
self.PIX_FORMAT = QImage.Format.Format_RGB32
|
|
self.backbuffer = QImage(self.vncWidth, self.vncHeight, self.PIX_FORMAT)
|
|
self.onInitialResize.emit(QSize(self.vncWidth, self.vncHeight))
|
|
|
|
def onRectangleUpdate(self,
|
|
x: int, y: int, width: int, height: int, data: bytes):
|
|
|
|
if self.backbuffer is None:
|
|
log.warning("backbuffer is None")
|
|
return
|
|
else:
|
|
log.debug("drawing backbuffer")
|
|
|
|
#with open(f"{width}x{height}.data", "wb") as f:
|
|
# f.write(data)
|
|
|
|
t1 = time.time()
|
|
|
|
painter = QPainter(self.backbuffer)
|
|
painter.drawImage(x, y, QImage(data, width, height, self.PIX_FORMAT))
|
|
painter.end()
|
|
|
|
log.debug(f"painting took: {(time.time() - t1)*1e3} ms")
|
|
|
|
del painter
|
|
del data
|
|
|
|
def onFramebufferUpdateFinished(self):
|
|
log.debug("FB Update finished")
|
|
self.update()
|
|
|
|
def paintEvent(self, a0: QPaintEvent):
|
|
#log.debug("Paint event")
|
|
painter = QPainter(self)
|
|
|
|
if self.backbuffer is None:
|
|
log.debug("backbuffer is None")
|
|
painter.fillRect(0, 0, self.width(), self.height(), Qt.GlobalColor.black)
|
|
|
|
else:
|
|
self.frontbuffer = self.backbuffer.scaled(
|
|
self.width(), self.height(),
|
|
Qt.AspectRatioMode.KeepAspectRatio,
|
|
Qt.TransformationMode.SmoothTransformation
|
|
)
|
|
painter.drawImage(0, 0, self.frontbuffer)
|
|
|
|
painter.end()
|
|
|
|
# Mouse events
|
|
|
|
def mousePressEvent(self, ev: QMouseEvent):
|
|
if self.readOnly or not self.frontbuffer: return
|
|
self.mouseButtonMask = RFBInput.fromQMouseEvent(ev, True, self.mouseButtonMask)
|
|
self.pointerEvent(*self._getRemoteRel(ev), self.mouseButtonMask)
|
|
|
|
def mouseReleaseEvent(self, ev: QMouseEvent):
|
|
if self.readOnly or not self.frontbuffer: return
|
|
self.mouseButtonMask = RFBInput.fromQMouseEvent(ev, False, self.mouseButtonMask)
|
|
self.pointerEvent(*self._getRemoteRel(ev), self.mouseButtonMask)
|
|
|
|
def mouseMoveEvent(self, ev: QMouseEvent):
|
|
if self.readOnly or not self.frontbuffer: return
|
|
try:
|
|
# 忽略拖动导致的问题
|
|
self.pointerEvent(*self._getRemoteRel(ev), self.mouseButtonMask)
|
|
except:
|
|
pass
|
|
|
|
def _getRemoteRel(self, ev: QMouseEvent) -> tuple:
|
|
xPos = (ev.localPos().x() / self.frontbuffer.width()) * self.vncWidth
|
|
yPos = (ev.localPos().y() / self.frontbuffer.height()) * self.vncHeight
|
|
|
|
return int(xPos), int(yPos)
|
|
|
|
# Key events
|
|
|
|
def keyPressEvent(self, ev: QKeyEvent):
|
|
if self.readOnly: return
|
|
self.keyEvent(RFBInput.fromQKeyEvent(ev.key(), ev.text()), down=1)
|
|
|
|
def keyReleaseEvent(self, ev: QKeyEvent):
|
|
if self.readOnly: return
|
|
self.keyEvent(RFBInput.fromQKeyEvent(ev.key(), ev.text()), down=0)
|
|
|
|
|
|
# other experimental implementations
|
|
|
|
class QVNCWidgetGL(QOpenGLWidget, RFBClient):
|
|
|
|
IMG_FORMAT = QImage.Format_RGB32
|
|
|
|
onInitialResize = pyqtSignal(QSize)
|
|
#onUpdatePixmap = pyqtSignal(int, int, int, int, bytes)
|
|
onUpdatePixmap = pyqtSignal()
|
|
onSetPixmap = pyqtSignal()
|
|
|
|
onKeyPress = pyqtSignal(QKeyEvent)
|
|
onKeyRelease = pyqtSignal(QKeyEvent)
|
|
|
|
def __init__(self, parent,
|
|
host, port=5900, password: str=None,
|
|
mouseTracking=False):
|
|
|
|
#super(QOpenGLWidget, self).__init__()
|
|
#super(RFBClient, self).__init__(
|
|
super().__init__(
|
|
parent=parent,
|
|
host=host,
|
|
port=port,
|
|
password=password,
|
|
daemonThread=True
|
|
)
|
|
|
|
#self.setAlignment(Qt.AlignCenter)
|
|
|
|
#self.onUpdatePixmap.connect(self._updateImage)
|
|
#self.onSetPixmap.connect(self._setImage)
|
|
self.onSetPixmap.connect(self._updateImage)
|
|
|
|
self.acceptMouseEvents = False # mouse events are not accepted at first
|
|
self.setMouseTracking(mouseTracking)
|
|
|
|
# Allow Resizing
|
|
self.setMinimumSize(1, 1)
|
|
|
|
self.data = list(tuple())
|
|
self.dataMonitor = QSemaphore(0)
|
|
|
|
def start(self):
|
|
self.startConnection()
|
|
|
|
def stop(self):
|
|
self.closeConnection()
|
|
|
|
def onConnectionMade(self):
|
|
log.info("VNC handshake done")
|
|
|
|
self.setPixelFormat(RFBPixelformat.getRGB32())
|
|
self.onInitialResize.emit(QSize(self.vncWidth, self.vncHeight))
|
|
self._initKeypress()
|
|
self._initMouse()
|
|
|
|
def onRectangleUpdate(self,
|
|
x: int, y: int, width: int, height: int, data: bytes):
|
|
#img = QImage(data, width, height, self.IMG_FORMAT)
|
|
#self.onUpdatePixmap.emit(x, y, width, height, data)
|
|
|
|
#self.dataMonitor.acquire(1)
|
|
|
|
self.data.append((x, y, width, height, data))
|
|
#self.data = (x, y, width, height, data)
|
|
#self.dataMonitor.release(1)
|
|
|
|
#self.onUpdatePixmap.emit()
|
|
|
|
#else:
|
|
# print("AAAAAAAAAAAAAA", "MONITOR AQUIRE FAILED")
|
|
|
|
def onFramebufferUpdateFinished(self):
|
|
self.onSetPixmap.emit()
|
|
return
|
|
|
|
if self.pixmap:
|
|
#self.setPixmap(QPixmap.fromImage(self.image))
|
|
self.resizeEvent(None)
|
|
|
|
def onFatalError(self, error: Exception):
|
|
log.error(str(error))
|
|
#logging.exception(str(error))
|
|
#self.reconnect()
|
|
|
|
#def _updateImage(self, x: int, y: int, width: int, height: int, data: bytes):
|
|
def _updateImage(self):
|
|
print("update image")
|
|
self.update()
|
|
|
|
#if not self.screen:
|
|
# self.screen = QImage(width, height, self.IMG_FORMAT)
|
|
# self.screen.fill(Qt.red)
|
|
# self.screenPainter = QPainter(self.screen)
|
|
|
|
#self.painter.beginNativePainting()
|
|
#self.painter.drawPixmapFragments()
|
|
|
|
#with open("/tmp/images/test.raw", "wb") as f:
|
|
# f.write(data)
|
|
|
|
#p = QPainter(self.screen)
|
|
|
|
#self.screenPainter.drawImage(
|
|
# x, y, QImage(data, width, height, self.IMG_FORMAT))
|
|
|
|
#p.end()
|
|
|
|
#self.repaint()
|
|
#self.update()
|
|
|
|
def _setPixmap(self):
|
|
if self.pixmap:
|
|
self.setPixmap(
|
|
self.pixmap.scaled(
|
|
self.width(), self.height(),
|
|
Qt.KeepAspectRatio,
|
|
Qt.SmoothTransformation
|
|
)
|
|
)
|
|
|
|
def _setImage(self):
|
|
if self.screen:
|
|
self.setPixmap(QPixmap.fromImage(
|
|
self.screen.scaled(
|
|
self.width(), self.height(),
|
|
Qt.KeepAspectRatio,
|
|
Qt.SmoothTransformation
|
|
)
|
|
))
|
|
self.acceptMouseEvents = True # mouse events are getting accepted
|
|
|
|
# Passed events
|
|
|
|
def _keyPress(self, ev: QKeyEvent):
|
|
self.keyEvent(
|
|
RFBInput.fromQKeyEvent(ev.key(), ev.text()), down=1)
|
|
|
|
def _keyRelease(self, ev: QKeyEvent):
|
|
self.keyEvent(
|
|
RFBInput.fromQKeyEvent(ev.key(), ev.text()), down=0)
|
|
|
|
# Window events
|
|
|
|
def paintEvent(self, e: QPaintEvent):
|
|
print("paint event")
|
|
|
|
#self.dataMonitor.acquire(1)
|
|
|
|
#while self.dataMonitor.tryAcquire(1):
|
|
while len(self.data) > 0:
|
|
x, y, w, h, data = self.data.pop(0)
|
|
|
|
p = QPainter(self)
|
|
|
|
#p.setPen(QColor(255, 0, 0))
|
|
#p.drawText(e.rect(), Qt.AlignCenter, str(self.dataMonitor.available()))
|
|
|
|
p.drawImage(x, y, QImage(data, w, h, self.IMG_FORMAT))
|
|
p.end()
|
|
|
|
#self.dataMonitor.release(1)
|
|
|
|
return
|
|
|
|
p = QPainter(self)
|
|
p.fillRect(e.rect(), QBrush(QColor(255, 255, 255)))
|
|
p.end()
|
|
|
|
return
|
|
|
|
if self.dataMonitor.tryAcquire(1):
|
|
x, y, w, h, data = self.data
|
|
|
|
p = QPainter(self)
|
|
p.drawImage(x, y, QImage(data, w, h, self.IMG_FORMAT))
|
|
p.end()
|
|
|
|
self.dataMonitor.release(1)
|
|
|
|
print("CCCCC", "Image painted diggah")
|
|
|
|
else:
|
|
print("BBBBBBBBB", "aquire monitor failed")
|
|
|
|
#return super().paintEvent(a0)
|
|
return
|
|
|
|
if not self.screen:
|
|
self.screen = QImage(self.size(), self.IMG_FORMAT)
|
|
self.screen.fill(Qt.red)
|
|
self.screenPainter = QPainter(self.screen)
|
|
|
|
p = QPainter()
|
|
p.begin(self)
|
|
p.drawImage(0, 0,
|
|
self.screen.scaled(
|
|
self.width(), self.height(),
|
|
Qt.KeepAspectRatio,
|
|
Qt.SmoothTransformation
|
|
))
|
|
p.end()
|
|
|
|
def resizeEvent(self, e: QResizeEvent):
|
|
return super().resizeEvent(e)
|
|
|
|
def resizeGL(self, w: int, h: int):
|
|
print("RESIZE THAT BITCH!!!", w, h)
|
|
#return super().resizeGL(w, h)
|
|
|
|
def resizeEvent_(self, a0: QResizeEvent):
|
|
#print("RESIZE!", self.width(), self.height())
|
|
#return super().resizeEvent(a0)
|
|
if self.screen:
|
|
self.setPixmap(QPixmap.fromImage(
|
|
self.screen.scaled(
|
|
self.width(), self.height(),
|
|
Qt.KeepAspectRatio,
|
|
Qt.SmoothTransformation
|
|
))
|
|
)
|
|
return super().resizeEvent(a0)
|
|
|
|
def mousePressEvent(self, ev: QMouseEvent):
|
|
#print(ev.localPos(), ev.button())
|
|
#print(self.height() - self.pixmap().height())
|
|
|
|
if self.acceptMouseEvents: # need pixmap instance
|
|
self.buttonMask = RFBInput.fromQMouseEvent(ev, True, self.buttonMask)
|
|
self.pointerEvent(*self._getRemoteRel(ev), self.buttonMask)
|
|
|
|
return super().mousePressEvent(ev)
|
|
|
|
def mouseReleaseEvent(self, ev: QMouseEvent):
|
|
if self.acceptMouseEvents: # need pixmap instance
|
|
self.buttonMask = RFBInput.fromQMouseEvent(ev, False, self.buttonMask)
|
|
self.pointerEvent(*self._getRemoteRel(ev), self.buttonMask)
|
|
|
|
return super().mouseReleaseEvent(ev)
|
|
|
|
def mouseMoveEvent(self, ev: QMouseEvent):
|
|
if self.acceptMouseEvents: # need pixmap instance
|
|
self.pointerEvent(*self._getRemoteRel(ev), self.buttonMask)
|
|
|
|
# FIXME: The pixmap is assumed to be aligned center.
|
|
def _getRemoteRel(self, ev: QMouseEvent) -> tuple:
|
|
# FIXME: this code is ugly as fk
|
|
|
|
# y coord is kinda fucked up
|
|
yDiff = (self.height() - self.pixmap().height()) / 2
|
|
yPos = ev.localPos().y() - yDiff
|
|
if yPos < 0: yPos = 0
|
|
if yPos > self.pixmap().height(): yPos = self.pixmap().height()
|
|
|
|
yPos = self._calcRemoteRel(
|
|
yPos, self.pixmap().height(), self.vncHeight)
|
|
|
|
# x coord is kinda fucked up, too
|
|
xDiff = (self.width() - self.pixmap().width()) / 2
|
|
xPos = ev.localPos().x() - xDiff
|
|
if xPos < 0: xPos = 0
|
|
if xPos > self.pixmap().width(): xPos = self.pixmap().width()
|
|
|
|
xPos = self._calcRemoteRel(
|
|
xPos, self.pixmap().width(), self.vncWidth)
|
|
|
|
return xPos, yPos
|
|
|
|
def _calcRemoteRel(self, locRel, locMax, remoteMax) -> int:
|
|
return int( (locRel / locMax) * remoteMax )
|
|
|
|
def _initMouse(self):
|
|
self.buttonMask = 0 # pressed buttons (bit fields)
|
|
|
|
def _initKeypress(self):
|
|
self.onKeyPress.connect(self._keyPress)
|
|
self.onKeyRelease.connect(self._keyRelease)
|
|
|
|
def __del__(self):
|
|
self.stop()
|
|
|
|
def __exit__(self, *args):
|
|
self.stop()
|
|
self.deleteLater()
|
|
|
|
class QVNCWidget_old(QLabel, RFBClient):
|
|
|
|
IMG_FORMAT = QImage.Format_RGB32
|
|
|
|
onInitialResize = pyqtSignal(QSize)
|
|
onUpdatePixmap = pyqtSignal(int, int, int, int, bytes)
|
|
onSetPixmap = pyqtSignal()
|
|
|
|
onKeyPress = pyqtSignal(QKeyEvent)
|
|
onKeyRelease = pyqtSignal(QKeyEvent)
|
|
|
|
def __init__(self, parent,
|
|
host, port=5900, password: str=None,
|
|
mouseTracking=False):
|
|
super().__init__(
|
|
parent=parent,
|
|
host=host,
|
|
port=port,
|
|
password=password,
|
|
daemonThread=True
|
|
)
|
|
#import faulthandler
|
|
#faulthandler.enable()
|
|
self.screen: QImage = None
|
|
|
|
# FIXME: The pixmap is assumed to be aligned center.
|
|
self.setAlignment(Qt.AlignCenter)
|
|
|
|
self.onUpdatePixmap.connect(self._updateImage)
|
|
self.onSetPixmap.connect(self._setImage)
|
|
|
|
self.acceptMouseEvents = False # mouse events are not accepted at first
|
|
self.setMouseTracking(mouseTracking)
|
|
|
|
# Allow Resizing
|
|
self.setMinimumSize(1,1)
|
|
|
|
def _initMouse(self):
|
|
self.buttonMask = 0 # pressed buttons (bit fields)
|
|
|
|
def _initKeypress(self):
|
|
self.onKeyPress.connect(self._keyPress)
|
|
self.onKeyRelease.connect(self._keyRelease)
|
|
|
|
def start(self):
|
|
self.startConnection()
|
|
|
|
def stop(self):
|
|
self.closeConnection()
|
|
if self.screenPainter: self.screenPainter.end()
|
|
|
|
def onConnectionMade(self):
|
|
self.onInitialResize.emit(QSize(self.vncWidth, self.vncHeight))
|
|
self.setPixelFormat(RFBPixelformat.getRGB32())
|
|
self._initKeypress()
|
|
self._initMouse()
|
|
|
|
def onRectangleUpdate(self,
|
|
x: int, y: int, width: int, height: int, data: bytes):
|
|
#img = QImage(data, width, height, self.IMG_FORMAT)
|
|
self.onUpdatePixmap.emit(x, y, width, height, data)
|
|
|
|
def onFramebufferUpdateFinished(self):
|
|
self.onSetPixmap.emit()
|
|
return
|
|
|
|
if self.pixmap:
|
|
#self.setPixmap(QPixmap.fromImage(self.image))
|
|
self.resizeEvent(None)
|
|
|
|
def onFatalError(self, error: Exception):
|
|
log.error(str(error))
|
|
#logging.exception(str(error))
|
|
#self.reconnect()
|
|
|
|
def _updateImage(self, x: int, y: int, width: int, height: int, data: bytes):
|
|
if not self.screen:
|
|
self.screen = QImage(width, height, self.IMG_FORMAT)
|
|
self.screen.fill(Qt.red)
|
|
self.screenPainter = QPainter(self.screen)
|
|
|
|
#self.painter.beginNativePainting()
|
|
#self.painter.drawPixmapFragments()
|
|
|
|
#with open("/tmp/images/test.raw", "wb") as f:
|
|
# f.write(data)
|
|
|
|
#p = QPainter(self.screen)
|
|
self.screenPainter.drawImage(
|
|
x, y, QImage(data, width, height, self.IMG_FORMAT))
|
|
#p.end()
|
|
|
|
#self.repaint()
|
|
#self.update()
|
|
|
|
def _drawPixmap(self, x: int, y: int, pix: QPixmap):
|
|
#self.paintLock.acquire()
|
|
self.pixmap = pix
|
|
|
|
if not self.painter:
|
|
self.painter = QPainter(self.pixmap)
|
|
else:
|
|
print("DRAW PIXMAP:", x, y, self.pixmap, self.painter, pix, pix.isNull())
|
|
self.painter.drawPixmap(x, y, self.pixmap)
|
|
#self.paintLock.release()
|
|
|
|
def _drawPixmap2(self, x: int, y: int, pix: QPixmap, data: bytes):
|
|
if not self.pixmap or (
|
|
x == 0 and y == 0 and
|
|
pix.width() == self.pixmap.width() and pix.height() == self.pixmap.height()):
|
|
|
|
self.pixmap = pix.copy()
|
|
self._setPixmap()
|
|
return
|
|
|
|
import time
|
|
print("DRAW PIXMAP:", x, y, self.pixmap.width(), self.pixmap.height(), pix.width(), pix.height())
|
|
_t = time.time()
|
|
#self.pixmap.save(f"/tmp/images/imgP_{_t}", "jpg")
|
|
#with open(f"/tmp/images/img_{_t}.raw", "wb") as f:
|
|
# f.write(data)
|
|
#pix.save(f"/tmp/images/img_{_t}", "jpg")
|
|
|
|
painter = QPainter(self.pixmap)
|
|
painter.drawPixmap(x, y, pix)
|
|
painter.end()
|
|
#self._setPixmap()
|
|
|
|
def _setPixmap(self):
|
|
if self.pixmap:
|
|
self.setPixmap(
|
|
self.pixmap.scaled(
|
|
self.width(), self.height(),
|
|
Qt.KeepAspectRatio,
|
|
Qt.SmoothTransformation
|
|
)
|
|
)
|
|
|
|
def _setImage(self):
|
|
if self.screen:
|
|
self.setPixmap(QPixmap.fromImage(
|
|
self.screen.scaled(
|
|
self.width(), self.height(),
|
|
Qt.KeepAspectRatio,
|
|
Qt.SmoothTransformation
|
|
)
|
|
))
|
|
self.acceptMouseEvents = True # mouse events are getting accepted
|
|
|
|
# Passed events
|
|
|
|
def _keyPress(self, ev: QKeyEvent):
|
|
self.keyEvent(
|
|
RFBInput.fromQKeyEvent(ev.key(), ev.text()), down=1)
|
|
|
|
def _keyRelease(self, ev: QKeyEvent):
|
|
self.keyEvent(
|
|
RFBInput.fromQKeyEvent(ev.key(), ev.text()), down=0)
|
|
|
|
# Window events
|
|
|
|
def paintEvent(self, a0: QPaintEvent):
|
|
return super().paintEvent(a0)
|
|
if not self.screen:
|
|
self.screen = QImage(self.size(), self.IMG_FORMAT)
|
|
self.screen.fill(Qt.red)
|
|
self.screenPainter = QPainter(self.screen)
|
|
|
|
p = QPainter()
|
|
p.begin(self)
|
|
p.drawImage(0, 0,
|
|
self.screen.scaled(
|
|
self.width(), self.height(),
|
|
Qt.KeepAspectRatio,
|
|
Qt.SmoothTransformation
|
|
))
|
|
p.end()
|
|
|
|
def resizeEvent(self, a0: QResizeEvent):
|
|
#print("RESIZE!", self.width(), self.height())
|
|
#return super().resizeEvent(a0)
|
|
if self.screen:
|
|
self.setPixmap(QPixmap.fromImage(
|
|
self.screen.scaled(
|
|
self.width(), self.height(),
|
|
Qt.KeepAspectRatio,
|
|
Qt.SmoothTransformation
|
|
))
|
|
)
|
|
return super().resizeEvent(a0)
|
|
|
|
def mousePressEvent(self, ev: QMouseEvent):
|
|
#print(ev.localPos(), ev.button())
|
|
#print(self.height() - self.pixmap().height())
|
|
|
|
if self.acceptMouseEvents: # need pixmap instance
|
|
self.buttonMask = RFBInput.fromQMouseEvent(ev, True, self.buttonMask)
|
|
self.pointerEvent(*self._getRemoteRel(ev), self.buttonMask)
|
|
|
|
return super().mousePressEvent(ev)
|
|
|
|
def mouseReleaseEvent(self, ev: QMouseEvent):
|
|
if self.acceptMouseEvents: # need pixmap instance
|
|
self.buttonMask = RFBInput.fromQMouseEvent(ev, False, self.buttonMask)
|
|
self.pointerEvent(*self._getRemoteRel(ev), self.buttonMask)
|
|
|
|
return super().mouseReleaseEvent(ev)
|
|
|
|
def mouseMoveEvent(self, ev: QMouseEvent):
|
|
if self.acceptMouseEvents: # need pixmap instance
|
|
self.pointerEvent(*self._getRemoteRel(ev), self.buttonMask)
|
|
|
|
# FIXME: The pixmap is assumed to be aligned center.
|
|
def _getRemoteRel(self, ev: QMouseEvent) -> tuple:
|
|
# FIXME: this code is ugly as fk
|
|
|
|
# y coord is kinda fucked up
|
|
yDiff = (self.height() - self.pixmap().height()) / 2
|
|
yPos = ev.localPos().y() - yDiff
|
|
if yPos < 0: yPos = 0
|
|
if yPos > self.pixmap().height(): yPos = self.pixmap().height()
|
|
|
|
yPos = self._calcRemoteRel(
|
|
yPos, self.pixmap().height(), self.vncHeight)
|
|
|
|
# x coord is kinda fucked up, too
|
|
xDiff = (self.width() - self.pixmap().width()) / 2
|
|
xPos = ev.localPos().x() - xDiff
|
|
if xPos < 0: xPos = 0
|
|
if xPos > self.pixmap().width(): xPos = self.pixmap().width()
|
|
|
|
xPos = self._calcRemoteRel(
|
|
xPos, self.pixmap().width(), self.vncWidth)
|
|
|
|
return xPos, yPos
|
|
|
|
def _calcRemoteRel(self, locRel, locMax, remoteMax) -> int:
|
|
return int( (locRel / locMax) * remoteMax )
|
|
|
|
|
|
def __del__(self):
|
|
self.stop()
|
|
|
|
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
self.stop()
|
|
self.deleteLater()
|