Archive for 7月 9th, 2017

Surface Dialをごにょごにょする。

日曜日, 7月 9th, 2017

Windows 10 [1607]から「設定」「デバイス」アプリに登場したのが「ホイール」である。実態はアメリカでは2016/11に「Surface Studio」とともに登場した「Surface Dial」である。

OSでは「ホイール」と名乗っているにもかかわらず製品では「Surface Dial」でこれを使うAPIがRadialController-API群である。

ということで、この時点ですでに混乱しているが、気にせず自作アプリへの実装を考えてみる。

基本、自分の周りにはC/C++使いしかいないので話はC/C++で進めていく、ごにょごにょやっている最中にWindows Updateで解消した不思議な動きもあった。

Surface Dailの API情報は以下が詳しい、
https://docs.microsoft.com/ja-jp/windows/uwp/input-and-devices/windows-wheel-interactions

基本、C#であるが、UWPではC++での情報は一見なさそうだが、基本、サンプルプログラムを弄り回すことで自分のプログラムへの実装ができそうだ。

ということで、C++で書いてある、UWPアプリの TouchJWに実装してみた。
最近は下手にAPIのリファレンスを読みまくるよりも、MSさんが公開しているサンプルプログラムをいじりまくるのが吉ですが、一応基本はAPIなので、押さえておく、
https://docs.microsoft.com/en-us/uwp/api/Windows.UI.Input.RadialController

ということで、[1607]から[1703]への移行で使えるAPIが増えている。

わたしのメインはSurface Pro 初代なので、[1703]へUpgradeするとディスプレイドライバがごねるので、結局[1603]に戻すというつらい仕打ちを強いられた。
ま、しかし、何とかなるな?ということで[1703]で実装されたAPIを使わないと[1607]でも十分に行ける感じなので、[1607]+VS2015でやってみた。

UWPでは、そんなに、苦も無く実装できた。しかし、新しいユーザーインターフェイスなので、本当に使いやすい技を出すのにはもう少し頑張らないと。
UWPアプリで注意すべき点は、Windows 10 Mobileでは、RadialControllerは乗っかっていないので、APIの初期化時に落ちます。ので、デバイスファミリを調べて、Phoneデバイスであれば、RadialControllerのAPIは呼ばないようにする必要がある。

さて、
https://docs.microsoft.com/ja-jp/windows/uwp/input-and-devices/windows-wheel-interactions
の最下行に

Windowsの従来のデスクトップのサンプル

というのがある、これをクリックすると、GitHubに飛ばされるので、CPPのソースをいただいてくる。そして、既存のプログラムに実装できないかと思って、ごにょごにょする。

C#のソースは充実しているが、CPPのソースはワーニングが出たり、ほとんどやる気がない感じだなぁ…
とりあえず。コンパイルしてみて、[1607]でとりあえず動く、がデバッガで追ったりすると、変な動作があるので、調べると[1703]用のAPIが使われている。

これを取っ払い、コンパイルすると無事に動く。

さて、GitHubのソースを眺めて、実際にWin32のフォームアプリに乗っけてみる、
基本的に、GitHubの DeviceListener.cpp / DeviceListener.h こいつに主要なAPIコールの実装がされている。本来ならコツコツ組まないといけないのだかが、面倒くさいので、
DeviceListener.cpp / DeviceListener.hをそのまま改変して自分のWin32のフォームアプリに乗っけてみることにする。

この辺の解析には、ここのサイトが参考になった。
http://blog.tmyt.jp/entry/2016/11/17/173447

基本的には一瞬で乗っけられる。これからガンガン作っていけそうだと思うのであるが、

躓いたのが、上記サイトでも書いてある。「RadialControllerConfiguration::SetDefaultMenuItems」だ。
これは、RadialControllerはデフォルトボタンというのを持っていて、数種類のデフォルトボタンを定義できる。設定するには最初に書いた、「設定」「デバイス」アプリに登場したのが「ホイール」だ。

