スポンサーサイト

--.--.--.--.--:--
上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

Windows8.1でJoystickの状態を取得する 2

2013.09.12.Thu.01:19
久しぶりに余裕ができたので、すごい広島第17回に行ってきました。

(あれ、この書き出し、前回もやったぞ…)

さて、今回もJoystickの状態を取得する方法の調査です。
前回はボタンの現在の押下状態などをバイト列から推定しましたが、ボタンの数などが分かっていないと、いろいろなコントローラに対応できません。できれば、何もわからない状態からボタンの数などを取得したいので、その方法について調べました。

□ レポートディスクリプタを取得する


デバイスのボタンの数などを取得する方法ですが、HIDデバイスではレポートディスクリプタによってデバイスが持っている機能を表しているそうなので、このレポートディスクリプタを取得する方法を探してみます。

まず、HID APIを眺めてみます。
HidDeviceクラスを見てみると、GetBooleanControlDescriptions関数とGetNumericControlDescriptions関数があります。名前から考えるとこのあたりが怪しいです。


□ GetNumericControlDescriptionsで方向キーの対応を確認する


前回の調査で、方向キーはX軸とY軸がそれぞれ0~255であらわされていることが確認できました。これはNumericControlだと思われるので、GetNumericControlDescriptionsで取得できるはずです。
GetNumericControlDescriptions関数の引数を見てみると、

GetNumericControlDescriptions(
HidReportType reportType,
ushort usagePage,
ushort usageId
)


となっています。

reportTypeはInputReportで間違いないでしょう。
問題はusagePageとusageIdです。JoystickのUsagePage(0x01),UsageId(0x04)を指定してみましたが、nullが返ってきます。HID Usage Tablesを確認してみると、"Table 6:Generic Desktop Page"の表の中にX,Y,Zの文字があります。あやしいです。


var numericControl = device.GetNumericControlDescriptions(
HidReportType.InputReport,
0x01,
0x30);


こんな感じで取得すると、numericControl.LogicalMaximumが255とか、それらしい値が取得できます。

ただ、あくまでUsageIdを指定して取得することしかできないため、どの軸に対応しているかは取得してみてnullじゃなかったら…みたいな処理になると思われます。つまり、ある程度、対象デバイスについて知っておく必要があります。
まぁ、デバイスの列挙時にUsagePageとUsageIdでJoystickに制限していますので、大して問題ないでしょう。

□ GetBooleanControlDescriptionsでボタンが何個ついているか確認する


ここにたどり着くのに少し時間がかかりました。
ボタンが何個ついているかは、GetBooleanControlDescriptions関数で調べられそうです。

関数の引数は先ほどと同様です。
問題はまたもusagePageとusageIdです。JoystickのUsageIdにはそれらしい値がありません。
先ほどのHID Usage Tablesをずーっと見ていくと、UsagePage(0x09)にButtonという項目があります。あやしいです。

UsageIdが0x01から順番にボタン番号となるようなので、10個ボタンのあるコントローラーなら、UsageIdが0x01~0x0AまでHidBooleanControlDescriptionが取得できるはずです。


□ まとめ


GetNumericControlDescriptions関数とGetBooleanControlDescriptions関数を使えば、コントローラーのボタン数などは推定できそうだということが分かりました。
次回は、コントローラーについているスティックとボタンの数を推定し、画面に表示できるよう実装します。
スポンサーサイト

Windows8.1でJoystick(GamePad)の状態を取得する

2013.08.15.Thu.01:00
久しぶりに余裕ができたので、すごい広島に行ってきました。


さて、Windows8.1からストアアプリでHIDがサポートされるようになりました。
http://msdn.microsoft.com/ja-jp/library/windows/apps/bg182882.aspx#one

これにより、ゲームパッドやジョイスティックはもちろん、HIDで通信するカスタムデバイスとのデータのやり取りも可能になりました。
ただし、HIDのうち下記のようなマウスやキーボードなどシステムが使用するものについては、APIでブロックされ使用できないため、注意が必要です。
http://msdn.microsoft.com/ja-jp/library/windows/apps/bg182882.aspx#limitations_of_the_hid_api

