18

アプリケーションのユーザーエクスペリエンスを向上させるために、UIでユーザーの動きとジェスチャーを測定および分析したいと思います。機能追跡ライブラリ(EQATECやPreemptiveのランタイムインテリジェンスなど)でこれが可能になると想像していました。ただし、これは当てはまらないようです。

理想的には、UIをインストルメント化してから、マウスとキーボードのナビゲーションジェスチャをキャプチャして、ヒートマップを介して表示できるようにしたいと思います。

私の検索は空になりました。ここにOSSやコマーシャルはありますか?

4

5 に答える 5

6
  1. コードプロジェクトに関するこの記事からソースバージョン2をダウンロードする
  2. ソリューションを開くか、Gma.UserActivityMonitorプロジェクトのみを開いて、やみくもに.NET4.0に変換します
  3. HookManager.Callbacks.csファイルで次の変更を行います。

    1. 追加using System.Diagnostics;
    2. 交換

      s_MouseHookHandle = SetWindowsHookEx(
          WH_MOUSE_LL,
          s_MouseDelegate,
          Marshal.GetHINSTANCE(
              Assembly.GetExecutingAssembly().GetModules()[0]),
          0);
      

      using (Process curProcess = Process.GetCurrentProcess())
      using (ProcessModule curModule = curProcess.MainModule)
      {
          s_MouseHookHandle = SetWindowsHookEx(
              WH_MOUSE_LL,
              s_MouseDelegate,
             GetModuleHandle(curModule.ModuleName), 0);
      }
      
    3. 交換

      s_KeyboardHookHandle = SetWindowsHookEx(
          WH_KEYBOARD_LL,
          s_KeyboardDelegate,
          Marshal.GetHINSTANCE(
              Assembly.GetExecutingAssembly().GetModules()[0]),
          0);
      

      using (Process curProcess = Process.GetCurrentProcess())
      using (ProcessModule curModule = curProcess.MainModule)
      {
          s_KeyboardHookHandle = SetWindowsHookEx(
          WH_KEYBOARD_LL,
          s_KeyboardDelegate, 
          GetModuleHandle(curModule.ModuleName), 0);
      }
      
  4. クラスの定義のどこかに次HookManager.Windows.csの2行を追加します。HookManager

    [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
    public static extern IntPtr GetModuleHandle(string lpModuleName);
    
  5. これで、これを作成して脇に置いておくことができるはずです。ここで、WPFパーツを開始します。

  6. できればWpfApplication1という名前で新しいWPFプロジェクトを作成します。手順1-5で作成したプロジェクト/アセンブリへの参照を追加し、 System.Windows.Formsへの参照を追加します。
  7. ここで、MainWindow.xamlを次のXAMLに置き換えます。クラス名とプロジェクト名を確認してください。テスト用にWpfApplication1を作成しました。

    <Window x:Class="WpfApplication1.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="350" Width="525">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="0.30*"/>
                <RowDefinition Height="0.70*"/>
            </Grid.RowDefinitions>
            <StackPanel Grid.Row="0" Orientation="Horizontal">
                <StackPanel Orientation="Vertical">
                    <CheckBox Name="MouseMove" Padding="5" Content="Mouse Move" Width="120" Height="30" Click="checkBoxOnMouseMove_CheckedChanged"/>
                    <CheckBox Name="MouseClick" Padding="5" Content="Mouse Click" Width="120" Height="30" Click="checkBoxOnMouseClick_CheckedChanged"/>
                    <CheckBox Name="MouseDown" Padding="5" Content="Mouse Down" Width="120" Height="30" Click="checkBoxOnMouseDown_CheckedChanged"/>
                </StackPanel>
                <StackPanel Orientation="Vertical">
                    <CheckBox Name="MouseUp" Padding="5" Content="Mouse Up" Width="120" Height="30" Click="checkBoxOnMouseUp_CheckedChanged"/>
                    <CheckBox Name="MouseDouble" Padding="5" Content="Mouse Double" Width="120" Height="30" Click="checkBoxMouseDoubleClick_CheckedChanged"/>
                    <CheckBox Name="MouseWheel" Padding="5" Content="Mouse Wheel" Width="120" Height="30" Click="checkBoxMouseWheel_CheckedChanged"/>
                </StackPanel>
                <StackPanel Orientation="Vertical">
                    <CheckBox Name="KeyDown" Padding="5" Content="Key Down" Width="120" Height="30" Click="checkBoxKeyDown_CheckedChanged"/>
                    <CheckBox Name="KeyPress" Padding="5" Content="Key Press" Width="120" Height="30" Click="checkBoxKeyPress_CheckedChanged"/>
                    <CheckBox Name="KeyUp" Padding="5" Content="Key Up" Width="120" Height="30" Click="checkBoxKeyUp_CheckedChanged"/>
                </StackPanel>
                <StackPanel Orientation="Vertical">
                    <TextBlock Name="labelMousePosition" Text="x={0:####}; y={1:####}"/>
                    <TextBlock Name="labelWheel" Text="Wheel={0:####}"/>
                </StackPanel>
            </StackPanel>
            <TextBlock Name="textBoxLog" Text="START" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Grid.Row="1" ScrollViewer.VerticalScrollBarVisibility="Visible"/>
        </Grid>
    </Window>
    
  8. 次に、MainWindowクラスで定義されたMainWindow.xaml.csファイルに次のコードを追加します。

    #region Check boxes to set or remove particular event handlers.
    
    private void checkBoxOnMouseMove_CheckedChanged(object sender, EventArgs e)
    {
        if ((bool)MouseMove.IsChecked)
        {
            HookManager.MouseMove += HookManager_MouseMove;
        }
        else
        {
            HookManager.MouseMove -= HookManager_MouseMove;
        }
    }
    
    private void checkBoxOnMouseClick_CheckedChanged(object sender, EventArgs e)
    {
        if ((bool)MouseClick.IsChecked)
        {
            HookManager.MouseClick += HookManager_MouseClick;
        }
        else
        {
            HookManager.MouseClick -= HookManager_MouseClick;
        }
    }
    
    private void checkBoxOnMouseUp_CheckedChanged(object sender, EventArgs e)
    {
        if ((bool)MouseUp.IsChecked)
        {
            HookManager.MouseUp += HookManager_MouseUp;
        }
        else
        {
            HookManager.MouseUp -= HookManager_MouseUp;
        }
    }
    
    private void checkBoxOnMouseDown_CheckedChanged(object sender, EventArgs e)
    {
        if ((bool)MouseDown.IsChecked)
        {
            HookManager.MouseDown += HookManager_MouseDown;
        }
        else
        {
            HookManager.MouseDown -= HookManager_MouseDown;
        }
    }
    
    private void checkBoxMouseDoubleClick_CheckedChanged(object sender, EventArgs e)
    {
        if ((bool)this.MouseDouble.IsChecked)
        {
            HookManager.MouseDoubleClick += HookManager_MouseDoubleClick;
        }
        else
        {
            HookManager.MouseDoubleClick -= HookManager_MouseDoubleClick;
        }
    }
    
    private void checkBoxMouseWheel_CheckedChanged(object sender, EventArgs e)
    {
        if ((bool)MouseWheel.IsChecked)
        {
            HookManager.MouseWheel += HookManager_MouseWheel;
        }
        else
        {
            HookManager.MouseWheel -= HookManager_MouseWheel;
        }
    }
    
    private void checkBoxKeyDown_CheckedChanged(object sender, EventArgs e)
    {
        if ((bool)KeyDown.IsChecked)
        {
            HookManager.KeyDown += HookManager_KeyDown;
        }
        else
        {
            HookManager.KeyDown -= HookManager_KeyDown;
        }
    }
    
    
    private void checkBoxKeyUp_CheckedChanged(object sender, EventArgs e)
    {
        if ((bool)KeyUp.IsChecked)
        {
            HookManager.KeyUp += HookManager_KeyUp;
        }
        else
        {
            HookManager.KeyUp -= HookManager_KeyUp;
        }
    }
    
    private void checkBoxKeyPress_CheckedChanged(object sender, EventArgs e)
    {
        if ((bool)KeyPress.IsChecked)
        {
            HookManager.KeyPress += HookManager_KeyPress;
        }
        else
        {
            HookManager.KeyPress -= HookManager_KeyPress;
        }
    }
    
    #endregion
    
    //##################################################################
    #region Event handlers of particular events. They will be activated when an appropriate check box is checked.
    
    private void HookManager_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
    {
        textBoxLog.Text += (string.Format("KeyDown - {0}\n", e.KeyCode));
    
    }
    
    private void HookManager_KeyUp(object sender, System.Windows.Forms.KeyEventArgs e)
    {
        textBoxLog.Text += (string.Format("KeyUp - {0}\n", e.KeyCode));
    
    }
    
    
    private void HookManager_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e)
    {
        textBoxLog.Text += (string.Format("KeyPress - {0}\n", e.KeyChar));
    
    }
    
    
    private void HookManager_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
    {
        labelMousePosition.Text = string.Format("x={0:0000}; y={1:0000}", e.X, e.Y);
    }
    
    private void HookManager_MouseClick(object sender, System.Windows.Forms.MouseEventArgs e)
    {
        textBoxLog.Text += (string.Format("MouseClick - {0}\n", e.Button));
    
    }
    
    
    private void HookManager_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e)
    {
        textBoxLog.Text += (string.Format("MouseUp - {0}\n", e.Button));
    
    }
    
    
    private void HookManager_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
    {
        textBoxLog.Text += (string.Format("MouseDown - {0}\n", e.Button));
    
    }
    
    
    private void HookManager_MouseDoubleClick(object sender, System.Windows.Forms.MouseEventArgs e)
    {
        textBoxLog.Text += (string.Format("MouseDoubleClick - {0}\n", e.Button));
    
    }
    
    
    private void HookManager_MouseWheel(object sender, System.Windows.Forms.MouseEventArgs e)
    {
        labelWheel.Text = string.Format("Wheel={0:000}", e.Delta);
    }
    
    #endregion
    