これには、「拡大」「スクロール」「アンドゥ」などのコマンドが割り当てられている。ちなみに、対応していないWindowsフォームアプリでSurface Dialを長押しして、これらのボタンを実行すると次の現象が発生する。

「拡大」の場合 WM_MOUSEWHELLがキューに投げられる。
「スクロール」の場合、「PgUp/PgDn」キーイベントがキューに投げられる。
「アンドゥ」の場合、「アンドゥ/リドゥ」のキーイベントが投げられる。

ということで、この動きはわかったのである、「RadialControllerConfiguration::SetDefaultMenuItems」というのはこのデフォルトボタンを自分のアプリに応じて設定するもんだ。

ところが、GitHubのCPPのソースにはこの辺の記述がない。仕方がないので、ヘッダファイルを読んだりしたのですが、SetDefaultMenuItemsの呼び方がわからない、
CPPのソースはGetActivationFactoryあたりで、ヘッダの文字列から、SetDefaultMenuItemsのポインタを引っ張ってくる感じだったのですが、どうやらこれをまちがっている感じこれだけで、1か月以上かかってしまった。C#でDLLを書いてそれをWin32から呼ぶかと?C#のソースを眺めているとSetDefaultMenuItemsのポインタを引っ張ってくる方法がわかった。

	//----------------   これを追加 6/16
	RETURN_IF_FAILED(Windows::Foundation::GetActivationFactory(
		HStringReference(RuntimeClass_Windows_UI_Input_RadialControllerConfiguration).Get(),
		&_controllerConfigInterop));
	//----------------   ここまで

	RETURN_IF_FAILED(_controllerInterop->CreateForWindow(hwnd, IID_PPV_ARGS(&_controller)));

	//----------------   これを追加 6/16
	RETURN_IF_FAILED(_controllerConfigInterop->GetForWindow(hwnd, IID_PPV_ARGS(&_controllerConfig)));
	//----------------   ここまで

	//	StoreAppの場合
	//Platform::Collections::Vector<RadialControllerSystemMenuItemKind> ^defButtons = ref new Platform::Collections::Vector<RadialControllerSystemMenuItemKind>;
	//defButtons->Append(RadialControllerSystemMenuItemKind::Volume);
	//	defButtons->Append(RadialControllerSystemMenuItemKind::Zoom);

	//	c#の場合
	//	radialControllerConfig = radialControllerConfigInterop.GetForWindow(this.Handle, ref guid);
	//	radialControllerConfig.SetDefaultMenuItems(new[] { RadialControllerSystemMenuItemKind.Volume, RadialControllerSystemMenuItemKind.Scroll });
	//	radialControllerConfig.TrySelectDefaultMenuItem(RadialControllerSystemMenuItemKind.Scroll);


	_controllerConfig->SetDefaultMenuItems(NULL);//	NULLを入れると消してくれる。

ということで、SetDefaultMenuItemsのポインタが取れたのはいいが、Win32環境で IVectorの扱いがナゾであちこちググったが、だめであった。

これは参考にしたサイト.http://blog.tmyt.jp/entry/2016/11/17/173447 にも書いてあるが,IVectorを使うにはWin32では、IDLファイルを作成、定義を書いて、MIDLコンパイラで処理

生成されたヘッダをインクルードしてコンパイルしなさいと、しかし、VS2015とVS2017では、どうもIDLファイルの記述が、どうも違うみたいである、この辺が謎になって結局、引数を設定することはできなかった。誰かこの辺を教えてください。…

SetDefaultMenuItemsの引数であるが、とりあえず。NULLを突っ込むと消えてくれました。[1703]だと、ちなみに[1607]だと、落ちました。(^^;…

Surface Dialのプログラミングの一つの情報になれば(^^;…

とにかく、Win32でデフォルトボタンを簡単に定義で来たら…と思うが

 

こんな、記事が(^^;..英語じゃ
https://blogs.windows.com/buildingapps/2017/07/06/calling-winrt-components-win32-process-via-desktop-bridge/#1x33gx2CgdwUQ32b.97