libvncclient SendPointerEvent sending only left button - c++

I am working on a VNC viewer using Qt 5 and the libvncserver / libvncclient library. I am subclassing a QWidget object to provide the VNC viewer widget.
I'm able to connect to a VNC server (running TightVNC and Windows XP), I'm able to move the remote cursor, able to left-click and able to drag things through the viewer, however I have been unsuccessful in getting right-clicks to work. It's as if the server is ignoring right-clicks sent to it, although wherever I right-click does seem to change the focus of the window on the server, but not icons.
Unfortunately the libvncclient documentation is not very helpful if you aren't already an expert. I did look through several projects' code for help, and tried using the approaches there with no success. The one I've settled on for reference is:
https://github.com/LibVNC/libvncserver/blob/master/client_examples/SDLvncviewer.c#L383
This is the SendPointerEvent function:
rfbBool SendPointerEvent (rfbClient * client,
int x,
int y,
int buttonMask
)
The relevant excerpt from the documentation:
A pointer event includes a cursor location and a button mask. The
button mask indicates which buttons on the pointing device are
pressed. Each button is represented by a bit in the button mask. A 1
indicates the button is pressed while a 0 indicates that it is not
pressed.
You may use these pre-defined button masks by ORing them
together: rfbButton1Mask, rfbButton2Mask, rfbButton3Mask,
rfbButton4Mask rfbButton5Mask
I'm not understanding when, where and how I should use these pre-defined button masks. I looked at the enum and they all just correspond with '1', '2', '3', etc. Qt emits '1' for left button and '2' for right button.
Here is my relevant code:
static int nButtonMask;
void VncViewer::handleMouseEvents(QMouseEvent* event)
{
if (event->type() == QMouseEvent::MouseButtonPress) {
nButtonMask |= event->button();
}
if (event->type() == QMouseEvent::MouseButtonRelease) {
nButtonMask &= ~event->button();
}
SendPointerEvent(g.currentViewer->client, event->x(), event->y(), nButtonMask);
nButtonMask &= ~(rfbButton4Mask | rfbButton5Mask);
}
Any clues on how to make right-clicks work?
Thank you in advance :-)

This is resolved.
The problem was that the button numbers emitted by Qt were not matching up with the rfb buttons expected by the VNC server. Again, libvncserver's documentation was very unhelpful, so the button mapping issue wasn't noticeable right away.
All is working well now. :-D Thanks!

Related

Problem with Keypress simulation on Linux (Ubuntu 18)

I'm making a hobby project that is basically a bot for a very old flash game, the mouse move and click works fine, but all key presses make the operating system lag/stutter and sometimes stop listening to all keyboard inputs, real or fake.
I started using just XLib with XTests but didn't work, so I tried XSendEvent instead of XTests, but all symptoms stayed the same, so the last attempt was with XDO, which gave better results, but still freezes the OS.
this is the current snippet that I'm trying to use to simulate a keypress:
//Constructor
CheatCore::CheatCore() {
xdo_t x = xdo_new(NULL);
Window *list;
xdo_search_t search;
unsigned int nwindows;
memset(&search, 0, sizeof(xdo_search_t));
search.max_depth = -1;
search.require = xdo_search::SEARCH_ANY;
search.searchmask = SEARCH_CLASS | SEARCH_ONLYVISIBLE;
search.winclass = "Chrome";
int id = xdo_search_windows(x, &search, &list, &nwindows);
qDebug() << nwindows;
if(!nwindows){
qDebug() << "Chrome not found";
return;
}
w = list[0];
//I have to call activate twice to really bring it forward, I suspect that its
//because I use a transparent "overlay" that show stats for the cheat and it is set as Aways on top
//(i used Qt to set it to not get any Events)
xdo_activate_window(x,w);
xdo_activate_window(x,w);
}
//there is a function that executes every second to check if a pixel color has changed,
//if so, then the SendKey is called to Reload weapon magazine pressing the "space" key
void CheatCore::SendKey(){
xdo_activate_window(x,w);
xdo_activate_window(x,w);
xdo_send_keysequence_window(x, w, "space", 500);
}
I'm using a transparent overlay to show the bot status, with just some numbers appearing, it is a widget created using Qt that is AlwaysOnTop and the paint event draws the desired information's, it is another object and don't have direct impact in the CheatCore, but this is the window flags used to draw over a transparent window and ignore events.
setWindowFlags(Qt::WindowTransparentForInput | Qt::FramelessWindowHint |
Qt::WindowStaysOnTopHint);
setAttribute(Qt::WA_NoSystemBackground);
setAttribute(Qt::WA_TranslucentBackground);
setAttribute(Qt::WA_TransparentForMouseEvents);
I didn't manage to understand what could be provoking this weird behavior, could it be the windowing system?
Also, I tried to find a Qt way of simulating mouse/keyboard inputs, but i didn't manage to find any solution to send events to other windows if there is a way possible of achieving this would be great!
The game i'm trying to automate is called "Storm the House"
If interested this is the link to the online repo : link
Can you help me make this work? Thank you!
Context about the setup:
Ubuntu 18.10 using VGA and Nvidia drivers (if it may influence the xserver)
Did you ever try to use xdotool from command line. To use xdotool you need to install package first.
To simualte a key press, you can use.
xdotool key <key>
For example if you want to simulate key press for X you can use this code
xdotool key x
Or any other combination like
xdotool key ctrl+f
Also you can replace key press with another one, for example if you want to replace pressing D with Backspace you can try this one
xdotool key D BackSpace
You can read complete guid online, also you can write script with this tool and use it in many different situations.
Also you can use it for remote connection too.
I hope this helps you with your little problem.
Using evdev is a linux specific option.
It's a simpler solution as you just need to open the correct file and write to it.
Take a look at this similar question to see how to get started.