•HID_USAGE_PAGE_UNDEFINED
•HID_USAGE_PAGE_GENERIC
•HID_USAGE_GENERIC_KEYBOARD
•HID_USAGE_GENERIC_KEYPAD
•HID_USAGE_GENERIC_SYSTEM_CTL
•HID_USAGE_PAGE_KEYBOARD
•HID_USAGE_PAGE_CONSUMER
•HID_USAGE_PAGE_DIGITIZER
•HID_USAGE_PAGE_SENSOR
•HID_USAGE_PAGE_BARCODE_SCANNER
•HID_USAGE_PAGE_WEIGHING_DEVICE
•HID_USAGE_PAGE_MAGNETIC_STRIPE_READER
•HID_USAGE_PAGE_TELEPHONY

今回は、安価で入手しやすいゲームパッドでAPIについてチェックしてみたいと思います。
なお、使用したゲームパッドはこれです。
http://buffalo.jp/products/catalog/supply/input/gamepad/wire/bsgp1001/index.html

□ ManifestのCapabilitiesに、使用するデバイスについて記載する


HIDデバイスなど、外部機器をストアアプリから使用する場合、Capabilitiesにどのデバイスを使用するか明記する必要があります。
今回使用するゲームパッドは、HIDのデバイスのUsage Pageが0x01、Usage IDが0x04のJoystickになりますので、Capabilitiesには下記のように記載します









今回は、使用するデバイスのベンダーやデバイスIDなどは指定しないため、としています。

□ PCに接続されているJoystickを検索する


HidDevice.GetDeviceSelectorを使用して、セレクタ文字列を生成します。
http://msdn.microsoft.com/en-us/library/windows/apps/windows.devices.humaninterfacedevice.hiddevice.getdeviceselector.aspx

引数が(UsagePage, UsageId)のものと、(UsagePage, UsageId, VenderId, ProductID)のものがありますが、今回は前述の通り、メーカーは指定しないので引数2つのほうを使用します。

その後、セレクタ文字列を引数にDeviceInformation.FindAllAsyncを実行し、PCに接続されているJoystickを検索します。

ushort usagePage = 0x01;
ushort usageId = 0x04;

// セレクタ文字列を生成する
string selector = HidDevice.GetDeviceSelector(usagePage, usageId);

// セレクタ文字列を使ってデバイスを列挙する
var devices = await DeviceInformation.FindAllAsync(selector);


□ InputReport受信時のハンドラをセットする


使用したいJoystickが見つかったら、HidDevice.FromIdAsyncを使って、HidDeviceを取得します。
このままでは、Joystickの入力状態が取得できないため、Joystickからの情報を受信した時のイベントハンドラを登録します。


// ターゲットのHIDをオープンする
HidDevice device = await HidDevice.FromIdAsync(deviceInformation.Id, FileAccessMode.Read);

if (device == null)
{
return;
}

// InputReport受信時のハンドラを登録する
device.InputReportReceived += device_InputReportReceived;


□ InputReportからJoystickの状態を調べる


受信時はargs.Report.DataにJoystickの情報が格納されています。
下記コードでは、1バイトずつ読み取ってデバッグ用に文字列をTextBlockに表示しています。


async void device_InputReportReceived(HidDevice sender, HidInputReportReceivedEventArgs args)
{
var data = args.Report.Data;
var dataReader = DataReader.FromBuffer(data);

StringBuilder sb = new StringBuilder();
for (int index = 0; index < data.Length; index++)
{
sb.Append(dataReader.ReadByte().ToString() + ":");
}
//Debug.WriteLine("data = " + sb.ToString());
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, new Windows.UI.Core.DispatchedHandler(() =>
{
textBlockLog.Text = sb.ToString();
}));
}


なにも押していない状態で出力される値は下記の通りです。
0:128:128:0:0:0:0:0:0:

ボタン1を押下した状態では
0:128:128:1:0:0:0:0:0:

ボタン2を押下した状態では
0:128:128:2:0:0:0:0:0:

ボタン3を押下した状態では
0:128:128:4:0:0:0:0:0:

もうお分かりですね。
4バイト目は押下されたボタンのビットフラグが立った値のようです。

もちろん、ボタン1と2を両方押すと
0:128:128:3:0:0:0:0:0:
になりました

