ペンタブレットの筆圧

タグの編集
投稿者 まだまだ  (高校生) 投稿日時 2010/12/18 22:26:19
こんにちは。いつもお世話になっております。
さて、本題ですが、今ペンタブレット対応のアプリケーションを製作しております。
そこで、ペンタブレットの筆圧を感知したいです。
調べてみたのですが、文献があまりないようで、やり方がわかりません。
どなたか、やり方をお知りの方は、教えてください
宜しくお願いいたします。
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2010/12/18 22:50:20
> ペンタブレットの筆圧を感知したいです。
インク ストロークのパケット プロパティにて筆圧情報を得られます。
Microsoft.Ink.DLL の Stroke クラスおよび PacketProperty クラスについて調べてみてください。
http://msdn.microsoft.com/ja-jp/library/microsoft.ink.stroke_members(v=VS.90).aspx
http://msdn.microsoft.com/ja-jp/library/microsoft.ink.packetproperty.normalpressure(v=VS.90).aspx
http://msdn.microsoft.com/ja-jp/library/microsoft.ink.packetproperty.tangentpressure(v=VS.90).aspx


> 文献があまりないようで、やり方がわかりません。
公式資料として、Tablet PC SDK が存在しています。
現在は Windows SDK に統合されていたと思います。まずはそちらを読んでみてください。

古い資料ですが、参考になりそうな開発記事としてはこのあたり。
http://msdn.microsoft.com/ja-jp/library/aa480685.aspx
http://msdn.microsoft.com/ja-jp/magazine/cc967278.aspx

Windows SDK 自体はこのあたり。
http://msdn.microsoft.com/ja-jp/windows/bb980924
投稿者 まだまだ  (高校生) 投稿日時 2010/12/18 23:25:44
魔界の仮面弁士さん、ありがとうございます。
僕の調べ方が下手なようで沢山資料もあるのですね。
さっそく見てみて、どうやらMicrosoft,Ink名前空間の関数群を
利用すればよいということが分かり、さっそくプログラムを打ってみました。
例えば、http://msdn.microsoft.com/ja-jp/library/microsoft.ink.packetproperty.normalpressure%28VS.90%29.aspxのを利用して、
Dim value As Guid
value = Microsoft.Ink.PacketProperty.NormalPressure

と打ってみましたが、InkはMicrosoftのメンバではないと警告が出てしまいます。
どうしてかさっぱりです。「Microsoft.Ink.DLL」等を参照に追加する必要があるのでしょうか。
「Microsoft.Ink.DLL」も探してみましたが、どこにあるかよくわかりません。
僕の知識不足で何かやっていない事が有るのでしょうか。
宜しくお願いします。

ちなみに、VB2008EEのWindowsフォームアプリケーションで進めています。
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2010/12/18 23:40:01
> Dim value As Guid
> value = Microsoft.Ink.PacketProperty.NormalPressure
これはただの定数に過ぎません。
この定数を Storoke.GetPacketValuesByProperty に指定する事で、実際の筆圧値が得られます。

> 「Microsoft.Ink.DLL」等を参照に追加する必要があるのでしょうか。
その通りです。XP Tablet PC Edition や Vista 等では、既にインストール済みの可能性もありますが、
2000 や XP Professional 等では、先述の SDK 等から、別途インストールしてください。

# SDK = Software Development Kit (ソフトウェア開発キット)
投稿者 まだまだ  (高校生) 投稿日時 2010/12/19 00:12:15
>これはただの定数に過ぎません。
>この定数を Storoke.GetPacketValuesByProperty に指定する事で、実際の筆圧値が得られます。
なるほど、そうだったのですか。勘違いしていたようです。

今僕はVistaを使っているのですが、どうやって
Microsoft.Ink.DLLを参照に追加すればよいのでしょうか。
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2010/12/19 11:42:16
手元に、HP社のタブレットPC(Vista Business, X64)+VS2008+VS6 があるのですが、
この環境においては、VB6 のコンポーネントの追加に "Microsoft Ink Edit Control 1.0" (InkEd.dll) が
表示されますが、VB2008 の参照設定の一覧には "Microsoft.Ink.dll" が見当たりませんでした。

しかし、HDD 上には
 C:\Program Files\Common Files\Microsoft Shared\ink
 C:\Program Files (x86)\Common Files\microsoft shared\ink
