Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Track Cursor Events With Window Click Through
Forum Updated to NodeBB v4.3 + New Features

Track Cursor Events With Window Click Through

Scheduled Pinned Locked Moved Unsolved General and Desktop
10 Posts 2 Posters 720 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • H Offline
    H Offline
    HOSHI
    wrote on last edited by HOSHI
    #1

    Hello. I am currently trying to capture cursor events so that I can draw some sort of cursor trail. I also want it disabled under specific conditions, such as when the mouse shape is currently precision (the + shaped cursor). To do this, I need to have a full screen, completely transparent window on top of everything so that I can capture events. At the same time, it needs to be click-through because otherwise the program would be simply useless. While I can achieve these two independently, but I cannot do them both at the same time.
    The code is as follows:

    MainOverlay::MainOverlay(QWidget *parent): QMainWindow(parent), ui(new Ui::MainOverlay){
        ui->setupUi(this);
        // this->setMouseTracking(true);
        this->installEventFilter(this);
        this->setAttribute(Qt::WA_TranslucentBackground);
        // this->setAttribute(Qt::WA_AlwaysStackOnTop, true);
        this->setAttribute(Qt::WA_TransparentForMouseEvents); //10th line
        this->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
        this->showFullScreen();
    }
    
    bool MainOverlay::eventFilter(QObject *obj, QEvent *event) {
        if (event->type() == QEvent::HoverMove) {
            auto cur = this->cursor();
            auto str = QString("%1, %2 (%3)").arg(cur.pos().x()).arg(cur.pos().y()).arg(cur.shape());
            qInfo() << str;
        }
        return false;
    }
    
    MainOverlay::~MainOverlay(){
        delete ui;
    }
    

    If I comment out the 10th line, I can no longer click through the window, but the output successfully prints out the location of the cursor. If I don't comment it out, then the window becomes click-through but the program no longer receives cursor events.

    What can I do to do both?

    Another semi-related question: I want this window to be an overlay that does not interfere with the user much. Currently, the window is shown in the taskbar, and is in whatever the alt-tab window is called. How can I hide the window from there? I would like to have the program to function like an overlay.
    26b6ca0b-6d10-4a06-9d87-483458dc2393-image.png
    S.png

    Axel SpoerlA 1 Reply Last reply
    0
    • H HOSHI

      Hello. I am currently trying to capture cursor events so that I can draw some sort of cursor trail. I also want it disabled under specific conditions, such as when the mouse shape is currently precision (the + shaped cursor). To do this, I need to have a full screen, completely transparent window on top of everything so that I can capture events. At the same time, it needs to be click-through because otherwise the program would be simply useless. While I can achieve these two independently, but I cannot do them both at the same time.
      The code is as follows:

      MainOverlay::MainOverlay(QWidget *parent): QMainWindow(parent), ui(new Ui::MainOverlay){
          ui->setupUi(this);
          // this->setMouseTracking(true);
          this->installEventFilter(this);
          this->setAttribute(Qt::WA_TranslucentBackground);
          // this->setAttribute(Qt::WA_AlwaysStackOnTop, true);
          this->setAttribute(Qt::WA_TransparentForMouseEvents); //10th line
          this->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
          this->showFullScreen();
      }
      
      bool MainOverlay::eventFilter(QObject *obj, QEvent *event) {
          if (event->type() == QEvent::HoverMove) {
              auto cur = this->cursor();
              auto str = QString("%1, %2 (%3)").arg(cur.pos().x()).arg(cur.pos().y()).arg(cur.shape());
              qInfo() << str;
          }
          return false;
      }
      
      MainOverlay::~MainOverlay(){
          delete ui;
      }
      

      If I comment out the 10th line, I can no longer click through the window, but the output successfully prints out the location of the cursor. If I don't comment it out, then the window becomes click-through but the program no longer receives cursor events.

      What can I do to do both?

      Another semi-related question: I want this window to be an overlay that does not interfere with the user much. Currently, the window is shown in the taskbar, and is in whatever the alt-tab window is called. How can I hide the window from there? I would like to have the program to function like an overlay.
      26b6ca0b-6d10-4a06-9d87-483458dc2393-image.png
      S.png

      Axel SpoerlA Offline
      Axel SpoerlA Offline
      Axel Spoerl
      Moderators
      wrote on last edited by
      #2

      @HOSHI
      No matter how often I count, your 10th line is number 7 for me. But that's my fault, I am sure :-)

      This line is making the widget unresponsive to mouse events. I am not sure, if this is what you want. I am also a bit confused about "cursor events". I guess you mean mouse events.

      What also comes to mind, is that the event filter always returns false.
      That tells the event handler, that the event has not been processed and needs to be delivered to the widget's eventoverride.
      I don't know exactly what is meant by

      then the window becomes click-through

      If you mean that the widget reacts to the mouse events, you can avoid it by returning trueif your event filter has processed the QEvent::HoverMove.

      Software Engineer
      The Qt Company, Oslo

      H 1 Reply Last reply
      0
      • Axel SpoerlA Axel Spoerl

        @HOSHI
        No matter how often I count, your 10th line is number 7 for me. But that's my fault, I am sure :-)

        This line is making the widget unresponsive to mouse events. I am not sure, if this is what you want. I am also a bit confused about "cursor events". I guess you mean mouse events.

        What also comes to mind, is that the event filter always returns false.
        That tells the event handler, that the event has not been processed and needs to be delivered to the widget's eventoverride.
        I don't know exactly what is meant by

        then the window becomes click-through

        If you mean that the widget reacts to the mouse events, you can avoid it by returning trueif your event filter has processed the QEvent::HoverMove.

        H Offline
        H Offline
        HOSHI
        wrote on last edited by HOSHI
        #3

        @Axel-Spoerl
        Yeah, it would be line 7 in the post, and 10th line in the IDE.
        To clarify, this is what I am trying to make for now:

        1. If I hover my mouse around, I expect the coordinate to be printed in the application output.
        2. If I click on any part of the screen, it works as if the window is not there. This is what I mean by click-through. For example, if I click on this while the program is running:
          4baae783-33bf-4298-965a-c3108e3a3aa0-image.png
          I expect the screen to turn into this.
          0305b750-390e-49d8-abbc-915d2ec33c05-image.png
          Note that this is just an example; I expect this "click-through" to work with any program.

        Currently, when this->setAttribute(Qt::WA_TransparentForMouseEvents); is commented out, number 1 works, but number 2 doesn't. The coordinates are printed into the output, but clicks have no effect.

        Axel SpoerlA 1 Reply Last reply
        0
        • H HOSHI

          @Axel-Spoerl
          Yeah, it would be line 7 in the post, and 10th line in the IDE.
          To clarify, this is what I am trying to make for now:

          1. If I hover my mouse around, I expect the coordinate to be printed in the application output.
          2. If I click on any part of the screen, it works as if the window is not there. This is what I mean by click-through. For example, if I click on this while the program is running:
            4baae783-33bf-4298-965a-c3108e3a3aa0-image.png
            I expect the screen to turn into this.
            0305b750-390e-49d8-abbc-915d2ec33c05-image.png
            Note that this is just an example; I expect this "click-through" to work with any program.

          Currently, when this->setAttribute(Qt::WA_TransparentForMouseEvents); is commented out, number 1 works, but number 2 doesn't. The coordinates are printed into the output, but clicks have no effect.

          Axel SpoerlA Offline
          Axel SpoerlA Offline
          Axel Spoerl
          Moderators
          wrote on last edited by
          #4

          @HOSHI
          If the intention is to print the mouse coordinates no matter what, I would not rely on hover events or specific widgets here.
          I'd install an event filter on qApp (the application) and intercept QEvent::MouseMove. You can print the coordinates in your window and make it transparent for mouse events.

          Software Engineer
          The Qt Company, Oslo

          H 1 Reply Last reply
          1
          • Axel SpoerlA Axel Spoerl

            @HOSHI
            If the intention is to print the mouse coordinates no matter what, I would not rely on hover events or specific widgets here.
            I'd install an event filter on qApp (the application) and intercept QEvent::MouseMove. You can print the coordinates in your window and make it transparent for mouse events.

            H Offline
            H Offline
            HOSHI
            wrote on last edited by HOSHI
            #5

            @Axel-Spoerl Do you mean something like this?

            #include "widget.h"
            #include "./ui_widget.h"
            #include <QLabel>
            
            Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget){
                ui->setupUi(this);
                this->setMouseTracking(true);
                qApp->installEventFilter(this);
                QLabel *label = new QLabel(this);
                label->setText("Window is open!");
                this->setAttribute(Qt::WA_TranslucentBackground);
                this->setAttribute(Qt::WA_TransparentForMouseEvents); //Line 12
                this->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::X11BypassWindowManagerHint);
                this->showFullScreen();
            }
            
            bool Widget::eventFilter(QObject *obj, QEvent *event) {
                if(!event->isPointerEvent()) return false;
                if (event->type() == QEvent::MouseMove) {
                    auto cur = this->cursor();
                    auto str = QString("%1, %2 (%3)").arg(cur.pos().x()).arg(cur.pos().y()).arg(cur.shape());
                    qInfo() << str;
                }
                return true;
            }
            
            Widget::~Widget() {
                delete ui;
            }
            
            
            

            When line 12 is commented out, the application output correctly prints the coordinate of the cursor as well as its current shape, but I cannot interact with anything underneath the invisible overlay. If it is not commented out, I can interact with anything underneath the overlay, but the eventFilter is not triggered. I do expect Qt::WA_TransparentForMouseEvents to make eventFilter to not trigger, but I would like to know if there is a way around that, and read the current mouse location and shape whilst allowing me to interact with anything underneath the overlay.

            Axel SpoerlA 1 Reply Last reply
            0
            • H HOSHI

              @Axel-Spoerl Do you mean something like this?

              #include "widget.h"
              #include "./ui_widget.h"
              #include <QLabel>
              
              Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget){
                  ui->setupUi(this);
                  this->setMouseTracking(true);
                  qApp->installEventFilter(this);
                  QLabel *label = new QLabel(this);
                  label->setText("Window is open!");
                  this->setAttribute(Qt::WA_TranslucentBackground);
                  this->setAttribute(Qt::WA_TransparentForMouseEvents); //Line 12
                  this->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::X11BypassWindowManagerHint);
                  this->showFullScreen();
              }
              
              bool Widget::eventFilter(QObject *obj, QEvent *event) {
                  if(!event->isPointerEvent()) return false;
                  if (event->type() == QEvent::MouseMove) {
                      auto cur = this->cursor();
                      auto str = QString("%1, %2 (%3)").arg(cur.pos().x()).arg(cur.pos().y()).arg(cur.shape());
                      qInfo() << str;
                  }
                  return true;
              }
              
              Widget::~Widget() {
                  delete ui;
              }
              
              
              

              When line 12 is commented out, the application output correctly prints the coordinate of the cursor as well as its current shape, but I cannot interact with anything underneath the invisible overlay. If it is not commented out, I can interact with anything underneath the overlay, but the eventFilter is not triggered. I do expect Qt::WA_TransparentForMouseEvents to make eventFilter to not trigger, but I would like to know if there is a way around that, and read the current mouse location and shape whilst allowing me to interact with anything underneath the overlay.

              Axel SpoerlA Offline
              Axel SpoerlA Offline
              Axel Spoerl
              Moderators
              wrote on last edited by
              #6

              @HOSHI
              Can you please specify, what exactly is your expected behavior?
              I am a bit confused about what is the use case here.
              Do you only want to write the mouse position to the application output, or print it somewhere on the screen?

              Event filter is installed correctly. Making the widget transparent for mouse events or not, has no influence on the event filter installed on application level. Returning true after printing the coordinates tells the event handler, that the event is consumed. It will not be delivered elsewhere.

              Software Engineer
              The Qt Company, Oslo

              H 1 Reply Last reply
              0
              • Axel SpoerlA Axel Spoerl

                @HOSHI
                Can you please specify, what exactly is your expected behavior?
                I am a bit confused about what is the use case here.
                Do you only want to write the mouse position to the application output, or print it somewhere on the screen?

                Event filter is installed correctly. Making the widget transparent for mouse events or not, has no influence on the event filter installed on application level. Returning true after printing the coordinates tells the event handler, that the event is consumed. It will not be delivered elsewhere.

                H Offline
                H Offline
                HOSHI
                wrote on last edited by HOSHI
                #7

                @Axel-Spoerl
                Okay, I originally mentioned cursor trail in OP, but I should simplify the use case for the sake of communication. Say, I need a cursor highlighter. All it does is highlight where my cursor is at, but with one extra feature (number 3). I expect the program to do the following:

                1. A circle is drawn around the hotspot of the cursor. It follows it around. If I move my cursor sideways, the circle underneath it follows it. It's a cursor highlighter, after all. This must happen on any part of the screen. The reason I need the coordinates of the mouse is to draw the circle.
                  0d756136-4fd8-419f-9057-64351308da9d-image.png
                2. The overlay itself must not interfere with the normal use. In other words, the overlay must not block clicking, dragging, scroll, as if the overlay is not there.
                3. The highlight disappears when the cursor turns into precision cursor for any reason. Again, this must happen on any part of the screen.
                  9c373740-f668-44ff-8708-1971a0021fa9-image.png

                You've probably seen those crappy Bandicam recorded videos, where the cursor is highlighted with yellow, and when the user clicks on any part of the screen, the yellow circle does not interfere with any interaction. If you haven't, here's an example: https://www.youtube.com/watch?v=wpg1YmuxNv8

                The reason I'm keep mentioning requirement number 2 is because I am having trouble achieving that one in particular. If I remove the line this->setAttribute(Qt::WA_TransparentForMouseEvents);, then I can achieve number 2 because the overlay no longer interferes with the normal use. However, the overlay stops receiving any mouse events, and I cannot achieve number 1 and 3. If I add the line this->setAttribute(Qt::WA_TransparentForMouseEvents); back into the code, the program receives mouse events and I can achieve 1 and 3, but the overlay blocks all clicking, and the requirement number 2 is no longer met. Making the event filter to return false did not help either.
                I need the overlay to be both always on top and full screen so that it can receive all cursor events and draw highlight regardless of the mouse location.

                I hope this is clear enough.

                Axel SpoerlA 1 Reply Last reply
                0
                • H HOSHI

                  @Axel-Spoerl
                  Okay, I originally mentioned cursor trail in OP, but I should simplify the use case for the sake of communication. Say, I need a cursor highlighter. All it does is highlight where my cursor is at, but with one extra feature (number 3). I expect the program to do the following:

                  1. A circle is drawn around the hotspot of the cursor. It follows it around. If I move my cursor sideways, the circle underneath it follows it. It's a cursor highlighter, after all. This must happen on any part of the screen. The reason I need the coordinates of the mouse is to draw the circle.
                    0d756136-4fd8-419f-9057-64351308da9d-image.png
                  2. The overlay itself must not interfere with the normal use. In other words, the overlay must not block clicking, dragging, scroll, as if the overlay is not there.
                  3. The highlight disappears when the cursor turns into precision cursor for any reason. Again, this must happen on any part of the screen.
                    9c373740-f668-44ff-8708-1971a0021fa9-image.png

                  You've probably seen those crappy Bandicam recorded videos, where the cursor is highlighted with yellow, and when the user clicks on any part of the screen, the yellow circle does not interfere with any interaction. If you haven't, here's an example: https://www.youtube.com/watch?v=wpg1YmuxNv8

                  The reason I'm keep mentioning requirement number 2 is because I am having trouble achieving that one in particular. If I remove the line this->setAttribute(Qt::WA_TransparentForMouseEvents);, then I can achieve number 2 because the overlay no longer interferes with the normal use. However, the overlay stops receiving any mouse events, and I cannot achieve number 1 and 3. If I add the line this->setAttribute(Qt::WA_TransparentForMouseEvents); back into the code, the program receives mouse events and I can achieve 1 and 3, but the overlay blocks all clicking, and the requirement number 2 is no longer met. Making the event filter to return false did not help either.
                  I need the overlay to be both always on top and full screen so that it can receive all cursor events and draw highlight regardless of the mouse location.

                  I hope this is clear enough.

                  Axel SpoerlA Offline
                  Axel SpoerlA Offline
                  Axel Spoerl
                  Moderators
                  wrote on last edited by
                  #8

                  @HOSHI
                  Okay...communication is key... I may be slow in understanding things, but I don't see how this is connected to "Track Cursor Events With Window Click Through".
                  Let me think about this use case a bit, I'll come back on it.

                  Software Engineer
                  The Qt Company, Oslo

                  H 1 Reply Last reply
                  0
                  • Axel SpoerlA Axel Spoerl

                    @HOSHI
                    Okay...communication is key... I may be slow in understanding things, but I don't see how this is connected to "Track Cursor Events With Window Click Through".
                    Let me think about this use case a bit, I'll come back on it.

                    H Offline
                    H Offline
                    HOSHI
                    wrote on last edited by HOSHI
                    #9

                    @Axel-Spoerl
                    The event is primarily for the 3rd requirement where the highlight disappears when the cursor shape changes to precision shape (known as Qt::CrossCursor). I am planning on getting it using shape() to get something from this list: https://doc.qt.io/qt-6/qt.html#CursorShape-enum
                    Additionally, I aim to add a number of features, including but not limited to:

                    • Ripple on click
                    • Different colour ripple for right click, middle click, etc

                    I did not mention them in OP because I originally did not expect getting the event to be complicated.
                    I would love to know if there are any other ways to get them though.

                    Axel SpoerlA 1 Reply Last reply
                    0
                    • H HOSHI

                      @Axel-Spoerl
                      The event is primarily for the 3rd requirement where the highlight disappears when the cursor shape changes to precision shape (known as Qt::CrossCursor). I am planning on getting it using shape() to get something from this list: https://doc.qt.io/qt-6/qt.html#CursorShape-enum
                      Additionally, I aim to add a number of features, including but not limited to:

                      • Ripple on click
                      • Different colour ripple for right click, middle click, etc

                      I did not mention them in OP because I originally did not expect getting the event to be complicated.
                      I would love to know if there are any other ways to get them though.

                      Axel SpoerlA Offline
                      Axel SpoerlA Offline
                      Axel Spoerl
                      Moderators
                      wrote on last edited by
                      #10

                      @HOSHI
                      The architecture seems off and overly complicated to me:

                      • You implement a class inheriting from QWidget, which looks like an application's main window.
                      • This class' mouse events are intercepted to eventually move a highlighter with the cursor.
                      • We don't know anything about this highlighter, so I assume it's just a normal cursor, surrounded by a halo.

                      => Why don't you write your own cursor(s), inheriting from QCursor and use setOverrideCursor()?

                      Software Engineer
                      The Qt Company, Oslo

                      1 Reply Last reply
                      0

                      • Login

                      • Login or register to search.
                      • First post
                        Last post
                      0
                      • Categories
                      • Recent
                      • Tags
                      • Popular
                      • Users
                      • Groups
                      • Search
                      • Get Qt Extensions
                      • Unsolved