在UWP上使用GamePad ( JoyStick )和Http cookie共享給WebView的方式。
日前遇上要使用GamePad(JoyStick)遊戲手把的UWP開發問題,所以稍微研究了一下Windows.Gaming.Input的GamePad物件!
而這個GamePad物件有幾點要注意!
- 使用的是Xbox 360或是Xbox One的JoyStick為基礎,所以對於其他第三方的JoyStick會有相容性問題。
- GamePad的讀取是需要高即時性的,最好使用Dispatcher.TryRunAsync的時候搭配CoreDispatcherPriority.High。
- GamePad的讀取必須要在Window Focus的UWP app上。
稍微說一下關於JoyStick的問題,之前在Win32的Classic的APP開發上可以使用DirectInput(DirectX 8)全域的JoyStick的抓取在JoyStick的輸入事件。但是...從Direct X 9的版本開始MSFT就將DirectInput拔除換作XInput的API!至於DirectInput和XInput有何優劣就請自行Search一下啦~
開始進入正題,在UWP如何使用JoyStick ( Gamepad )的API,在一開始的時候reference Windows.Gaming.Input的namespace就可以使用GamePad的物件。Gamepad的物件有兩個事件GamepadAdded以及GamepadRemoved,分別就是當UWP的App偵測到有Gamepad插入(已經插入的狀態)和被拔除的狀態。
Gamepad.GamepadAdded += Gamepad_GamepadAdded;
Gamepad.GamepadRemoved += Gamepad_GamepadRemoved;
稍微要注意的是GamepadAdded是每次只要App launch的時候都需要抓取到目前UWP Client連接到的JoyStick數量!以下是Added和Removed的事件
private void Gamepad_GamepadAdded(object sender, Gamepad e)
{
System.Diagnostics.Debug.WriteLine("Add");
FirstGp = Gamepad.Gamepads.FirstOrDefault();
}
private void Gamepad_GamepadRemoved(object sender, Gamepad e)
{
System.Diagnostics.Debug.WriteLine("Remove");
}
然後要取的CurrentReading的操作並顯示在UI的話大致Code如下
<Page
x:Class="GamePadApp1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:GamePadApp1"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Page.Resources>
<x:Double x:Key="CircleSize">40</x:Double>
</Page.Resources>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Ellipse x:Name="RedCircle" Fill="Red" Width="{StaticResource CircleSize}" Height="{StaticResource CircleSize}">
<Ellipse.Transform3D>
<CompositeTransform3D x:Name="CircleTransform3D"/>
</Ellipse.Transform3D>
</Ellipse>
</Grid>
</Page>
先在XAML上面加入個Ellipse來表示Thumbstick(蘑菇頭)移動方向,並使用CompositerTransform3D來及時的顯示Transfrom。
private async void MainPage_Loaded(object sender, RoutedEventArgs e)
{
var baseScale = 100;
while(true)
{
await Dispatcher.TryRunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
var fgp = FirstGp.GetCurrentReading();
CircleTransform3D.TranslateX = fgp.LeftThumbstickX * baseScale;
CircleTransform3D.TranslateY = fgp.LeftThumbstickY * baseScale * -1;
});
await Task.Delay(TimeSpan.FromMilliseconds(5));
}
}
接者在MainPage_Loaded的事件中使用Loop的方式不斷在First的Gamepad上抓取CurrentReading的數值後把左邊的Thumbstick的移動assign給在XAML上的Ellispe的CompositTransform。而為什麼Y軸需要乘一個 -1的是因為在Y的部分是對應到XAML的Composite屬性是上下顛倒的。這樣就可以看到磨菇頭在XAML上的移動。
接者第二個問題則是因為要做到Hybird的APP(web browser和native app有些超做需要整合)所以當如果APP進行登入後webview也需要能夠顯示為登入的狀態。
先是Call Login的Async方法大致如下
public async Task<string> LoginAsync(string accountName, string accountPassword)
{
var accountObject = new JObject();
var uriString = System.IO.Path.Combine(baseUriString, LoginApi);
accountObject.Add(new JProperty("accountName", $"{accountName}"));
accountObject.Add(new JProperty("accountPassword", $"{accountPassword}"));
var content = JsonConvert.SerializeObject(accountObject);
var resultStr = string.Empty;
try
{
var filter = new HttpBaseProtocolFilter();
filter.AllowAutoRedirect = true;
filter.CacheControl.ReadBehavior = HttpCacheReadBehavior.Default;
filter.CacheControl.WriteBehavior = HttpCacheWriteBehavior.Default;
var cookieMgr = filter.CookieManager;
using (var client = new HttpClient(filter))
{
using (var response = await client.PostAsync(new Uri(uriString), new HttpStringContent(content, Windows.Storage.Streams.UnicodeEncoding.Utf8, mediaType)))
{
response.EnsureSuccessStatusCode();
var responseStr = await response.Content.ReadAsStringAsync();
resultStr = responseStr;
SetupCookie(resultStr, cookieMgr);
}
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
resultStr = ex.Message;
}
return resultStr;
}
先把account的Name以及Password做Json序列化,然後再使用HttpBaseProtocolFilter來設定給httpclient,然後以下是SetupCookie的寫法
private void SetupCookie(string rawJsonString, HttpCookieManager cookieManager)
{
var accountObj = JsonConvert.DeserializeObject<UserAccountModel>(rawJsonString);
var cookie = new HttpCookie("AccessKey", "Domain.com", "/");
cookie.HttpOnly = false;
cookie.Secure = false;
cookie.Value = accountObj.accessKey;
cookieManager.SetCookie(cookie, false);
}
這邊情境是把Server吐出來的Json String轉換成物件後把accessKey塞進cookie的值,接者在把Cookie設定在HttpCookieManager內。
UWP所提供的Cookie container可以在整個App的Life cycle都可以把Cookie變成共享的方式,當WebView進行Navigate的時候依然可以在APP內使用Cookie來帶相關資訊給Server端。