Глобальное событие смены раскладки клавиатуры

Мне нужно знать, какая установлена раскладка клавиатуры пользователя в данный момент (использую в CALLBACK функции)

Нашел решение:

HKL kbLayout = GetKeyboardLayout(GetWindowThreadProcessId(GetForegroundWindow(), NULL));

Это работает, но мне кажется, что не очень хорошо при каждом вызове функции запрашивать у системы текущую раскладку.


Нашел ещё одно решение, но не совсем понимаю, как его использовать.

В документации написано:

Чтобы установить этот приемник, получите объект ITfSource из объекта ITfInputProcessorProfiles, вызвав ITfInputProcessorProfiles::QueryInterface с параметром IID_ITfSource. Затем вызовите ITfSource::AdviseSink с IID_ITfLanguageProfileNotifySink.

HRESULT hr;
ITfInputProcessorProfiles *pProfiles;
ITfSource *pSource;

hr = CoCreateInstance(CLSID_TF_InputProcessorProfiles,
                      NULL,
                      CLSCTX_INPROC_SERVER,
                      IID_ITfInputProcessorProfiles,
                      (LPVOID*) &pProfiles);

if(!SUCCEEDED(hr)) return 1;

hr = pProfiles->QueryInterface(IID_ITfSource, (LPVOID*) &pSource);
if(!SUCCEEDED(hr)) return 1;

// Some code

pSource->Release();
pProfiles->Release();

Вроде удалось получить объект ITfSource, но дальше непонятно, как вызвать AdviseSink

HRESULT AdviseSink(
  REFIID   riid,
  IUnknown *punk,
  DWORD    *pdwCookie
);

Я так понимаю - в качестве riid нужно передать IID_ITfLanguageProfileNotifySink, pdwCookie это указатель на переменную, в которую будет записан идентификатор, который позже используется в ITfSource::UnadviseSink.

Но что такое IUnknown *punk? В примерах кода в интернете туда обычно передают this.

То еcть мне нужно создать функцию (или класс?) и писать все это там?

А дальше нужно реализовать метод OnLanguageChanged. Буду очень благодарен, если покажете как это сделать.


И последний вопрос - мне нужно получать это событие глобально, даже если окно моего приложения не в фокусе. Надеюсь, что это возможно


UPDATE

Может мне нужно создать класс, наследоваться от ITfLanguageProfileNotifySink, реализовать методы OnLanguageChange и OnLanguageChanged, а в AdviseSink в качестве параметра punk передавать ссылку на объект этого класса?
Мысли вслух...


UPDATE 2

Спустя некоторое время, получилось реализовать интерфейс ITfLanguageProfileNotifySink (спасибо @user7860670)

Реализация:

header

#ifndef LANGAUGECHANGEHANDLER_H
#define LANGAUGECHANGEHANDLER_H

#include <msctf.h>

class LangaugeChangeHandler : ITfLanguageProfileNotifySink {
private:
    ULONG cRef;
    LANGID id;

public:
    LangaugeChangeHandler();
    virtual ~LangaugeChangeHandler();

    HRESULT STDMETHODCALLTYPE OnLanguageChange(LANGID id, WINBOOL *pfAccept) override;
    HRESULT STDMETHODCALLTYPE OnLanguageChanged() override;

    HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) override;
    ULONG STDMETHODCALLTYPE AddRef(void) override;
    ULONG STDMETHODCALLTYPE Release(void) override;

};

#endif // LANGAUGECHANGEHANDLER_H

cpp

#include "langauge_change_handler.h"
#include <iostream>

LangaugeChangeHandler::LangaugeChangeHandler() {
    cRef = 0;
}

LangaugeChangeHandler::~LangaugeChangeHandler() {
}

HRESULT STDMETHODCALLTYPE LangaugeChangeHandler::OnLanguageChange(LANGID id, WINBOOL *pfAccept)  {
    (void) pfAccept;
    this->id = id;
    return S_OK;
}

HRESULT STDMETHODCALLTYPE LangaugeChangeHandler::OnLanguageChanged() {
    std::cout << id << std::endl;
    return S_OK;
}

HRESULT STDMETHODCALLTYPE LangaugeChangeHandler::QueryInterface(REFIID riid, void** ppvObject) {
    if (!ppvObject)
        return E_INVALIDARG;

    if(riid == IID_IUnknown || riid == IID_ITfLanguageProfileNotifySink) {
        *ppvObject = this;
        AddRef();
        return S_OK;
    } else
        return E_NOINTERFACE;
}

ULONG STDMETHODCALLTYPE LangaugeChangeHandler::AddRef(void) {
    InterlockedIncrement(&cRef);
    return cRef;
}

ULONG STDMETHODCALLTYPE LangaugeChangeHandler::Release(void) {
    ULONG ulRefCount = InterlockedDecrement(&cRef);
    if (cRef == 0) {
        delete this;
        return 0;
    } else
        return ulRefCount;
}

Но я всё ещё не понимаю, как заставить это работать...


Ответы (0 шт):