QKeyEvent isAutoRepeat not working?

So, I have an application where if a particular button is kept pressed it plays an audio device, when the button is released it stops the audio device. I use keyPressEvent and KeyReleaseEvent to implement this which is similar to the code below:
void MainWindow::keyPressEvent(QKeyEvent *event)
{
if(event->isAutoRepeat())
{
event->ignore();
}
else
{
if(event->key() == Qt::Key_0)
{
qDebug()<<"key_0 pressed"<<endl;
}
else
{
QWidget::keyPressEvent(event);
}
}
}
void MainWindow::keyReleaseEvent(QKeyEvent *event)
{
if(event->isAutoRepeat())
{
event->ignore();
}
else
{
if(event->key() == Qt::Key_0)
{
qDebug()<<"key_0 released"<<endl;
}
else
{
QWidget::keyReleaseEvent(event);
}
}
}
But apparently isAutoRepeat function isn't working as I can see continuous print out of key_0 pressed and key_0 released despite the fact I haven't released the 0 key after I have pressed it. Is my code wrong or something else is wrong?
Thanks.
EDIT
I think this is happening because the MainWindow loses the keyboard focus. How can I actually find out which widget has the focus? I'm actually using some widgets when Qt::Key_0 pressed, but I thought I set all those possible widgets to Qt::NoFocus, I guess it's not working.
I'm trying to know which widget has the focus by doing the following:
QWidget * wigdet = QApplication::activeWindow();
qDebug()<<wigdet->accessibleName()<<endl;
but it always prints an empty string. How can I make it print the name of the widget which has the keyboard focus?
So as I also stumbled over this issue (and grabKeyboard didn't really help), I begun digging in qtbase. It is connected to X11 via xcb, and by default, in case of repeated keys, X11 sends for each repeated key a release-event immediately followed by a key-press-event. So holding down a key results in a sequence of XCB_BUTTON_RELEASE/XCB_BUTTON_PRESS-events beeing sent to the client (try it out with xev or the source at the end of this page).
Then, qt (qtbase/src/plugins/platforms/xcb/qxcbkeyboard.cpp) tries to figure out from these events whether its an autorepeat case: when a release is received, it uses a lookahead feature to figure if its followed by a press (with timestamps close enough), and if so it assumes autorepeat.
This does not always work, at least not on all platforms. For my case (old and outworn slow laptop (Intel® Celeron(R) CPU N2830 # 2.16GHz × 2) running ubuntu 16.04), it helped to just put a usleep (500) before that check, allowing the press event following the release event to arrive... it's around line 1525 of qxcbkeyboard.cpp:
// look ahead for auto-repeat
KeyChecker checker(source->xcb_window(), code, time, state);
usleep(500); // Added, 100 is to small, 200 is ok (for me)
xcb_generic_event_t *event = connection()->checkEvent(checker);
if (event) {
...
Filed this as QTBUG-57335.
Nb: The behaviour of X can be changed by using
Display *dpy=...;
Bool result;
XkbSetDetectableAutoRepeat (dpy, true, &result);
Then it wont send this release-press-sequences in case of a hold down key, but using it would require more changes to the autorepeat-detection-logic.
Anyway solved it.
The problem was that I have a widget which is a subclass of QGLWidget which I use to show some augmented reality images from Kinect. This widget takes over the keyboard focus whenever a keyboard button is pressed.
To solve this problem, I needed to call grabKeyboard function from the MainWindow class (MainWindow is a subclass of QMainWindow), so this->grabKeyboard() is the line I needed to add when key_0 button is pressed so that MainWindow doesn't lose the keyboard focus, and then when the key is released I needed to add the line this->releaseKeyboard() to resume normal behaviour, that is, other widgets can have the keyboard focus.

Simulating a mouse button press on Qt 5.3 only works the first time

I've written at QT5/QML application that I wish to be able to control remotely from a web browser. I'm sending a screen shot out to the browser and receiving position as x,y in return. I've written a C++ class to do this.
When I start the application, the image comes up and the first click from the browser works. The second does not work. If I click anywhere in the application, I see the button press happen on the screen, and then the remote press will work one more time.
I suspect the problem is that the focus changes and it's not being reset properly until I click on the actual application.
I'm using QGuiApplicatiop and so far haven't been able to get anythong useful out of itemAt or widgetAt so I can send the event to the appropriate object.
Here's a code snippet to show what I'm doing.
void Wremote::mClick(int x, int y ) {
QPointF *pos = new QPointF((qreal)x,(qreal)y);
QWindowList wl = QGuiApplication::allWindows();
_mwindow = wl[0];
QMouseEvent pevent(QEvent::MouseButtonPress,
*pos, Qt::LeftButton
,Qt::LeftButton, 0);
QMouseEvent revent(QEvent::MouseButtonRelease,
*pos, Qt::LeftButton
,Qt::LeftButton, 0);
QApplication::instance() ->sendEvent(_mwindow, &pevent);
QApplication::processEvents();
QApplication::instance() ->sendEvent(_mwindow, &revent);
QApplication::processEvents();
}
This is my first foray into integrating Qt with C++. The bulk of the application uses pyotherside.
Any pointers to where I'm going wrong would be appreciated.
Thanks,
Steve
Here's a working solution if not an elegant one.
void Wremote::mClick(int x, int y ) {
QTest::mouseClick(_mwindow,Qt::LeftButton,0,QPoint(x,y),-1);
}

Creating HyperLink in Notepad(textEdit)[MFC]

I am building a textEdit application with MFC. Is there a way to create a hyperlink automatically when a user write web address? It's like when you write a web address "www.google.com" the application detects web address and create a hyperlink right away. I have searched documents that explains about this, but couldn't find it..
and i couldn't make it..
i already have made notepad but i couldn't add the function of hyperlink on the notepad.
the following sentences are functions of hyperlink.
Clicking the text needs to open a browser window to the location specified by the text.
The cursor needs to change from the standard arrow cursor to a pointing index finger when it moves over the control.
The text in the control needs to be underlined when the cursor moves over the control.
A hyperlink control needs to display text in a different color—black just won't do.
The features that I added are:
5.A hyperlink control once visited needs to change color.
6.The hyperlink control should be accessible from the keyboard.
7.It should install some kind of hooks to allow the programmer to perform some actions when the control has the focus or when the cursor is hovering over the control.
Among the functions, What I mostly want to complete is the first one.
If I click a Hyperlink text, it should be linked to a browser window on the Internet.
Please answer and help me. Thanks.
Just use a CRichEditCtrl control (remember to call AfxInitRichEdit2 in your InitInstance). Call SetAutoURLDetect. Done.
Unfortunately this is not enough to make it work. It will display text that resembles URL as blue underlined but it will not invoke the link.
This will have to be handled by additional code. This will set needed event mask:
long lMask = m_RichEditCtrl.GetEventMask();
m_RichEditCtrl.SetEventMask(lMask | ENM_LINK);
m_RichEditCtrl.SetAutoURLDetect();
Also reflected EN_LINK will has to be handled to follow the link. For example:
void CHyperLinkInEditView::OnEnLink(NMHDR *pNMHDR, LRESULT *pResult)
{
ENLINK *p_Link = reinterpret_cast<ENLINK *>(pNMHDR);
if(p_Link && p_Link->msg == WM_LBUTTONDOWN)
{
//int iRange = m_RichEditCtrl.GetTextRange(p_enLinkInfo->chrg.cpMin, p_enLinkInfo->chrg.cpMax);
m_RichEditCtrl.SetSel(p_Link->chrg);
CString szLinkString = m_RichEditCtrl.GetSelText ();
ShellExecute(m_hWnd, L"Open", szLinkString, NULL, NULL, SW_MAXIMIZE);
}
*pResult = 0;
}
All of the above will solve requirement 1, 2, 3 (partially –text is underlined always), and 4.
I do not quite understand 5, 6 and 7.
Could you elaborate?

How to implement the mouse click for URLs at rich edit control

I added a read-only rich edit 2.0 control to my dialog (code is using C windows API, the dialog is created by using function DialogBox)
At the dialog call back, at the WM_INITDIALOG, I add the following code to enable url detection and also enable the event ENM_LINK is sent to the parent dialog instead of the rich edit control itself:
LRESULT mask = SendMessage(hWndText, EM_GETEVENTMASK, 0, 0); //hWndText is rich edit control
SendMessage(hWndText, EM_SETEVENTMASK, 0, mask | ENM_LINK);
::SendMessage(hWndText, EM_AUTOURLDETECT, TRUE, NULL);
I had a little trouble to enable the url detection when dialog is initially launched (which seems a known issue or behavior since rich edit control would only enable url detection of modified text). However I worked around this issue by setting the dialog text again on every WM_PAINT event.
The code is generally working. I also implemented the following code to launch the URL at the browser when mouse is hovering over the url:
case WM_NOTIFY:
plink = (ENLINK *) lParam;
switch(LOWORD(wParam))
{
case IDC_DISPLAY_TEXT_2: //this is ID for my rich edit control
szURL =m_strDisplay.Mid(plink->chrg.cpMin, plink->chrg.cpMax - plink->chrg.cpMin);
LaunchURL(szURL); //function to launch the url with default browser
break;
default:
break;
}
It seems that I would get WM_NOTIFY event every time when I hovered the mouse over the url. However when I clicked on it, I always get same event as the mouse hover over.
Based on the structure of ENLINK, I should get more detailed NM event at the NMHDR structure, however the value plink->nmhdr.code is always 1803 which is not even NM_HOVER (its defined value is (NM_FIRST-13) and NM_FIRST is (0U- 0U), so NM_HOVER value is 4294967283 on my 64 bit machine). I know that I am missing something here. Could someone shed some lights here? How can I get the mouse click event for the rich edit control?
I think you should capture the EN_LINK notification. I implemented the following code. It enables a url link in a richedit control placed into the parent window, not into a dialog. You could adapt it for your dialog, as well.
Consider beginning with the code:
case WM_NOTIFY: {
switch (((LPNMHDR)lParam)->code) { //NMHDR structure contains information about a notification message.
case EN_LINK: {
ENLINK *enLinkInfo = (ENLINK *)lParam; // pointer to a ENLINK structure
then, if you choose to launch url on LBUTTONUP, you have to check the value contained in enLinkInfo->msg (remember to adapt it for your dialog, though)
if (enLinkInfo->msg == WM_LBUTTONUP) {
// select all the text from enLinkInfo->chrg.cpMin to enLinkInfo->chrg.cpMax
// lauch the url
}
Besides, you can intercept WM_MOUSEMOVE:
if(enLinkInfo->msg == WM_MOUSEMOVE) {
; // do nothing
}
Hope it helps.
As the answer by #A_nto2 shows, to intercept a mouse click do:
case WM_NOTIFY: {
//NMHDR structure contains information about a notification message.
switch (((LPNMHDR)lParam)->code) {
case EN_LINK: {
ENLINK *enLinkInfo = (ENLINK *)lParam; // pointer to a ENLINK structure
if (enLinkInfo->msg == WM_LBUTTONUP) {
But the tricky part is to get the link that was clicked on.
One gets a "range" that was clicked on in the enLinkInfo->chrg of the type CHARRANGE.
An answer to Detect click on URL in RichEdit suggests using the EM_EXSETSEL with the enLinkInfo->chrg. And then using the EM_GETSELTEXT to retrieve the text.
That works with auto-detected plain-text URLs (EM_AUTOURLDETECT).
A problem is with friendly name hyperlinks (i.e. those that have an anchor text different than the URL itself):
{\rtf1{\field{\*\fldinst{ HYPERLINK "https://www.example.com"}}{\fldrslt{Example}}}}
(Note that these are supported in Rich Edit 4.1 and newer only)
For these, the CHARRANGE points to the HYPERLINK "https://www.example.com" part, which is hidden and cannot be selected using the EM_EXSETSEL. Actually it can be selected on Windows 10. But it cannot be selected on Windows 7, Vista and XP. Sending the EM_EXSETSEL to these systems results in selecting a zero-length block just after the hidden part.
So either you have to go back in the rich edit buffer and scan for the link; or use another method to retrieve the clicked text.
In my case, as I have small texts only in the rich edit, I've used the WM_GETTEXT. It returns a plain-text version of the rich edit document, but with the friendly name hyperlinks preserved in this form:
HYPERLINK "https://www.example.com" Example
The CHARRANGE points to the URL, strangely including the leading quote: ("https://www.example.com).
But the indexes correspond to a text with a single-character (LF) line separators. While the WM_GETTEXT returns the CRLF separators. So you have to convert the text to the LF before extracting the URL using the CHARRANGE.
According to the documentation of EM_AUTOURLDETECT, you are supposed to get an EN_LINK notification, which should be reflected in the nmhdr.code. According to Google,
#define EN_LINK 0x70B
which is 7 * 256 + 11 = 1750 + 42 + 11 = 1803.
Please note that your code misses a check for nmhdr.code == EN_LINK.
I'm not sure if the control sends NM_HOVER messages at all.