Qt :: Key列挙は、QKeyEventイベントの15種類のマルチメディアコントロールキーを定義します(記事の最後の表を参照)。 これらはすべて、イベントフィルタ(installEventFilter)で使用して、マルチメディアキーボードのキーストロークを処理できます(オーディオデバイスと再生を制御できます)。
逆の問題は記事で検討されています-Windows、Linux、およびMacOSXで対応するキーを押すことをエミュレートしてシステムにマルチメディア制御コマンドを送信します(オペレーティングシステムはソリューションの検索に費やされた時間でソートされます)。 この記事に記載されている資料は、システムメッセージ処理サイクルに送信されるクロスプラットフォームイベントの問題をさらに調査するための出発点となります。
ソースコードの説明に直接進む前に、マルチメディアキーのエミュレーションを一般的に適用できる場所を見てみましょう。たとえば、次のとおりです。
- オーディオ再生制御ウィジェットの作成。
- アプリケーションのテスト時のユーザー入力エミュレーション。
- オーディオシステムのリモートコントロール用のアプリケーションを作成します。 この場合、コンピューター上のアプリケーションはサーバーとして機能し、クライアントはスマートフォンです。 このようなバンドルを使用すると、ソファから立ち上がることなくオーディオ/ビデオを制御したり、着信コールが到着したときに自動的に再生を一時停止したりできます。
- ネットワークを介して2つ以上のコンピューターでキーボードとマウスを「共有」するアプリケーションを作成します(提出されたコードをすべてのキーに完了した後)。
- 「スマートホーム」システムの作成、新しいヒューマンマシンインターフェイス(音声コマンド制御など)。
QEventでは、アプリケーションの「内部」にある特定のオブジェクトにのみメッセージを送信できるため、標準のQtツールを使用してキーストロークをエミュレートすることはできません。 これを行うには、Apiシステムコール(Windowsの場合)または対応するライブラリ(LinuxではX Window System、Mac OS Xでは多くのフレームワーク)を使用します。
説明の便宜上、送信メッセージの実装全体をsendKeyEventToSystem(Qt :: Key qtKey)関数に配置します 。この関数はQt :: Key列挙からキーコードを受け取ります。 この関数は、たとえば次のようにスロットから呼び出されます。
void playPauseToogle() { // postKeyEventToSystem(Qt::Key_MediaTogglePlayPause); }
プラットフォーム依存コードを#ifdef OS_TYPEディレクティブと#endifディレクティブで分離します( Objective-Cコードの別の部分を別のmacx.mmファイルに取り出しますが、これについては後で詳しく説明します)。
Windowsのキーボードエミュレーション
このオペレーティングシステムでは、 SendInput関数がメッセージを送信します。 コードを使用してメッセージを送信できます。コードの完全なリストは、MSDN Virtual-Key Codesページに表示されます。
この関数を使用するには、<Windows.h>ヘッダーファイルを含める必要があります。
#ifdef Q_OS_WIN32 #define WINVER 0x0500 #include <Windows.h> #endif
インターネットでこの関数を使用する例は数多くあり、そのアプリケーションは問題を引き起こさないはずなので、すぐにコードを提供します(Windowsの部分)。
sendKeyEventToSystem(Qt::Key qtKey) { // . qtKey - #ifdef Q_OS_WIN32 INPUT ip; // ip.type = INPUT_KEYBOARD; ip.ki.wScan = 0; ip.ki.time = 0; ip.ki.dwExtraInfo = 0; // switch (qtKey) { case Qt::Key_MediaPrevious: ip.ki.wVk = VK_MEDIA_PREV_TRACK; // break; case Qt::Key_MediaTogglePlayPause: ip.ki.wVk = VK_MEDIA_PLAY_PAUSE; // break; case Qt::Key_MediaNext: ip.ki.wVk = VK_MEDIA_NEXT_TRACK; // break; default: return; break; } // ip.ki.dwFlags = 0; SendInput(1, &ip, sizeof(INPUT)); // ip.ki.dwFlags = KEYEVENTF_KEYUP; SendInput(1, &ip, sizeof(INPUT)); #endif }
以下の例では、3つのキーのみが使用されます。 記事の最後に、コードマッチングの表があります。
Linuxでのキーボードエミュレーション
Linuxでキーをエミュレートするための最も簡単な方法は、libXtst開発者ライブラリ( X11 Record拡張ライブラリ )を使用することです。
パッケージから取得するには、次のコマンドを実行する必要があります。
また、プロジェクトファイルにライブラリを含める必要があります。sudo apt-get install libxtst-dev
unix:!macx:LIBS += -lXtst -lX11
ファイルの先頭で、必要なヘッダーファイルを接続し、マルチメディアキーのコードに対応する多数の定数を定義します(実際には、X11 / keysymdef.hファイルにはマルチメディアキーのコードはありません)。
#ifdef Q_OS_LINUX #include <X11/Xlib.h> #include <X11/extensions/XTest.h> #define XF86AudioLowerVolume 0x1008ff11 #define XF86AudioMute 0x1008ff12 #define XF86AudioRaiseVolume 0x1008ff13 #define XF86AudioPlay 0x1008ff14 #define XF86AudioStop 0x1008ff15 #define XF86AudioPrev 0x1008ff16 #define XF86AudioNext 0x1008ff17 #define XF86AudioPause 0x1008ff31 #endif
Linuxエミュレーションコード:
#ifdef Q_OS_LINUX unsigned int key; unsigned int keycode; switch (qtKey) { case Qt::Key_MediaPrevious: key = XF86AudioPrev; break; case Qt::Key_MediaTogglePlayPause: key = XF86AudioPlay; break; case Qt::Key_MediaNext: key = XF86AudioNext; break; default: return; break; } // X Display *display; display = XOpenDisplay(NULL); // keycode = XKeysymToKeycode(display, key); // XTestFakeKeyEvent(display, keycode, 1, 0); // XTestFakeKeyEvent(display, keycode, 0, 0); // X XFlush(display); // X XCloseDisplay(display); #endif
Mac OS Xでのキーボードエミュレーション
MacOS Xのソリューションを見つけようとしても、GoogleがHacoのQtアプリケーションをMac OS Xに統合する(CocoaとObjective-C ++を使用) 。 すでにObjective-Cアプリケーションで使用するC ++コードを分離する方法を説明した英語の記事を見つけました。 Objective-Cコードを分離するために、正反対が必要でした(これは必要な機能を実行しましたが、同時にコンパイラーは誓いました)。 すべてが非常にシンプルであることが判明しました。
1. macx.mmファイルを作成し、Objective-Cコードをその中に配置しました(プロジェクトファイルに行が自動的に表示されました
OBJECTIVE_SOURCES += macx.mm
2. macx.hファイルを作成し、その中にmacx.mmから関数宣言を配置しました(#include“ macx.h”をmacx.mmに追加)。
3.プロジェクトファイルに、特に次の必要なフレームワークの接続を追加しました。
macx:LIBS += -framework ApplicationServices -framework IOKit
4. Mac OS Xのマクロ条件付きコンパイル内に、必要なヘッダーとmacx.hが追加されました。
5.既におなじみのスイッチケース構造に、新しく作成した関数への呼び出しを挿入しました。
したがって、ファイルの冒頭で、Mac OS Xの設計を取得しました。
#ifdef Q_OS_MAC #include <ApplicationServices/ApplicationServices.h> // UInt8 #include <IOKit/hidsystem/ev_keymap.h> // #include "mac.h" // Objective-C #endif
次のコードがsendKeyEventToSystem関数に追加されます。
#ifdef Q_OS_MAC switch (qtKey) { case Qt::Key_MediaPrevious: HIDPostAuxKey( NX_KEYTYPE_PREVIOUS ); break; case Qt::Key_MediaTogglePlayPause: HIDPostAuxKey( NX_KEYTYPE_PLAY ); break; case Qt::Key_MediaNext: HIDPostAuxKey( NX_KEYTYPE_NEXT ); break; default: return; break; } #endif
mac.mmファイルの内容:
#import <Cocoa/Cocoa.h> #import <IOKit/hidsystem/IOHIDLib.h> #import <IOKit/hidsystem/ev_keymap.h> #include "macx.h" static io_connect_t get_event_driver(void) { static mach_port_t sEventDrvrRef = 0; mach_port_t masterPort, service, iter; kern_return_t kr; if (!sEventDrvrRef) { // Get master device port kr = IOMasterPort( bootstrap_port, &masterPort ); check( KERN_SUCCESS == kr); kr = IOServiceGetMatchingServices( masterPort, IOServiceMatching( kIOHIDSystemClass ), &iter ); check( KERN_SUCCESS == kr); service = IOIteratorNext( iter ); check( service ); kr = IOServiceOpen( service, mach_task_self(), kIOHIDParamConnectType, &sEventDrvrRef ); check( KERN_SUCCESS == kr ); IOObjectRelease( service ); IOObjectRelease( iter ); } return sEventDrvrRef; } void HIDPostAuxKey(const UInt8 auxKeyCode ) { NXEventData event; kern_return_t kr; IOGPoint loc = { 0, 0 }; // UInt32 evtInfo = auxKeyCode << 16 | NX_KEYDOWN << 8; bzero(&event, sizeof(NXEventData)); event.compound.subType = NX_SUBTYPE_AUX_CONTROL_BUTTONS; event.compound.misc.L[0] = evtInfo; kr = IOHIDPostEvent( get_event_driver(), NX_SYSDEFINED, loc, &event, kNXEventDataVersion, 0, FALSE ); check( KERN_SUCCESS == kr ); // evtInfo = auxKeyCode << 16 | NX_KEYUP << 8; bzero(&event, sizeof(NXEventData)); event.compound.subType = NX_SUBTYPE_AUX_CONTROL_BUTTONS; event.compound.misc.L[0] = evtInfo; kr = IOHIDPostEvent( get_event_driver(), NX_SYSDEFINED, loc, &event, kNXEventDataVersion, 0, FALSE ); check( KERN_SUCCESS == kr ); }
結論:
メッセージ(キーボード、マウス、その他のイベントを含む)を送信できる、オープンにアクセス可能なクロスプラットフォームライブラリがこれまで存在しなかったことは、私にとって少し奇妙でした。 いずれにせよ、そのようなライブラリは見つかりませんでした。 提示されたコードは完全にはほど遠いです(新しいキーを追加するとスイッチケースシーケンスがどのように成長するか想像できます)。 それでも、これは、クロスプラットフォームアプリケーションの作成に関する知識ベースの一般的な貯金箱への小さな貢献としましょう。
記事の作業中に、VirtualBox がマルチメディアキーのキーストロークをインターセプトすることに気付きました(Ubuntuでテストされました-すべてハードウェアで動作しました)。 WMWareにはこの欠点はありません(Mac OS Xでテスト済み)。
付録:マルチメディアキーとその定義のリスト(#defineを使用)。
Qt ::キー | 窓 | Linux | Mac OS X |
---|---|---|---|
Qt :: Key_VolumeDown | VK_VOLUME_DOWN | XF86AudioLowerVolume | NX_KEYTYPE_SOUND_DOWN |
Qt :: Key_VolumeMute | VK_VOLUME_MUTE | XF86AudioMute | NX_KEYTYPE_MUTE |
Qt :: Key_VolumeUp | VK_VOLUME_UP | XF86AudioRaiseVolume | NX_KEYTYPE_SOUND_UP |
Qt :: Key_BassBoost | |||
Qt :: Key_BassUp | |||
Qt :: Key_BassDown | |||
Qt :: Key_TrebleUp | |||
Qt :: Key_TrebleDown | |||
Qt :: Key_MediaPlay | VK_MEDIA_PLAY_PAUSE | XF86AudioPlay | NX_KEYTYPE_PLAY |
Qt :: Key_MediaStop | VK_MEDIA_STOP | XF86AudioStop | |
Qt :: Key_MediaPrevious | VK_MEDIA_PREV_TRACK | XF86AudioPrev | NX_KEYTYPE_PREVIOUS |
Qt :: Key_MediaNext | VK_MEDIA_NEXT_TRACK | XF86AudioNext | NX_KEYTYPE_NEXT |
Qt :: Key_MediaRecord | |||
Qt :: Key_MediaPause | XF86AudioPause | ||
Qt :: Key_MediaTogglePlayPause | VK_MEDIA_PLAY_PAUSE | XF86AudioPlay | NX_KEYTYPE_PLAY |
関連リンク:
1.問題を解決するための既存のアプローチ: キーボード入力、sendkeys、send kestrokesなどをシミュレートするためのC ++(Qt)クロスプラットフォームライブラリ
2. MSDN WebサイトのSendInput関数の説明とキーボードコードのリスト 。
3. CおよびX11でのMediakey Pressのシミュレーション -この記事では、Linuxで「xev」ユーティリティ(Ubuntuでは「sudo apt-get install x11-utils」)を使用してキーコードを検索する方法と、archlinuxの記事を説明しています.org
4. Pythonプログラミング言語でのMacOS Xのマルチメディアキーのエミュレーション。