に、Microsoft.Ink.DLL が存在していたので、64bit 版の方を指定することで .NET の参照設定に
"Microsoft.Ink  6.0.0.0" が加わり、VB2008 から利用できるようになりました。

これらのマネージ/アンマネージ ライブラリが、OS や VS 標準の物かどうかは把握していませんが、
下記を見る限り、どうやら SDK には含まれているようですので、もし見つからなければ
別途インストールすることで対応できるかと思います。
http://msdn.microsoft.com/ja-jp/library/dd251263.aspx
http://dev.tyzoh.jp/trac/kotodama/ticket/33
投稿者 まだまだ  (高校生) 投稿日時 2010/12/19 12:11:25
ご回答ありがとうございます。
さっそく教えていただいた
 C:\Program Files\Common Files\Microsoft Shared\ink\Microsoft.Ink.dll
を参照に追加してコード上でも入力候補にMicrosoft.Inkが出るようになりました。
そこで先ほどのMSDNを参考にして、次のように書きました。
Dim a As Microsoft.Ink.Stroke
Label1.Text = a.GetPacketValuesByProperty(Microsoft.Ink.PacketProperty.NormalPressure)(0)

これだと予想通りaがNullだと怒られました。
Microsoft.Ink.StrokeはClassだからNewをつけてやれば解決かと思い、
Dim a As New Microsoft.Ink.Stroke
Label1.Text = a.GetPacketValuesByProperty(Microsoft.Ink.PacketProperty.NormalPressure)(0)

と書きました。しかしこんどは、Microsoft.Ink.Strokeにコンストラクタが有りません、
と、でてしまい、できません。
コンストラクタのないクラスで、GetPacketValuesByPropertyもSharedではないのに、
どうやってこのクラスを使うのでしょうか。
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2010/12/19 12:23:19
ツールボックスを右クリックして、先程の DLL を指定してみてください。
InkPicture(とInkEdit)コントロールが追加されるはずです。
投稿者 まだまだ  (高校生) 投稿日時 2010/12/19 13:12:16
ご回答ありがとうございます。
無事にInkPictureコントロールが出現し、Formに張り付けて
実行すると筆圧に応じて太さ等が変わったのですが、
今やりたいことは「数値で現在の筆圧を感知する」、ということです。
そのようなことはできないのでしょうか?
また、このコントロールを使わないで筆圧検知は出来るのでしょうか?
宜しくお願いします。
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2010/12/19 15:39:26
闇雲にコーディングを進めるのではなく、まずは SDK に一通り目を通しましょう。
とりあえず、日本語の追加資料を紹介しておきます。VB/C# 両対応です。
http://www.microsoft.com/japan/windowsxp/tabletpc/techinfo/articles/inkedit.mspx

> 沢山資料もあるのですね。
日本語化された資料も増えては来ましたが、基本的には英語原文の方が情報が豊富です。
http://msdn.microsoft.com/en-us/library/ms819502.aspx

> 今やりたいことは「数値で現在の筆圧を感知する」、ということです。
先ほども書きましたが、Storoke クラスについて調べてみてください。

InkPicture を使っているのなら、描画後に発生する Stroke イベントの引数を見ると良いでしょう。
あるいは、既に描画済みのストロークをユーザーが選択した場合、それを Selection プロパティから
得ることができます。

> コンストラクタのないクラスで、GetPacketValuesByPropertyもSharedではないのに、
> どうやってこのクラスを使うのでしょうか。 
ストロークは通常、自分で生成するたぐいのものではありませんよね。
ペン入力された結果としてシステム側から通知される物です。

それともペン入力とは関係なく、ストロークをコードで生成したいという意味でしょうか?