ちなみに、ボタン9を押下すると
0:128:128:0:1:0:0:0:0:
になり、5バイト目のビットフラグが変わりました。

このあたりの、何ボタンのコントローラか等の情報は何かで取得できる気はしているのですが、まだ調べていません。

2,3バイト目の128が気になりますが、これは十字キーの値になります。
左を押すと
0:0:128:0:0:0:0:0:0:

右を押すと
0:255:128:0:0:0:0:0:0:
でしたので、アナログジョイスティックのついたコントローラでは0~255まで連続的に変化するものと思われます。

こんな感じでJoystickの状態が取得できますので、ストアアプリをジョイスティックを使ったアプリを作る場合はこんな感じになると思います。

IBuffeのインスタンスでToArrayを使うには

2012.12.27.Thu.16:20
MSDNでNFC関連の記事(例えばこれとか)を見ていると、ProximityMessageのインスタンスに対して、

message.Data.ToArray();

とか、普通に使われているけど、message.DataはIBuffer型でCapacityとLengthプロパティしか持っていない。
じゃぁ、どっからToArrayが出てくるかというと、拡張メソッドである。

WindowsRuntimeBufferExtensionsをインポートすると使えるようになるので、

using System.Runtime.InteropServices.WindowsRuntime;

を追加してやれば、message.Data.ToArray();と書いてもエラーが出なくなる。

[AdventCalender2012]NFCタグを使ってアプリを起動する(LaunchApp編)

2012.12.17.Mon.01:40
このエントリは Windows 8 Store apps Advent Calendar の17日目のエントリです。

前回、LaunchAppタイプのタグでアプリ起動ができず、CustomURIで逃げてみましたが、ようやく起動できるようになったので今回はNFCのLaunchAppをつかってアプリを起動します。

○用意するもの
・RC-S380 (NFCカードリーダー)
・NFCタグ (今回はFelica Liteを使用。Mifareでもたぶん可能)

1.LaunchApp:WriteTag
LaunchApp:WriteTagはProximityDevice.PublishBinaryMessageで引数に指定するメッセージタイプの一つです。
特定のフォーマットの文字列を、このLaunchAppとして書き込むとアプリを起動することが出来ます。

フォーマットは
 アプリ起動パラメータ[tab]プラットフォーム名[tab]アプリ名[tab]プラットフォーム名[tab]アプリ名・・・
となります。

今回はパラメータなし/Windows8のみとして、タグに書き込む文字列は
 " \tWindows\t"+[アプリ名]
とします。
このときパラメータに当たる部分に半角スペース等空白以外のものを入れないと私の環境では反応しませんでした。
サンプルコードでは「The string can be an empty string ("").」とか書いてあったから完全に騙されたじゃねーか…

アプリ名の部分はAPIを通して取得したものを使用しますので後述のコードを参考にしてください。

2.アプリの作成
今回は面倒なのでタグ書き込みアプリと、起動されるアプリは同じにします。
タグを書き込むコードはこんな感じです。

void publishLaunchApp()
{
var device = ProximityDevice.GetDefault();

if (device == null)
return;

var appName = Package.Current.Id.FamilyName + "!" + CoreApplication.Id;

var launchAppMessage = " \tWindows\t" + appName;

var writer = new DataWriter();
writer.UnicodeEncoding = UnicodeEncoding.Utf16LE;
writer.WriteString(launchAppMessage);
var launchAppPubId = device.PublishBinaryMessage("LaunchApp:WriteTag", writer.DetachBuffer());
}


あとは、ボタン押すなりなんなり適当なタイミングでpublishLaunchApp関数を呼んで、NFCタグをリーダーライターにタッチすれば変な音とともにタグの情報が書き込まれます。

3.アプリを起動する
いったんアプリを終了し、先ほど書き込んだNFCタグをNFCリーダーにタッチします。
すると、
taptolaunch.png

ってのが出てきますので、これをクリックするとアプリが起動します。
個人的にはタッチと同時にアプリが起動すると思ってたんですが、いったんユーザー操作をかますのはWindows8のポリシーですかね…。

4.まとめ

・CustomURIだとおなじURIschemeがあった時にアプリの選択画面が出るが、LaunchApp:WriteTagでタグ情報を書き込むとアプリが直接起動できる
・起動パラメータはなくてもスペース一個入れとけ
・トーストを操作しないといけないので、タッチで直起動とはならない

