Surface ペン ( Microsoft Store で購入可能)。
概要
ペン入力用に Windows アプリを最適化して、標準 のポインター デバイス 機能とユーザーに最適な Windows Ink エクスペリエンスの両方を提供します。
注
このトピックでは、Windows Ink プラットフォームについて説明します。 ポインター入力の一般的な処理 (マウス、タッチ、タッチパッドと同様) については、「 ポインター入力の処理」を参照してください。
Windows アプリでのインクの使用
Windows ペンとインクを使用して、より魅力的なエンタープライズ アプリを構築する
Windows Ink プラットフォームは、ペン デバイスと共に、デジタル手書きのメモ、描画、注釈を作成する自然な方法を提供します。 このプラットフォームでは、デジタイザー入力のインク データとしてのキャプチャ、インク データの生成、インク データの管理、出力デバイスでのインク ストロークとしてのインク データのレンダリング、手書き認識によるインクからテキストへの変換がサポートされています。
ユーザーが書き込みまたは描画するときにペンの基本的な位置と動きをキャプチャするだけでなく、アプリはストローク全体で使用されるさまざまな量の圧力を追跡して収集することもできます。 この情報は、ペン先の図形、サイズ、回転、インクの色、目的 (プレーン インク、消去、強調表示、選択) の設定と共に、ペン、鉛筆、またはブラシを使用した紙の書き込みや描画によく似たユーザー エクスペリエンスを提供できます。
注
アプリでは、タッチ デジタイザーやマウス デバイスなど、他のポインター ベースのデバイスからのインク入力をサポートすることもできます。
インク プラットフォームは非常に柔軟です。 要件に応じて、さまざまなレベルの機能をサポートするように設計されています。
Windows Ink UX ガイドラインについては、「インキング コントロール」を参照してください。
Windows Ink プラットフォームのコンポーネント
コンポーネント | 説明 |
---|---|
InkCanvas | 既定では、ペンからのすべての入力をインク ストロークまたは消去ストロークとして受け取って表示する XAML UI プラットフォーム コントロール。 InkCanvas の使用方法の詳細については、「 Windows Ink ストロークをテキストとして認識 し、Windows Ink ストローク データを保存して取得する」を参照してください。 |
InkPresenter | 分離コード オブジェクトは、InkCanvas コントロールと共にインスタンス化され、InkCanvas.InkPresenter プロパティによって公開されます。 このオブジェクトは、 InkCanvas によって公開されるすべての既定の手描き入力機能と、追加のカスタマイズとパーソナル化のための包括的な API セットを提供します。 InkPresenter の使用方法の詳細については、「 Windows Ink ストロークをテキストとして認識 し、Windows Ink ストローク データを保存して取得する」を参照してください。 |
InkToolbar | 関連付けられた InkCanvas のインク関連機能をアクティブ化する、カスタマイズ可能で拡張可能なボタンのコレクションを含む XAML UI プラットフォーム コントロール。 InkToolbar の使用方法の詳細については、「 Windows アプリの手描き入力アプリに InkToolbar を追加する」を参照してください。 |
IInkD2DRenderer | 既定の InkCanvas コントロールではなく、ユニバーサル Windows アプリの指定された Direct2D デバイス コンテキストにインク ストロークをレンダリングできるようにします。 これにより、手描き入力エクスペリエンスを完全にカスタマイズできます。 詳細については、 複合インクのサンプルを参照してください。 |
InkCanvas を使用した基本的な手描き入力
基本的な手描き入力機能を追加するには、アプリの適切なページに InkCanvas UWP プラットフォーム コントロールを配置するだけです。
既定では、 InkCanvas は ペンからのインク入力のみをサポートします。 入力は、色と太さ (太さが 2 ピクセルの黒いボールペン) の既定の設定を使用してインク ストロークとしてレンダリングされるか、ストローク消しゴムとして扱われます (入力が消しゴムの先端または消去ボタンで変更されたペンヒントの場合)。
注
消しゴムの先端またはボタンが存在しない場合は、ペン先からの入力を消去ストロークとして処理するように InkCanvas を構成できます。
この例では、 InkCanvas によって 背景画像がオーバーレイされます。
注
InkCanvas には、StackPanel や Grid コントロールなどの子要素のサイズを自動的に設定する要素の子でない限り、既定の Height プロパティと Width プロパティは 0 です。
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel x:Name="HeaderPanel" Orientation="Horizontal" Grid.Row="0">
<TextBlock x:Name="Header"
Text="Basic ink sample"
Style="{ThemeResource HeaderTextBlockStyle}"
Margin="10,0,0,0" />
</StackPanel>
<Grid Grid.Row="1">
<Image Source="Assets\StoreLogo.png" />
<InkCanvas x:Name="inkCanvas" />
</Grid>
</Grid>
この一連の画像は、この InkCanvas コントロールによってペン入力がどのようにレンダリングされるかを示しています。
![]() |
![]() |
![]() |
---|---|---|
背景画像付きの空白の InkCanvas。 | InkCanvas にインクストロークが含まれています。 | InkCanvas 1つのストロークが消去されます(部分ではなく、ストローク全体がどのように消去されるかに注目してください)。 |
InkCanvas コントロールでサポートされる手描き入力機能は、InkPresenterと呼ばれるコードビハインド オブジェクトによって提供されます。
基本的な手描き入力では、InkPresenterについて心配する必要はありません。 ただし、 InkCanvas で手描き入力動作をカスタマイズして構成するには、対応する InkPresenter オブジェクトにアクセスする必要があります。
InkPresenter を使用した基本的なカスタマイズ
InkPresenter オブジェクトは、各 InkCanvas コントロールでインスタンス化されます。
注
InkPresenter を直接インスタンス化することはできません。 代わりに、InkCanvas の InkPresenter プロパティを介してアクセスします。
InkPresenter は、対応する InkCanvas コントロールのすべての既定の手描き入力動作を提供すると共に、ストロークのカスタマイズを追加し、ペン入力 (標準と変更) をきめ細かく管理するための包括的な API セットを提供します。 これには、ストローク プロパティ、サポートされている入力デバイスの種類、および入力がオブジェクトによって処理されるか、処理のためにアプリに渡されるかが含まれます。
注
標準のインク入力 (ペン先または消しゴムの先端/ボタンのいずれか) は、ペン バレル ボタン、マウスの右ボタン、または同様のメカニズムなど、2 つ目のハードウェア アフォーダンスでは変更されません。
既定では、インクはペン入力でのみサポートされています。 ここでは、ペンとマウスの両方からの入力データをインク ストロークとして解釈するように InkPresenter を構成します。 また、 InkCanvas へのストロークのレンダリングに使用される初期インク ストローク属性も設定します。
マウスとタッチの手描き入力を有効にするには、InkPresenter の InputDeviceTypes プロパティを、必要な CoreInputDeviceTypes 値の組み合わせに設定します。
public MainPage()
{
this.InitializeComponent();
// Set supported inking device types.
inkCanvas.InkPresenter.InputDeviceTypes =
Windows.UI.Core.CoreInputDeviceTypes.Mouse |
Windows.UI.Core.CoreInputDeviceTypes.Pen;
// Set initial ink stroke attributes.
InkDrawingAttributes drawingAttributes = new InkDrawingAttributes();
drawingAttributes.Color = Windows.UI.Colors.Black;
drawingAttributes.IgnorePressure = false;
drawingAttributes.FitToCurve = true;
inkCanvas.InkPresenter.UpdateDefaultDrawingAttributes(drawingAttributes);
}
インク ストローク属性は、ユーザー設定またはアプリの要件に合わせて動的に設定できます。
ここでは、ユーザーがインクの色の一覧から選択できるようにします。
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel x:Name="HeaderPanel" Orientation="Horizontal" Grid.Row="0">
<TextBlock x:Name="Header"
Text="Basic ink customization sample"
VerticalAlignment="Center"
Style="{ThemeResource HeaderTextBlockStyle}"
Margin="10,0,0,0" />
<TextBlock Text="Color:"
Style="{StaticResource SubheaderTextBlockStyle}"
VerticalAlignment="Center"
Margin="50,0,10,0"/>
<ComboBox x:Name="PenColor"
VerticalAlignment="Center"
SelectedIndex="0"
SelectionChanged="OnPenColorChanged">
<ComboBoxItem Content="Black"/>
<ComboBoxItem Content="Red"/>
</ComboBox>
</StackPanel>
<Grid Grid.Row="1">
<Image Source="Assets\StoreLogo.png" />
<InkCanvas x:Name="inkCanvas" />
</Grid>
</Grid>
その後、選択した色の変更を処理し、それに応じてインク ストローク属性を更新します。
// Update ink stroke color for new strokes.
private void OnPenColorChanged(object sender, SelectionChangedEventArgs e)
{
if (inkCanvas != null)
{
InkDrawingAttributes drawingAttributes =
inkCanvas.InkPresenter.CopyDefaultDrawingAttributes();
string value = ((ComboBoxItem)PenColor.SelectedItem).Content.ToString();
switch (value)
{
case "Black":
drawingAttributes.Color = Windows.UI.Colors.Black;
break;
case "Red":
drawingAttributes.Color = Windows.UI.Colors.Red;
break;
default:
drawingAttributes.Color = Windows.UI.Colors.Black;
break;
};
inkCanvas.InkPresenter.UpdateDefaultDrawingAttributes(drawingAttributes);
}
}
これらの画像は、 InkPresenter によってペン入力がどのように処理およびカスタマイズされるかを示しています。
InkCanvas、ユーザーが選択した赤インクのストローク付き。
ストロークの選択など、インクや消去以外の機能を提供するためには、アプリで処理されるべき未処理の状態で特定の入力を受け取るために、InkPresenter の入力を正確に識別する必要があります。
高度な処理のためのパススルー入力
既定では、 InkPresenter は、ペン バレル ボタン、右マウス ボタンなどのセカンダリ ハードウェア アフォーダンスによって変更された入力を含め、すべての入力をインク ストロークまたは消去ストロークとして処理します。 ただし、ユーザーは通常、これらのセカンダリ アフォーダンスを使用して、いくつかの追加機能または変更された動作を期待します。
場合によっては、通常ペン先に関連付けられていない、セカンダリアフォーダンスのないペンの追加機能や、その他のタイプの入力デバイス、またはアプリのUIでのユーザーの選択に基づいた動作の変更を公開する必要がある場合もあります。
これをサポートするために、 InkPresenter は、特定の入力を未処理のままにするように構成できます。 この未処理の入力は、処理のためにアプリに渡されます。
例 - 未処理の入力を使用してストロークの選択を実装する
Windows Ink プラットフォームでは、ストロークの選択など、変更された入力を必要とするアクションの組み込みサポートは提供されません。 このような機能をサポートするには、アプリにカスタム ソリューションを提供する必要があります。
次のコード例 (すべてのコードは MainPage.xaml および MainPage.xaml.cs ファイルにあります) では、ペン バレル ボタン (またはマウスの右ボタン) を使用して入力が変更されたときにストロークの選択を有効にする方法について説明します。
まず、MainPage.xaml で UI を設定します。
ここでは、選択ストロークを描画するキャンバス ( InkCanvas の下) を追加します。 別のレイヤーを使用して選択ストロークを描画すると 、InkCanvas とそのコンテンツはそのまま残ります。
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <StackPanel x:Name="HeaderPanel" Orientation="Horizontal" Grid.Row="0"> <TextBlock x:Name="Header" Text="Advanced ink customization sample" VerticalAlignment="Center" Style="{ThemeResource HeaderTextBlockStyle}" Margin="10,0,0,0" /> </StackPanel> <Grid Grid.Row="1"> <!-- Canvas for displaying selection UI. --> <Canvas x:Name="selectionCanvas"/> <!-- Inking area --> <InkCanvas x:Name="inkCanvas"/> </Grid> </Grid>
MainPage.xaml.csでは、選択 UI の側面への参照を保持するためのグローバル変数をいくつか宣言します。 具体的には、選択したなげなわのストロークと、選択したストロークを強調表示する外接する四角形です。
// Stroke selection tool. private Polyline lasso; // Stroke selection area. private Rect boundingRect;
次に、インク ストロークとしてペンとマウスの両方からの入力データを解釈し、インクCanvas へのストロークのレンダリングに使用される初期インク ストローク属性を設定するように InkPresenter を構成します。
最も重要なのは、InkPresenter の InputProcessingConfiguration プロパティを使用して、変更された入力をアプリで処理する必要があることを示します。 変更された入力は、
InputProcessingConfiguration.RightDragAction InkInputRightDragAction.LeaveUnprocessedの値割り当てることによって指定されます。 この値が設定されると、 InkPresenter は InkUnprocessedInput クラスに渡されます。これは、処理するポインター イベントのセットです。 未処理の PointerPressed、PointerMoved、そして PointerReleased イベントに対して、InkPresenterによって渡されたリスナーを割り当てます。 すべての選択機能は、これらのイベントのハンドラーに実装されます。
最後に、InkPresenterの StrokeStarted イベントと StrokesErased イベントのリスナーを割り当てます。 これらのイベントのハンドラーを使用して、新しいストロークが開始された場合、または既存のストロークが消去された場合に、選択 UI をクリーンアップします。
public MainPage() { this.InitializeComponent(); // Set supported inking device types. inkCanvas.InkPresenter.InputDeviceTypes = Windows.UI.Core.CoreInputDeviceTypes.Mouse | Windows.UI.Core.CoreInputDeviceTypes.Pen; // Set initial ink stroke attributes. InkDrawingAttributes drawingAttributes = new InkDrawingAttributes(); drawingAttributes.Color = Windows.UI.Colors.Black; drawingAttributes.IgnorePressure = false; drawingAttributes.FitToCurve = true; inkCanvas.InkPresenter.UpdateDefaultDrawingAttributes(drawingAttributes); // By default, the InkPresenter processes input modified by // a secondary affordance (pen barrel button, right mouse // button, or similar) as ink. // To pass through modified input to the app for custom processing // on the app UI thread instead of the background ink thread, set // InputProcessingConfiguration.RightDragAction to LeaveUnprocessed. inkCanvas.InkPresenter.InputProcessingConfiguration.RightDragAction = InkInputRightDragAction.LeaveUnprocessed; // Listen for unprocessed pointer events from modified input. // The input is used to provide selection functionality. inkCanvas.InkPresenter.UnprocessedInput.PointerPressed += UnprocessedInput_PointerPressed; inkCanvas.InkPresenter.UnprocessedInput.PointerMoved += UnprocessedInput_PointerMoved; inkCanvas.InkPresenter.UnprocessedInput.PointerReleased += UnprocessedInput_PointerReleased; // Listen for new ink or erase strokes to clean up selection UI. inkCanvas.InkPresenter.StrokeInput.StrokeStarted += StrokeInput_StrokeStarted; inkCanvas.InkPresenter.StrokesErased += InkPresenter_StrokesErased; }
次に、処理されていない PointerPressed、PointerMoved、そして PointerReleased イベントが InkPresenterを通じて渡される際のハンドラーを定義します。
これらのハンドラーでは、選択機能のすべてが実装されており、なげなわストロークや外接矩形が含まれています。
// Handle unprocessed pointer events from modified input. // The input is used to provide selection functionality. // Selection UI is drawn on a canvas under the InkCanvas. private void UnprocessedInput_PointerPressed( InkUnprocessedInput sender, PointerEventArgs args) { // Initialize a selection lasso. lasso = new Polyline() { Stroke = new SolidColorBrush(Windows.UI.Colors.Blue), StrokeThickness = 1, StrokeDashArray = new DoubleCollection() { 5, 2 }, }; lasso.Points.Add(args.CurrentPoint.RawPosition); selectionCanvas.Children.Add(lasso); } private void UnprocessedInput_PointerMoved( InkUnprocessedInput sender, PointerEventArgs args) { // Add a point to the lasso Polyline object. lasso.Points.Add(args.CurrentPoint.RawPosition); } private void UnprocessedInput_PointerReleased( InkUnprocessedInput sender, PointerEventArgs args) { // Add the final point to the Polyline object and // select strokes within the lasso area. // Draw a bounding box on the selection canvas // around the selected ink strokes. lasso.Points.Add(args.CurrentPoint.RawPosition); boundingRect = inkCanvas.InkPresenter.StrokeContainer.SelectWithPolyLine( lasso.Points); DrawBoundingRect(); }
PointerReleased イベント ハンドラーを終了するには、すべてのコンテンツ (なげなわストローク) の選択レイヤーをクリアし、なげなわ領域に囲まれたインク ストロークの周囲に単一の外接する四角形を描画します。
// Draw a bounding rectangle, on the selection canvas, encompassing // all ink strokes within the lasso area. private void DrawBoundingRect() { // Clear all existing content from the selection canvas. selectionCanvas.Children.Clear(); // Draw a bounding rectangle only if there are ink strokes // within the lasso area. if (!((boundingRect.Width == 0) || (boundingRect.Height == 0) || boundingRect.IsEmpty)) { var rectangle = new Rectangle() { Stroke = new SolidColorBrush(Windows.UI.Colors.Blue), StrokeThickness = 1, StrokeDashArray = new DoubleCollection() { 5, 2 }, Width = boundingRect.Width, Height = boundingRect.Height }; Canvas.SetLeft(rectangle, boundingRect.X); Canvas.SetTop(rectangle, boundingRect.Y); selectionCanvas.Children.Add(rectangle); } }
最後に、 StrokeStarted イベントと StrokesErased InkPresenter イベントのハンドラーを定義します。
これらはどちらも同じクリーンアップ関数を呼び出して、新しいストロークが検出されるたびに現在の選択をクリアするだけです。
// Handle new ink or erase strokes to clean up selection UI. private void StrokeInput_StrokeStarted( InkStrokeInput sender, Windows.UI.Core.PointerEventArgs args) { ClearSelection(); } private void InkPresenter_StrokesErased( InkPresenter sender, InkStrokesErasedEventArgs args) { ClearSelection(); }
新しいストロークが開始されたとき、または既存のストロークが消去されたときに、選択キャンバスからすべての選択 UI を削除する関数を次に示します。
// Clean up selection UI. private void ClearSelection() { var strokes = inkCanvas.InkPresenter.StrokeContainer.GetStrokes(); foreach (var stroke in strokes) { stroke.Selected = false; } ClearDrawnBoundingRect(); } private void ClearDrawnBoundingRect() { if (selectionCanvas.Children.Any()) { selectionCanvas.Children.Clear(); boundingRect = Rect.Empty; } }
カスタムインクレンダリング
既定では、インク入力は待機時間の短いバックグラウンド スレッドで処理され、描画時に進行中 ("wet" ) でレンダリングされます。 ストロークが完了すると (ペンまたは指が持ち上げられたり、マウス ボタンが離されたり)、ストロークは UI スレッドで処理され、 InkCanvas レイヤーに "ドライ" レンダリングされます (アプリケーションコンテンツの上、ウェット インクを置き換えます)。
この既定の動作をオーバーライドし、ウェット インク ストロークを "カスタム乾燥" することで、手描き入力エクスペリエンスを完全に制御できます。 通常、既定の動作はほとんどのアプリケーションで十分ですが、カスタムの乾燥が必要になる場合がいくつかありますが、次のような場合があります。
- インク ストロークの大規模な、または複雑なコレクションのより効率的な管理
- 大規模なインク キャンバスでのより効率的なパンニングとズームのサポート
- Z オーダーを維持しつつ、インクや図形、テキストなどのオブジェクトを交互に配置する
- インクを同期的に乾燥して DirectX 図形に変換します (たとえば、インクCanvas レイヤーを個別に
するのではなく、直線または図形をラスタライズしてアプリケーション コンテンツに統合します)。
カスタム乾燥には、インク入力を管理し、既定の InkCanvas コントロールではなく、ユニバーサル Windows アプリの Direct2D デバイス コンテキストにレンダリングするために、IInkD2DRenderer オブジェクトが必要です。
ActivateCustomDrying (InkCanvas が読み込まれる前) を呼び出すことにより、アプリは InkSynchronizer オブジェクトを作成し、インクストロークをどのように乾いた状態で SurfaceImageSource または VirtualSurfaceImageSourceにレンダリングするかをカスタマイズします。
SurfaceImageSource と VirtualSurfaceImageSource はどちらも、アプリがアプリケーションのコンテンツに描画して作成するための DirectX 共有サーフェイスを提供しますが、VSIS には、パンとズームを実行するために画面よりも大きい仮想サーフェスが用意されています。 これらのサーフェイスに対する視覚的な更新は XAML UI スレッドと同期されているため、インクがどちらかにレンダリングされる際、濡れているインクを InkCanvas から同時に削除することができます。
SwapChainPanel に対してドライ インクをカスタムすることもできますが、UI スレッドとの同期は保証されず、インクが SwapChainPanel にレンダリングされてから InkCanvas からインクが削除されるまでに遅延が発生する可能性があります。
この機能の完全な例については、 複合インクのサンプルを参照してください。
注
カスタム乾燥と InkToolbar
アプリが InkPresenter の既定のインク レンダリング動作をカスタムの乾燥実装でオーバーライドした場合、レンダリングされたインク ストロークは InkToolbar で使用できなくなり、InkToolbar の組み込みの消去コマンドは期待どおりに動作しません。 消去機能を提供するには、すべてのポインター イベントを処理し、各ストロークでヒット テストを実行し、組み込みの "すべてのインクの消去" コマンドをオーバーライドする必要があります。
このセクションのその他の記事
トピック | 説明 |
---|---|
インク ストロークの認識 | 手書き認識を使用してインク ストロークをテキストに変換するか、カスタム認識を使用して図形に変換します。 |
インク ストロークを 保存し、読み込む | 埋め込みインク シリアル化形式 (ISF) メタデータを使用して、インク ストローク データをグラフィックス交換形式 (GIF) ファイルに格納します。 |
Windows 手描き入力アプリに InkToolbar を追加する | Windows アプリの手描き入力アプリに既定の InkToolbar を追加し、InkToolbar にカスタム ペン ボタンを追加し、カスタム ペン ボタンをカスタム ペン定義にバインドします。 |
関連資料
API(アプリケーションプログラミングインターフェース)
サンプル
- 入門チュートリアル: Windows アプリでインクをサポートする方法
- 単純なインク サンプル (C#/C++)
- 複合インク サンプル (C++)
- JavaScriptのインクサンプル
- 塗り絵のサンプル
- 家族メモのサンプル
- 基本的な入力サンプル
- 低待機時間の入力サンプル
- ユーザー操作モードのサンプル
- フォーカス ビジュアルズ サンプル
アーカイブされたサンプル
Windows developer