9.WPFアプリをビルドして実行します。MainWindowにusing Gma.UserActivityMonitor;ディレクティブを追加する必要がある場合があります。

10.すべてのクレジットは、最初にそれを作成したGeorge Mamaladzeに与えられます。彼に感謝状を送信することもできます。また、お金を稼ぎたい場合は、元の作成者からのこのコードの配布ライセンスを確認してください。

11.WPFで動作するように、いくつかの小さな変更を加えました。この長い投稿をフォローしていただきありがとうございます。このコードを共有する方法がわかりません。そのため、このような手順を提供します。

12.私はSOでコードをうまくフォーマットすることに真剣に取り組んでいます。誰かがコード、XMLをうまくフォーマットする方法についてコメントを残すことができますか。また、誰かがこの投稿のスニペットをフォーマットするのを手伝ってくれます。ありがとうございました。

于 2011-03-05T10:23:23.770 に答える
2

ここでのアプローチや、 UIAutomationイベントETW for WPFの使用など、いくつかのアプローチを試した後、WPFイベントにハンドラーを単純にアタッチすることにしました。これにより、イベントデータだけでなく、ユーザーの注意を引くUIElementもキャプチャできるため、ユーザーのアクションと意図を追跡するのがはるかに簡単になります。これがなければ、画面のビジュアルをキャプチャして、何が起こっているのかを視覚的に判断する必要があります。

