UI 要素の名前が正しいことを確認する
このトピックでは、Microsoft Active Accessibilityが IAccessible Name プロパティを使用してクライアント アプリケーションに名前を正確に公開できるように、Microsoft Win32 アプリケーションで UI 要素の名前を指定する正しい方法について説明します。
このセクションの情報は、Microsoft Active Accessibility にのみ適用されます。 Microsoft UI オートメーションを使用するアプリケーションや、HTML、動的 HTML (DHTML)、XML などのマークアップ言語に基づくアプリケーションには適用されません。
- 概要
- 不適切な名前付けが原因で発生する問題
- MSAA が Name プロパティを取得する方法
- 名前付けの問題を見つけて修正する方法
- トラック バーに正しい名前を付ける方法
- 非表示のラベルを使用してコントロールに名前を付ける方法
- 直接注釈を使用して Name プロパティを指定する方法
- 関連トピック
概要
Microsoft Active Accessibility では、アプリケーション内の各 UI 要素は、IAccessible インターフェイスを公開するオブジェクトによって表されます。 クライアント アプリケーションでは、IAccessible インターフェイスのプロパティとメソッドを使用して UI 要素を操作し、それに関する情報を取得します。 IAccessible インターフェイスによって公開される最も重要なプロパティの 1 つは、Name プロパティです。 クライアント アプリケーションは、ユーザーに対して UI 要素を検索、識別、または読み上げるために Name プロパティに依存します。 Microsoft Active Accessibility が特定の UI 要素の Name プロパティを適切に公開できない場合、クライアント アプリケーションはその UI 要素をユーザーに提示できず、その UI 要素は障碍のあるユーザーにアクセスできなくなります。
不適切な名前付けが原因で発生する問題
UI 要素の不適切な名前付けに起因する問題を例示するために、次の図に示す名前入力フォームについて考えてみましょう。
フォーム内の UI 要素に問題はないように見えますが、プログラムによる実装は正しくありません。 スクリーン リーダーなどの Microsoft Active Accessibility クライアントの場合、 上部の編集コントロールの Name プロパティは "Last Name (姓):" で、下部の編集コントロールの Name プロパティは空の文字列 ("") です。 スクリーン リーダーは上部の編集コントロールを "Last Name (姓)" と読み取りますが、ユーザーは下の名前を入力する必要があります。 スクリーン リーダーは、2 番目の編集コントロールを "名前なし" と読み取るので、ユーザーは 2 番目の編集コントロールに何を入力したらよいか分かりません。 スクリーン リーダーは、ユーザーがこの単純なフォームにデータを入力するのを支援できません。
このフォームのもう 1 つの問題は、いずれかの編集コントロールにもショートカット キーが割り当てられていない点です。 ユーザーは、コントロールにタブ移動するか、マウスを使用するように強制されます。
次のセクションでは、これらの問題の原因について説明し、それらを修正するためのガイドラインを提供します。
MSAA が Name プロパティを取得する方法
Microsoft Active Accessibility は、UI 要素の種類に応じて異なる場所から Name プロパティ文字列を取得します。 ウィンドウ テキストが関連付けられているほとんどの UI 要素では、Microsoft Active Accessibility はウィンドウ テキストを Name プロパティ文字列として使用します。 この種類の UI 要素の例としては、ボタン、メニュー項目、ヒントなどのコントロールがあります。
次のコントロールの場合には、Microsoft Active Accessibility はウィンドウ テキストを無視し、代わりに、タブ オーダーでコントロールの直前にある静的テキスト ラベル (またはグループ ボックス ラベル) を探します。
- コンボ ボックス
- 日付と時刻の選択
- エディット コントロールとリッチ エディット コントロール
- IP アドレス コントロール
- リスト ボックス
- リスト ビュー
- プログレス バー
- スクロール バー
- SS_ICON または SS_BITMAP スタイルを持つ静的コントロール
- トラックバー
- ツリー ビュー
上記のコントロールに静的テキスト ラベルが添付されていない場合、またはラベルが正しく実装されていない場合、Microsoft Active Accessibility はクライアント アプリケーションに正しい Name プロパティを提供できません。
上記のコントロールのほとんどには、実際にはウィンドウ テキストが関連付けられています。 リソース エディターは、"edit1" や "listbox3" などの汎用文字列で構成されるウィンドウ テキストを自動的に生成します。 開発者は生成されたウィンドウテキストをより意味のあるテキストに置き換えることができますが、ほとんど人はそうしません。 生成されたウィンドウ テキストはユーザーとって意味がないため、Microsoft Active Accessibility はそれを無視し、代わりに付随する静的テキスト ラベルを使用します。
名前付けの問題を見つけて修正する方法
「不適切な名前付けが原因で発生する問題」で示した名前の入力フォームでは、問題の原因はコントロールのタブ オーダーが正しくないことです。 Inspect などのテスト ツールを使用して UI を調べると、オブジェクト階層の問題が明らかになります。 次のスクリーン ショットは、Inspect が表示する、正しくない名前入力フォームのオブジェクト階層を示しています。
前のスクリーン ショットでは、オブジェクト階層は、名前入力フォームのユーザー インターフェイスに表示されるコントロールの構造と一致していないことに注意してください。 また、Inspect によって、最後から 2 番目の項目に正しくない名前が割り当てられていることに注意してください (これは、下の名前を入力するための編集コントロールであり、"First Name (名):" と名付ける必要があります)。 最後に、Inspect は、最後の項目の名前を見つけられなかったことにも注意しましょう (これは姓を入力するための編集コントロールであり、名前は "Last Name (姓):" である必要があります)。
次の例は、名前入力フォームのリソース ファイルの内容を示しています。 タブ オーダーがユーザー インターフェイスに表示されるコントロールの論理構造と一致していないことに注意してください。 また、2 つの編集コントロールにショートカット キーが指定されていないことにも注意してください。
IDD_INPUTNAME DIALOGEX 22, 17, 312, 118
STYLE DS_SETFONT | DS_MODALFRAME | WS_CAPTION | WS_SYSMENU
CAPTION "Enter your name"
FONT 8, "System", 0, 0, 0x0
BEGIN
DEFPUSHBUTTON "OK",IDOK,179,35,30,11,WS_GROUP
LTEXT "First Name:",IDC_STATIC,8,16,43,8
LTEXT "Last Name:",IDC_STATIC,8,33,43,8
EDITTEXT IDC_EDIT1,53,15,120,12,ES_AUTOHSCROLL
EDITTEXT IDC_EDIT2,53,34,120,12,ES_AUTOHSCROLL
END
名前入力フォームの問題を修正するには、リソース (.rc) ファイルを編集してキーボード ショートカットを指定し、コントロールを次の順序で配置する必要があります。
- 「&First Name:」という静的テキストラベル。
- 名を入力するための編集コントロール (IDC_EDIT1)。
- 「&Last Name:」という静的テキストラベル。
- 姓を入力するための編集コントロール (IDC_EDIT2)。
- 既定の "OK" プッシュ ボタン。
次の例は、修正された名前入力フォームのリソース ファイルを示しています。
IDD_INPUTNAME DIALOGEX 22, 17, 312, 118
STYLE DS_SETFONT | DS_MODALFRAME | WS_CAPTION | WS_SYSMENU
CAPTION "Enter your name"
FONT 8, "System", 0, 0, 0x0
BEGIN
LTEXT "&First Name:",IDC_STATIC,8,16,43,8
EDITTEXT IDC_EDIT1,53,15,120,12,ES_AUTOHSCROLL
LTEXT "&Last Name:",IDC_STATIC,8,33,43,8
EDITTEXT IDC_EDIT2,53,34,120,12,ES_AUTOHSCROLL
DEFPUSHBUTTON "OK",IDOK,179,35,30,11,WS_GROUP
END
リソース ファイルを修正するには、ファイルを直接編集するか、Microsoft Visual Studio のタブ オーダー ツールを使用します。 Visual Studio でタブ オーダー ツールにアクセスするには、Ctrl + D を押すか、[書式] メニューから [タブ オーダー] を選択します。
アプリケーションを修正して再構築すると、名前入力フォームの UI は以前と同じように表示されます。 しかし、Microsoft Active Accessibility では、クライアント アプリケーションに正しい Name プロパティが提供され、ユーザーが Alt + F、または Alt + L を押すと、フォーカスが正しく設定されます。 また、次のスクリーン ショットに示すように、Inspect には正しいオブジェクト階層が表示されます。
トラック バーに正しい名前を付ける方法
トラックバー (またはスライダー) を定義するときは、トラックバーのメインの静的テキスト ラベルがトラックバーの前に表示され、最小および最大範囲の静的テキスト ラベルがトラックバーの後に表示されるようにします。 Microsoft Active Accessibility では、コントロールの直前にある静的テキスト ラベルが、コントロールの Name プロパティとして使用されます。 メインの静的テキスト ラベルをトラックバーの直前に配置し、その直後に他のラベルを配置することで、Microsoft Active Accessibility がクライアントに正しい Name プロパティを提供するようにします。
次の図は、"Speed" というメインの静的テキスト ラベルを持つ一般的なトラックバーと、最小 ("min") 範囲と最大 ("max") 範囲の静的テキスト ラベルを示しています。
次の例は、リソース ファイルでトラックバーとその静的テキスト ラベルを定義する正しい方法を示します。
BEGIN
...
LTEXT "&Speed",IDC_STATIC,47,20,43,8
CONTROL "",IDC_SLIDER1,"msctls_trackbar32",
TBS_AUTOTICKS | TBS_BOTH | WS_TABSTOP,
32,32,62,23
LTEXT "min",IDC_STATIC,16,37,15,8
LTEXT "max",IDC_STATIC,94,38,43,8
...
END
非表示のラベルを使用してコントロールに名前を付ける方法
すべてのコントロールに対して表示ラベルを持つことは、常に可能、または望ましいとは限りません。 たとえば、ラベルを追加すると、UI の外観に望ましくない変化が起きる場合があります。 この場合、非表示のラベルを使用できます。 Microsoft Active Accessibility は、非表示のラベルに関連付けられているテキストも取得しますが、そのラベルはビジュアル UI には表示されず、影響も与えません。
表示ラベルと同様に、非表示ラベルは、タブ オーダーでコントロールの直前に配置する必要があります。 リソース ファイル (.rc) でラベルを非表示にするには、静的テキスト コントロールのスタイル部分に NOT WS_VISIBLE
または |~WS_VISIBLE
を追加します。 Visual Studio でリソース エディターを使用している場合は、Visible プロパティを False に設定できます。
直接注釈を使用して Name プロパティを指定する方法
Microsoft Active Accessibility ランタイム コンポーネント Oleacc.dll に含まれる既定のプロキシは、すべての標準 Windows コントロールに IAccessible オブジェクトを自動的に提供します。 標準の Windows コントロールをカスタマイズする場合、既定のプロキシは、カスタマイズされたコントロールのすべての IAccessible プロパティを正確に提供するために最善を尽くします。 カスタマイズされたコントロールを十分にテストして、既定のプロキシが正確で完全なプロパティ値を提供していることを確認する必要があります。 テストで不正確または不完全なプロパティ値が明らかになった場合は、直接注釈と呼ばれる動的注釈手法を使用して、正しいプロパティ値を提供し、欠けている値を追加できる可能性があります。
動的注釈は、Microsoft Active Accessibility プロキシでサポートされているコントロールだけのためのものではありません。 独自の IAccessible 実装を提供する任意のコントロールのプロパティを変更または提供することにも使用できます。
このセクションでは、直接注釈を使用して、コントロールに対する IAccessible オブジェクトの Name プロパティに正しい値を指定することに重点を置きます。 直接注釈を使用して、他のプロパティ値も指定できます。 また、直接注釈以外の他の動的注釈手法も利用できます。動的注釈 API の機能は、このセクションで説明されているものをはるかに超えるものです。 動的注釈の詳細については、「Dynamic Annotation API」を参照してください。
Name プロパティに注釈を付ける手順
直接注釈を使用してコントロールの Name プロパティを変更するには、次の手順を実行します。
次のヘッダー ファイルをインクルードします。
- Initguid.h
- Oleacc.h
Note
GUID を定義するには、同じファイル内で Oleacc.h より先に Initguid.h をインクルードする必要があります。
CoInitializeEx 関数を、通常はアプリケーションの初期化プロセス中に呼び出して、コンポーネント オブジェクト モデル (COM) ライブラリを初期化します。
ターゲット コントロールが作成された直後 (通常は WM_INITDIALOG メッセージ中)、注釈マネージャーのインスタンスを作成し、その IAccPropServices ポインターへのポインターを取得します。
IAccPropServices::SetHwndPropStr メソッドを使用して、ターゲット コントロールの Name プロパティに注釈を付けます。
IAccPropServices ポインターを解放します。
ターゲット コントロールが破棄される前に (通常、WM_DESTROY メッセージを処理する時)、注釈マネージャーのインスタンスを作成し、その IAccPropServices インターフェイスへのポインターを取得します。
IAccPropServices::ClearHwndProps メソッドを使用して、ターゲット コントロールから Name プロパティの注釈をクリアします。
IAccPropServices ポインターを解放します。
アプリケーションが終了する前に (通常、WM_DESTROY メッセージの処理中)、CoUninitialize 関数を呼び出して COM ライブラリを解放します。
IAccPropServices::SetHwndPropStr 関数は 5 つのパラメータを受け取ります。 最初の 3 つ (hwnd、idObject、idChild) の組み合わせでコントロールを識別します。 4 番目のパラメータ idProp は、変更するプロパティの識別子を指定します。 Name プロパティを変更するには、idProp を PROPID_ACC_NAME に設定します。 (直接注釈を使用して設定できるその他のプロパティの一覧については、「直接注釈の使用」を参照してください。)SetHwndPropStr の最後のパラメータ str は、Name プロパティとして使用する新しい文字列です。
Name プロパティに注釈を付ける例
次のコード例は、直接注釈を使用してコントロールの IAccessible オブジェクトの Name プロパティを変更する方法を示しています。 わかりやすくするために、この例ではハードコーディングされた文字列 ("New Control Name") を使用して Name プロパティを設定します。 ハードコーディングされた文字列はローカライズできないため、アプリケーションの最終バージョンでは使用しないでください。 代わりに、常にリソース ファイルから文字列を読み込むようにしてください。 また、この例では、CoInitializeEx 関数と CoUninitialize 関数の呼び出しは表示されません。
#include <initguid.h>
#include <oleacc.h>
// AnnotateControlName - Uses direct annotation to change the Name property
// of the IAccessible object for a control.
//
// hDlg - Handle of the dialog box that contains the control.
// hwndCtl - Handle of the control whose Name property is to be changed.
HRESULT AnnotateControlName(HWND hDlg, HWND hwndCtl)
{
HRESULT hr;
IAccPropServices *pAccPropSvc = NULL;
// Create an instance of the annotation manager and retrieve the
// IAccPropServices pointer.
hr = CoCreateInstance(CLSID_AccPropServices, NULL, CLSCTX_SERVER,
IID_IAccPropServices, (void **) &pAccPropSvc);
if (hr != S_OK || pAccPropSvc == NULL)
return hr;
// Set the Name property for the control.
// Note: A hard-coded string is used here to keep the example simple.
// Always use localizable string resources in your applications.
hr = pAccPropSvc->SetHwndPropStr(hwndCtl, OBJID_CLIENT, CHILDID_SELF,
PROPID_ACC_NAME, L"New Control Name");
pAccPropSvc->Release();
return hr;
}
// RemoveAnnotatedNameFromControl - Removes the annotated name from the
// Name property of the IAccessible object for a control.
//
// hDlg - Handle of the dialog box that contains the control.
// hwndCtl - Handle of the control whose annotated name is to be removed.
HRESULT RemoveAnnotatedNameFromControl(HWND hDlg, HWND hwndCtl)
{
HRESULT hr;
IAccPropServices *pAccPropSvc = NULL;
// Create an instance of the annotation manager and retrieve the
// IAccPropServices pointer.
hr = CoCreateInstance(CLSID_AccPropServices, NULL, CLSCTX_SERVER,
IID_IAccPropServices, (void **) &pAccPropSvc);
if (hr != S_OK || pAccPropSvc == NULL)
return hr;
// Remove the annotated name from the Name property for the control.
MSAAPROPID propid = PROPID_ACC_NAME;
hr = pAccPropSvc->ClearHwndProps(hwndCtl, OBJID_CLIENT, CHILDID_SELF,
&propid, 1);
// Release the annotation manager.
pAccPropSvc->Release();
return hr;
}