[AdventCalender2012]アプリと広告とSnapとAppBar

2012.12.05.Wed.01:14
このエントリは Windows 8 Store apps Advent Calendar の5日目のエントリです。

WindowsPhoneにはMS公式の広告コントロールがありましたが、Windowsストアアプリにも公式広告コントロールがあります。

Windows 8 Ads in Apps
http://advertising.microsoft.com/ads-in-apps

今回はこのコントロールをSnapped状態(以下スナップ状態)と、Full/Fill状態(以下フル状態)で画面下に表示するネタで行こうと思います。
広告サイズは、スナップ状態は292x60,フル状態は728x90を使います。
adSize.png


アプリに組み込む場合にはPubCenterに登録して、ApplicationIdとAdUnitIdを取得する必要がありますが、とりあえず今回のエントリ内容を試してみたい場合はテスト用のIDを使うと良いでしょう。
http://msdn.microsoft.com/en-us/library/hh506361(v=msads.10).aspx

○広告のスナップ対応
さて、スナップ状態とフル状態に広告を表示する方法は何通りか考えられます。
1.広告コントロールを一つ配置し、状態に応じてサイズを変更する
2.スナップ状態用とフル状態用の広告コントロールを配置する

簡単なのは1.の方法ですが、フル状態用の広告サイズをスナップ状態サイズに縮小すると広告の内容まで縮小されてしまいます。
screenshot_12022012_011923.png

screenshot_12022012_011914.png


2.の方法で実装するとそれぞれのサイズにあった広告が表示されます。
screenshot_12032012_003431.png


今回は2.の方法で実装しましょう。

○広告コントロールの配置
「基本ページ」に広告コントロール2つをそれぞれ下記のように配置します。
<AD:AdControl x:Name="adForFull"
      ApplicationId="d25517cb-12d4-4699-8bdc-52040c712cab"
      AdUnitId="10042998"
      Width="728"
      Height="90"
      VerticalAlignment="Bottom"
      Grid.Row="1" />
<AD:AdControl x:Name="adForSnapped"
      ApplicationId="d25517cb-12d4-4699-8bdc-52040c712cab"
      AdUnitId="10043074"
      Width="292"
      Height="60"
      VerticalAlignment="Bottom"
      Visibility="Collapsed"
      Grid.Row="1" />


次に、VSMでスナップ状態の時はAdForSnappedをVisibleに、AdForFullをCollapsedになるようにします。


これで、VisualStateに応じて広告コントロールが切り替わるようになりました。

○AppBarへの対応
次にAppBarを追加します。

AppBarを表示したとき広告コントロールが前面に表示されてしまいますが、これはバグ仕様です。
screenshot_12032012_005136.png


「広告コントロールはWebView使ってるから最前面にでちゃうの。ResumeとSuspendで対応してね!」
http://msdn.microsoft.com/en-us/library/jj157023(v=msads.10).aspx

仮にこのままの状態でストアに申請すると、もちろんリジェクトされます
なので、AppBarが表示されたときに広告コントロールをSuspendし、非表示になったらResumeするようにします。

private void AppBar_Opened(object sender, object e)
{
    adForFull.Suspend();
    adForSnapped.Suspend();
}
private void AppBar_Closed(object sender, object e)
{
    adForFull.Resume();
    adForSnapped.Resume();
}


これでAppBarが出たときには広告コントロールが一時停止し、AppBarが前面に表示されるようになります。
screenshot_12052012_012051.png

screenshot_12052012_012132.png


なお、ちゃんとSuspendするようにしても、タイミングによってはAppBarの上に広告コントロールが表示されます。さらにそのせいでリジェクトされることもありますが、テストメモに
AdControlのバグだからどうしようもありません
って書いて、審査通過することを祈るしかありません。

○まとめ
スナップ状態でも広告を表示したい場合は、広告コントロールを2つ配置して、それぞれに適切なサイズのAdUnitIdを設定する。
AppBarと被る位置に広告がある場合は、SuspendとResumeを使ってリジェクトされないように対応する。

それでは!
 | HOME | Next »
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。