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

151
26 июня 2022, 08:10

Мне нужно знать, какая установлена раскладка клавиатуры пользователя в данный момент (использую в 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;
}

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

READ ALSO
Как получить вектор с нужным capacity?

Как получить вектор с нужным capacity?

Может ли новосозданный вектор после вызова метода reserve(x) иметь capacity больше, чем x? Если да, то правда ли, что чтобы получить вектор с нужным...

186
.exe вызвал срабатывание точки останова

.exe вызвал срабатывание точки останова

Не понимаю, в чем ошибка, ведь значение вычисляется правильно, иногда даже выводиться в консоль, но с вводом первого числа ,как 1, а второго...

230
Функция завершается не дойдя до return с++

Функция завершается не дойдя до return с++

вот код программы, из книги олимпиадное программированиеОн должен решать задачу о количестве способов разместить n ферзей на доске n*n чтобы...

173