register for WindowServer CGScreenRefreshCallback CGScreenUpdateMoveCallback in C++ - c++

I'm trying to register for CGScreenRefreshCallback and CGScreenUpdateMoveCallback ( here's what apple's saying about http://developer.apple.com/mac/library/documentation/GraphicsImaging/Reference/Quartz_Services_Ref/Reference/reference.html#//apple_ref/doc/uid/TP30001070-CH1g-F16970 )
using C++ only.
I wrote this simple tester for the refresh callback in order to retrieve the changing rectangles:
#include "ApplicationServices/ApplicationServices.h"
#include <iostream>
using namespace std;
/////////////HEADER
static void DHRefreshCallback (CGRectCount count,const CGRect * rectArray,void * userParameter);
///////////////////
int main (int argc, char * const argv[]) {
CGRegisterScreenRefreshCallback(DHRefreshCallback, NULL);
while (true) {
// just hanging
}
return 0;
}
static void DHRefreshCallback (CGRectCount count,const CGRect * rectArray,void * userParameter){
cout << "something changed" << endl;
return;
}
...but didn't work.
I know I need a connection with WindowServer (Quartz Compositor \ Quartz Extreme \ Quartz Extreme 2D...still can't figure out the difference) and a running thread in order to get these callbacks, but I really don't know how to do this in C++ only (no Objective-C at all).
any direction?
thx in advance,
pigiuz

It's not about using/not using Objective-C. It's about the event loop in OS X apps in general, which is done by CFRunloop, which is a C API. See Run Loop management and CFRunLoop reference. You also need a connection to the window server, which can be established by calling
Instead of
while (true) {
// just hanging
}
just do
extern "C" void NSApplicationLoad(void);
NSApplicationLoad(); // establish a connection to the window server. In <Cocoa/Cocoa.h>
CFRunLoopRun(); // run the event loop
Don't forget to link against Cocoa.framework; just add -framework Cocoa in the command line of the compiler.
You can #import <Cocoa/Cocoa.h> but then you need to use Objective-C++ because of the Objective-C classes declared in it.
You could use
RunApplicationEventLoop(); //establish a connection to the window server
//and runs the event loop. In <Carbon/Carbon.h>
in an 32 bit app, instead of NSApplicationLoad + CFRunLoopRun, but it's not available in an 64 bit app.

Related

Get Capslock state on Linux with Wayland

I am struggling with the following task: for our cross-platform application I want to enable a capslock warning for the user. This works perfectly on Windows and macOS and is a bit unnecessarily complicated but doable on Linux with X11, though I cannot find out how to do it properly on Wayland.
We are using Qt5, so the more Qt APIs I can use for this, the better. I see that Qt has a very extensive Wayland framework, but it seems to be designed primarily for writing your own compositor and not for accessing specifics of the underlying platform plugin.
Here's the code as far as I have it:
#include <QGuiApplication>
#include <qpa/qplatformnativeinterface.h>
// namespace required to avoid name clashes with declarations in XKBlib.h
namespace X11
{
#include <X11/XKBlib.h>
}
void checkCapslockState()
{
// ... Windows and macOS one-liners
// Here starts the Linux mess.
// At least I can query the display with this for both X11 and Wayland.
QPlatformNativeInterface* native = QGuiApplication::platformNativeInterface();
auto* display = native->nativeResourceForWindow("display", nullptr);
if (!display) {
return;
}
const QString platform = QGuiApplication::platformName();
if (platform == "xcb") {
unsigned state = 0;
if (X11::XkbGetIndicatorState(reinterpret_cast<X11::Display*>(display), XkbUseCoreKbd, &state) == Success) {
// works fine
newCapslockState = ((state & 1u) != 0);
}
} else if (platform == "wayland") {
// but how to proceed here?
// struct wl_display* waylandDisplay = reinterpret_cast<struct wl_display*>(display);
}
// ...
}
My understanding is that I have to get hold of the Wayland wl_seat object somehow, which holds information about the wl_keyboard. However, I cannot find a way to access these objects from the wl_display object alone without instantiating all sorts of contexts. The Qt application itself is already running as a Wayland client, so there should be a way to access these objects, I would assume. Unfortunately, the Wayland documentation on this is very sparse and quite opaque for someone not familiar with the whole architecture and Wayland's user base is still too small that things pop up on Google.
I found a solution, but I am far from satisfied with it.
I am using KWayland here, but it is possible to use the plain Wayland C API, of course. Be prepared to write 200-300 additional lines of boilerplate code, though. KWayland abstracts that a bit, but it is still pretty verbose. Even the X11 solution is shorter, let alone the one-liners of Windows and macOS.
I don't think this is a state in which Wayland will be pretty successful in the long-term. It's okay to have that much control on the lowest level, but there need to be proper high-level abstractions in place.
Long story short, here's the full code for all platforms:
#include <QGuiApplication>
#if defined(Q_OS_WIN)
#include <windows.h>
#elif defined(Q_OS_MACOS)
#include <CoreGraphics/CGEventSource.h>
#elif defined(Q_OS_UNIX)
#include <qpa/qplatformnativeinterface.h>
// namespace required to avoid name clashes with declarations in XKBlib.h
namespace X11
{
#include <X11/XKBlib.h>
}
#include <KF5/KWayland/Client/registry.h>
#include <KF5/KWayland/Client/seat.h>
#include <KF5/KWayland/Client/keyboard.h>
#endif
void MyCls::checkCapslockState()
{
const QString platform = QGuiApplication::platformName();
#if defined(Q_OS_WIN)
newCapslockState = (GetKeyState(VK_CAPITAL) == 1);
#elif defined(Q_OS_MACOS)
newCapslockState = ((CGEventSourceFlagsState(kCGEventSourceStateHIDSystemState) & kCGEventFlagMaskAlphaShift) != 0);
#elif defined(Q_OS_UNIX)
// get platform display
QPlatformNativeInterface* native = QGuiApplication::platformNativeInterface();
auto* display = native->nativeResourceForWindow("display", nullptr);
if (!display) {
return;
}
if (platform == "xcb") {
unsigned state = 0;
if (X11::XkbGetIndicatorState(reinterpret_cast<X11::Display*>(display), XkbUseCoreKbd, &state) == Success) {
newCapslockState = ((state & 1u) != 0);
}
} else if (platform == "wayland") {
if (!m_wlRegistry) {
auto* wlDisplay = reinterpret_cast<struct wl_display*>(display);
m_wlRegistry.reset(new KWayland::Client::Registry());
m_wlRegistry->create(wlDisplay);
m_wlRegistry->setup();
// wait for a seat to be announced
connect(m_wlRegistry.data(), &KWayland::Client::Registry::seatAnnounced, [this](quint32 name, quint32 version) {
auto* wlSeat = new KWayland::Client::Seat(m_wlRegistry.data());
wlSeat->setup(m_wlRegistry->bindSeat(name, version));
// wait for a keyboard to become available in the seat
connect(wlSeat, &KWayland::Client::Seat::hasKeyboardChanged, [wlSeat, this](bool hasKeyboard) {
if (hasKeyboard) {
auto* keyboard = wlSeat->createKeyboard(wlSeat);
// listen for a modifier change
connect(keyboard, &KWayland::Client::Keyboard::modifiersChanged,
[this](quint32 depressed, quint32 latched, quint32 locked, quint32 group) {
Q_UNUSED(depressed)
Q_UNUSED(latched)
Q_UNUSED(group)
newCapslockState = (locked & 2u) != 0;
// emit signals etc. here to notify outer non-callback
// context of the new value of newCapslockState
});
}
});
});
}
}
// do something with the newCapslockState state for any
// platform other than Wayland
}
m_wlRegistry is defined as a QScopedPointer<KWayland::Client::Registry> member in the header file.
This solution basically works, but suffers from either a bug in KWin or a weirdness of the protocol (I don't know which). Pressing the Capslock key will trigger the inner lambda callback twice: first time with bit 2 in locked set and a second time on key release with it unset. There is no reliable way of filtering out this second activation based on the other parameters passed (I tried ignoring when depressed != 0, but it's not working as expected). Pressing any other key after that will trigger the callback a third time with the bit set again. So when you are actually typing, the code works, but when you are just pressing Capslock, the behaviour is weird and less reliable than the solutions for other platforms. Since the Capslock indicator in the Plasma tray has the same issue, I would assume this is a bug.
As a KDE-specific solution, there appears to be another interface one could listen to called org_kde_kwin_keystate (https://github.com/KDE/kwayland/blob/master/src/client/protocols/keystate.xml). However, when I was testing it in a KDE Neon VM, the compositor did not announce this protocol extension, so I was unable to use it.

Read text multiple times with Elementary access on native Tizen TV

Hello fellow programmers,
I am trying to use the Text To Speech functionality provided by the Elementary access library (from Enlightenment) in a native app for tizen TV.
So far I have been able to read text, but only once: when I call the API multiple times, only the first call is rendered to audio.
I have investigated the sources of elementary access, but can't really spot the problem.
Here is a sample of my app:
#include <app.h>
#include <Elementary.h>
#include <unistd.h>
#include <string>
using namespace std;
const char APP_PKG[] = "org.tizen.tts";
/// Struct to store application information and passed at start time to the efl framework
struct _appdata
{
const char *name;
Evas_Object *win;
};
static bool
_create(void *data)
{
elm_config_access_set(EINA_TRUE);
return true;
}
static bool
_control(app_control_h app_control, void *data)
{
for (int i = 1; i <= 2; i++) {
string text = to_string(i) + ". Read me please.";
elm_access_say(text.c_str());
// sleep(10);
}
return true;
}
int
main(int argc, char *argv[])
{
_appdata ad = {0,};
ad.name = APP_PKG;
ui_app_lifecycle_callback_s lifecycle_callback = {0,};
lifecycle_callback.create = _create;
lifecycle_callback.app_control = _control;
return ui_app_main(argc, argv, &lifecycle_callback, &ad);
}
I have tried using elm_access_force_say, also moving elm_config_access_set(EINA_TRUE) inside the loop, but everytime the sentence is only said once.
Here in the source is some code called by elm_access_say. It seems that the api makes a call to espeak executable, strangely I can't find any espeak executable on the device.
Tizen provides an API for using the TTS engine in native apps, but only for mobile and watches (at least in the documentation).
If someone ever tried to use the TTS engine on native TV, or have more experience with the Elementary access library, and would like to share some knowledge, I would be really thankful.
If you are using Tizen 4.0 or above and you want to read text multiple times using accessibility framework, please use the elm_atspi_bridge_utils_say. Below code snippet demonstrates how to read consecutive numbers.
statc void reade_n_times(int n) {
char buf[32];
for (int i=1;i<=n;++i){
snprintf(bug,sizesizeof(buf), "%d", i);
elm_atspi_bridge_utils_say(buf, EINA_FALSE, say_cb, NULL);
}
}
Full specification of elm_atspi_bridge_utils_say can be found here:
https://developer.tizen.org/dev-guide/tizen-iot-headed/4.0/group__Elm__Atspi__Bridge.html#gafde6945c1451cb8752c67f2aa871d12d "
Use this page for 4.0 Wearable API Reference. API Reference of tizen-iot-headed is not up-to-date.
https://docs.tizen.org/application/native/api/mobile/4.0/group__Elm__Atspi__Bridge.html

Listen close event of iexplorer in my application

I am writing a win32 application by C++, and I want it to do something when all iexplorer.exe were closed.
I know that SetWindowsHook() may be useful in my case.
But if I have no idea about the process or thread ID of IE, because every time open IE would get a different thread ID.
If I do not use timer to check the process list to get the ID of iexplorer, does there have another approach to listen close event of IE in my win32 application?
The object for IE is called InternetExplorer. TheShellWindows object is a collection of InternetExplorer objects. But here it gets complicated. Not all InternetExplorer objects are what you would call an IE window. Some of them are "Windows Explorer" windows. See About the Browser (Internet Explorer).
The following is a managed C++ console program that lists the existing windows and sets a count of the number of existing windows. Then it uses WindowRegistered and WindowRevoked events to monitor creation and closing of windows. Those event are not documented very well. The sample below uses the Document member of each InternetExplorer object to determine if the window has HTML. However see the comment in c# - Distinguishing IE windows from other windows when using SHDocVw; it is possible for a IE window to not have HTML in it.
Note that the following sample is using an AutoResetEvent to keep the program going since it is a console program.
The following is the header:
#pragma once
#include <stdio.h>
#include <tchar.h>
#include <windows.h>
#include <ShlObj.h>
#include <comdef.h>
#include <vcclr.h>
The following is the program:
#include "stdafx.h"
using namespace System;
using namespace System::Threading;
static int Browsers = 0;
static gcroot<AutoResetEvent^> Event;
bool IsBrowser(SHDocVw::InternetExplorer ^ ie)
{
MSHTML::IHTMLDocument2^ Document;
try { Document = (MSHTML::IHTMLDocument2^)ie->Document; }
catch (Exception^ ex)
{
return false;
}
return Document != nullptr;
}
static void WindowRegistered(int lCookie) {
++Browsers;
Console::WriteLine("WindowRegistered");
}
static void WindowRevoked(int lCookie) {
--Browsers;
Console::WriteLine("WindowRevoked");
if (Browsers <= 0)
Event->Set();
}
int main(array<System::String ^> ^args)
{
SHDocVw::ShellWindows^ swList = gcnew SHDocVw::ShellWindowsClass();
Console::WriteLine(L"{0} instances", swList->Count);
for each (SHDocVw::InternetExplorer ^ ie in swList) {
Console::WriteLine(ie->LocationURL);
if (IsBrowser(ie)) {
Console::WriteLine("HTML document");
++Browsers;
}
else
Console::WriteLine("Not HTML");
}
if (Browsers == 0)
{
Console::WriteLine("No browsers");
return 0;
}
Event = gcnew AutoResetEvent(false);
swList->WindowRegistered += gcnew SHDocVw::DShellWindowsEvents_WindowRegisteredEventHandler(WindowRegistered);
swList->WindowRevoked += gcnew SHDocVw::DShellWindowsEvents_WindowRevokedEventHandler(WindowRevoked);
Event->WaitOne();
Console::WriteLine("No more browsers");
return 0;
}
Now I just realized that there is a problem with the way this works. The WindowRegistered and WindowRevoked handlers are incrementing the Browsers count even if the window is not an IE window. I don't know how to determine what window that the cookie passed to WindowRegistered and WindowRevoked represents. A few years ago I spent a couple of days or more tryinig to figure that out. So what you should do is to somehow re-list all the windows after each WindowRegistered and WindowRevoked event.
You need to add references for "Microsoft Internet Controls" (SHDocVw.dll) and "Microsoft HTML Object Library" (mshtml.dll) to the project. They are COM objects that should be in your "C:\Windows\System32" directory.

Clipboard Shortcut/Hotkey binding with Qt outside of application

I've tried googling, and searching on this site about this but to no avail.
I am building a Clipboard related application for Windows using Qt, and one of the requirements for it to work right is to be able to register for keyboard events outside my Qt application, like ctrl + c, ctrl + v. (copy/paste). The only thing that I have found online is using an external plugin for Qt but the entire concept was not explained properly, so I hit a dead end.
Does anyone have an idea how I can do this? Again, I want to register shortcuts to my application that will occur outside the application itself.
Thanks in advance!
Binding clipboard shortcuts and binding shortcuts in general are as I have discovered, two different things. Related to Clipboard events, Qt provides access to a dataChanged() signal through its QClipboard class. Using that, you are able to know when the clipboard data has changed, and act accordingly, and should eliminate the need to perform a system-wide binding of the Copy/Paste shortcuts.
In order to register a global shortcut (in this case the need for ctrl + v), and this is platform specific like in my needs, one can use the RegisterHotKey function under Windows. The HWND requested as the first parameter can be obtained from the winId function that is provided by QWidget.
In order to accept the WM_HOTKEY event, one would have to implement the winEvent virtual protected function under Qt <= 5.0, and nativeEvent on >= 5.0.
This depends on the Desktopenvironment the application runs in and it is OS-specific. If you intend to run the application within KDE you can register global hotkeys easyly by deploying a .desktop File with your Application or by adding things to /usr/share/kde4/apps/khotkeys .
Within Windows, the easiest way would probably be adding a registry key to the registry in order to register a global Hotkey. See MSDN
I think you're just confused about how the clipboard works. You never need to register clipboard-related hotkeys outside of your application. Those are handled by other applications. What those applications do is interact with the system-wide clipboard. Your application needs to interact with the same clipboard and get notifications about new clipboard data being available etc.
You might get more helpful answers if you tell us what you mean by a "clipboard related" application. Is it used to sell wooden clipboards? Or to calibrate clipboard springs? Or to manage inventory of clipboards? Or does it run on a digital clipboard? Sigh.
This should get you up and running in Windows+Qt and HotKeys pretty quickly.
I haven't tried the Qt eXTension library with QxtGlobalShortcut, but it sounds like it may be a more elegant complete solution for more platforms. (like in #TimMeyer's comment to your question)
https://stackoverflow.com/a/3154652/808151
I wrote up this function to listen for a single system wide hotkey in windows.
#ifndef HOTKEYTHREAD_H
#define HOTKEYTHREAD_H
#include <QThread>
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
class HotKeyThread : public QThread
{
Q_OBJECT
public:
HotKeyThread(QObject *parent);
~HotKeyThread();
signals:
void hot_key_event(int);
public slots:
void run();
void stop();
private:
volatile bool m_stopped;
DWORD m_thread_id;
};
#endif // HOTKEYTHREAD_H
.cpp file
#include "hotkeythread.h"
#include <QDebug>
#include <process.h>
#define WM_END_THREAD (WM_USER+2)
HotKeyThread::HotKeyThread(QObject *parent)
: QThread(parent)
{
this->m_thread_id = 0;
}
HotKeyThread::~HotKeyThread()
{
}
void HotKeyThread::stop()
{
if(this->m_thread_id != 0)
::PostThreadMessage(this->m_thread_id, WM_END_THREAD, 0, 0);
}
//
void HotKeyThread::run()
{
// store a thread id so we can exit later
m_thread_id = ::GetCurrentThreadId();
qDebug() << "ThreadIDs" << QString::number(m_thread_id, 16) << QString::number((int) this->currentThreadId(), 16);
// register an atom, and a hotkey
BOOL retVal;
int counter = 0;
int magic_num = 1128;
ATOM id = ::GlobalAddAtom(MAKEINTATOM(magic_num + counter++));
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx
int modifier = 0x0;// modify this line
int key = VK_NUMPAD0;// modify this line
if(QSysInfo::windowsVersion() > QSysInfo::WV_VISTA)
{
retVal = ::RegisterHotKey(NULL, id, modifier | MOD_NOREPEAT, key);
}
else
{
// No repeat is only supported in 7 and later
retVal = ::RegisterHotKey(NULL, id, modifier, key);
}
if(retVal)
{
qDebug() << "Successfully added a HotKey!";
}
else
{
qDebug() << "Failed to add a hotkey!";
return;
}
// wait on hotkeys
MSG msg = {0};
while (0 < ::GetMessage(&msg, NULL, 0, 0))
{
if(msg.message == WM_HOTKEY)
{
bool control = LOWORD(msg.lParam) & MOD_CONTROL;
bool shift = LOWORD(msg.lParam) & MOD_SHIFT;
bool alt = LOWORD(msg.lParam) & MOD_ALT;
bool win = LOWORD(msg.lParam) & MOD_WIN;
qDebug() << "HotKey!" << (control ? "Ctrl +": "")
<< (alt ? "Alt +": "")
<< (shift ? "Shift +":"")
<< (win ? "Win +":"") << QString::number(HIWORD(msg.lParam),16);
// TODO Notify MainWindow of the event
emit hot_key_event(msg.lParam);
}
else if(msg.message == WM_END_THREAD)
{
// exit
break;
}
}
// Clean up Hotkey
::UnregisterHotKey(NULL, id);
::GlobalDeleteAtom(id);
}
Usage in your GUI
// Start HotKey Thread!
m_hot_key_thread = new HotKeyThread(this);
QObject::connect(m_hot_key_thread, SIGNAL(hot_key_event(int)),
this, SLOT(handle_hot_key_event(int)), Qt::QueuedConnection);
m_hot_key_thread->start();
and when your program is closing use
m_hot_key_thread->stop();
Hope that helps.

C++ Running 2 processes at a time

A C++ question on running 2 processes at a time.
I have a client-server model kind of C++ code. My server will fork for every connection from the client. This is a system that also has a reminder module. This reminder module will need to send an email when, let's say, it counts down from 1000 to 0: when it reaches 0, it will perform its code.
But my server is already running in a while(1) loop. How do I invoke this reminder thing together while not affecting the server listening to connections?
Thanks for all help and suggestions.
You are looking for what is commonly know as threads.
Here is an example using Boost.Thread:
#include <iostream>
#include <boost/thread.hpp>
#include <boost/date_time.hpp>
bool worker_running = true;
void workerFunc() {
while (worker_running) {
boost::posix_time::seconds workTime(3);
// do something
boost::this_thread::sleep(workTime);
}
}
int main(int argc, char* argv[])
{
//before your while loop:
boost::thread workerThread(workerFunc);
//while loop here
worker_running = false;
workerThread.join();
return 0;
}