> また、このコントロールを使わないで筆圧検知は出来るのでしょうか?
どういう意味でしょう。InkOverlay クラスの事でしょうか?
使いたくない理由を説明してもらわないことには、代替案を提示する事すらできません。(^^;

コントロール外での認識が必要という意味なのか、インクの流出が邪魔と感じているとか、
標準のライブラリの動きに不満があるので、ペンの角度、筆圧、速度、近接空中での動きなどを
把握したうえで、自分で処理したいとか、アンマネージコード(WinTab API)を使いたいとか…。

で。そもそも筆圧を感知したうえで、何をやりたいのでしょうか。
描画処理でないとしたら、文字認識? ジェスチャー入力?
(もしも Windows タッチ絡みの話だとしたら、それはまた別の技術です)
投稿者 まだまだ  (高校生) 投稿日時 2010/12/20 20:31:53
ご回答ありがとうございます。
今私はタブレットを利用したゲームの制作をしています。
それで、あまり普通の関数やプロパティがないコントロールは使用せずに
すすめたいのです。
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2010/12/20 20:50:43
> 今私はタブレットを利用したゲームの制作をしています。
> それで、あまり普通の関数やプロパティがないコントロールは使用せずに
> すすめたいのです。 

「何故、それらを使用したくないと考えているのか」の説明にはなっていないような…。(^^;
投稿者 まだまだ  (高校生) 投稿日時 2010/12/20 22:05:32
不明瞭な投稿ですみません。

Form上にはいろいろな描写を行うので、InkPictureを使うと、船が描写され邪魔になったり、
また、InkPictureの上にコントロールを配置するとInkPictureコントロールが反応しなくなり、
また、InkPictureの下にコントロールを配置するとそのコントロールが見えなくなるので、
使用したくないと考えております。
まだ不明瞭な点が有ればすみません。
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2010/12/21 02:42:25
> Form上にはいろいろな描写を行うので
船などの描画を、Form ではなく InkPicture に対して行ってはダメでしょうか?
InkPicture は、PictureBox の派生クラスです。

> また、InkPictureの上にコントロールを配置するとInkPictureコントロールが反応しなくなり、
> また、InkPictureの下にコントロールを配置するとそのコントロールが見えなくなるので、
既存のコントロールに対して、タブレット機能を追加したいなら、
InkOvelayクラスにAttachedControlすれば済みます。
(使い方は、InkPicture とほぼ同じです)


フォーム上にラベルをひとつ貼っておいてください。
フォームをスタイラスで操作すると、筆圧値とタブレット座標が、リアルタイムに表示されます。

Imports Microsoft.Ink

Public Class Form1
    Private WithEvents obj As InkOverlay

    Private Sub obj_NewInAirPackets(ByVal sender As Object, _
            ByVal e As InkCollectorNewInAirPacketsEventArgs) Handles obj.NewInAirPackets
        Dim pos As New Point(e.PacketData(0), e.PacketData(1))
        Label1.Text = String.Format("{0} [空中] {1}", e.Cursor.Name, pos)
    End Sub

    Private Sub obj_NewPackets(ByVal sender As Object, _
            ByVal e As InkCollectorNewPacketsEventArgs) Handles obj.NewPackets
        Dim pos As New Point(e.PacketData(0), e.PacketData(1))
        Dim pressure As Integer = e.PacketData(2)
        Label1.Text = String.Format("{0} [筆圧{1}] {2}", e.Cursor.Name, pressure, pos)
    End Sub

    Private Sub Form1_Load(ByVal sender As ObjectByVal e As EventArgs) Handles MyBase.Load
        obj = New InkOverlay()
        obj.AttachedControl = Me                        'Form を対象にして認識させる 
        obj.AttachMode = InkOverlayAttachMode.Behind    'Form 上の Label や Button 等の下のレイヤー 

        'パケットに筆圧を含める 
        Dim Packets() As Guid = {PacketProperty.NormalPressure}
        obj.DesiredPacketDescription = Packets

        'スタイラスの動きを分かりやすくするため、デジタルインクをあえて描画させておく 
        '邪魔にならない程度に目立たせるため、半透明の赤いインクを利用 
        obj.DynamicRendering = True
        obj.EditingMode = InkOverlayEditingMode.Ink
        obj.DefaultDrawingAttributes.Color = Color.Red
        obj.DefaultDrawingAttributes.Transparency = 200

        obj.Enabled = True  'タブレット利用=On 
    End Sub

    Private Sub Form1_FormClosed(ByVal sender As Object, _
            ByVal e As FormClosedEventArgs) Handles Me.FormClosed
        obj.Dispose()        '使用後は必ず破棄すること 
    End Sub

    Private Sub obj_Stroke(ByVal sender As Object, _
            ByVal e As InkCollectorStrokeEventArgs) Handles obj.Stroke
        e.Cancel = True        '描画したいわけではないので、インク情報は即座に捨ててしまう 
    End Sub
End Class
投稿者 まだまだ  (高校生) 投稿日時 2010/12/26 00:47:27
返信遅くなりましたがありがとうございます。
今回はInkOverlayを使わせていただくことにします。
ご提示いただいたサンプルを参考にしながらプログラムを
完成させたいと思います。
また困った時は宜しくお願いいたします。