サンプルは次のとおりです。

private Int32 _eventCount;

public MainWindow()
{
    InitializeComponent();
    EventManager.RegisterClassHandler(typeof(UIElement), MouseEnterEvent, (RoutedEventHandler)handleEvent, true);
    EventManager.RegisterClassHandler(typeof(UIElement), MouseLeaveEvent, (RoutedEventHandler)handleEvent, true);
    EventManager.RegisterClassHandler(typeof(UIElement), MouseMoveEvent, (RoutedEventHandler)handleEvent, true);
    EventManager.RegisterClassHandler(typeof(UIElement), MouseUpEvent, (RoutedEventHandler)handleEvent, true);
    EventManager.RegisterClassHandler(typeof(UIElement), MouseDownEvent, (RoutedEventHandler)handleEvent, true);
    EventManager.RegisterClassHandler(typeof(UIElement), KeyUpEvent, (RoutedEventHandler)handleEvent, true);
    EventManager.RegisterClassHandler(typeof(UIElement), KeyDownEvent, (RoutedEventHandler)handleEvent, true);
}

private void handleEvent(object sender, RoutedEventArgs e)
{
    var uiElement = e.Source as UIElement;

    if (uiElement == null)
    {
        return;
    }

    EventStatusDisplay.Text = e.Source + " " + e.RoutedEvent.Name;
    EventCountDisplay.Text = (++_eventCount).ToString();
    var over = Mouse.DirectlyOver as UIElement;
    MouseIsOverDisplay.Text = over == null ? "" : over.ToString();
}

ここには示されていませんが、UIElementログを取得したら、を使用してUIElement.DataContext、ビューを駆動しているViewModelの状態を判別できるため、特定のワークフローやデータ状態、および視覚的な使用パターンを見つけることができます。状態。次に、これに関するレポートを取得し、ワークフローとデータ値を介してパスごとにヒートマップを区別して比較できます。

于 2011-03-08T23:23:25.600 に答える
1

Snoopは、WPFアプリケーションのビジュアルツリーを検査するためのツールであることがわかっていますが、イベントもキャプチャします(特に、イベントが発生した要素、ビジュアルツリー内を移動した方法、および処理された場所に関する情報を使用してイベントをキャプチャします)。オープンソースであるため、イベントの追跡に関するその部分を抽出し、この情報をニーズに合わせてログに記録することをお勧めします。

于 2011-03-05T09:54:48.507 に答える
1

http://iographica.comを試してみてください 。マウスカーソルが移動した場所に線が作成され、マウスカーソルが停止した場所に円が表示されるほど、円が大きくなり、そこで停止した時間が長くなります。

于 2011-03-03T22:33:07.750 に答える
1

このアプリケーションを見てください。それはあなたが望むことをしませんが、あなたが必要とする機能を実装するための出発点として役立つかもしれません:パーセプター:WPFのための人工知能ガイド付きナビゲーションシステム

于 2011-03-02T10:55:08.520 に答える