2016-07-08 4 views
3

私はDelphiとC++ Builderを使用していますが、スクリーンリーダーに関するいくつかのアクセシビリティに関する質問があります。Delphiコンポーネントとスクリーンリーダー

TWinControlの下にあるフォームにボタンがあります。キャプションをボタンに付けると、ボタンがフォーカスされているときにスクリーンリーダーがそれを私に読んでくれます。しかし、画像とキャプションのないボタンを使用する場合があります。キャプションがない場合、スクリーンリーダーは何も言いません。スクリーンリーダーがこのボタンの意味を伝えるようにするにはどうすればよいですか?

同様に、TGraphicControlを継承したフォーム上の画像。オブジェクトがマウスオーバーしたときに何をすべきかをスクリーンリーダーに伝えるにはどうすればよいですか?

私はIAccessibleラッパーを調べましたが、できる限り使用するすべてのコントロールを拡張しないことをお勧めします。

+0

'TGraphic'はフォーカスを取得できません。コンポーネントでもありません。あなたはおそらく 'TGraphicControl'と言うことになりますが、これはまだフォーカスを得ることができません。それは 'TGraphicControl'の主な目的の一つです。 –

+0

ありがとうございました。私は本当にTGraphicControlを意味し、それに応じて質問を更新しました。私はコントロールの上にマウスを意味し、フォーカスを取得しませんでした。 TGraphicControlsのある種のaltテキストをフォーム上で処理するために他の人が考え出したアイディアを知りたいのです。 –

答えて

3

ただし、画像とキャプションのないボタンを使用する場合があります。キャプションがない場合、スクリーンリーダーは何も言いません。スクリーンリーダーがこのボタンの意味を伝えるようにするにはどうすればよいですか?

IAccessibleボタンの実装は、スクリーンリーダーに必要なテキストを提供する必要があります。デフォルトでは、OSにはボタンを含む多くのUIコントロールのデフォルトのIAccessible実装が用意されています。

だから、あなたができる簡単な一のトリックは、手動ボタンを-描く所有者になり、その後は正常に使用するデフォルトIAccessible実装のための標準Captionを設定することができ、そしてときに、あなたは単にCaptionが含まれていませんでしたボタンを描く。

WM_GETOBJECTメッセージを直接処理して、ボタンのデフォルトのIAccessibleの実装を取得し、それをラップして、必要なテキストを返すことができ、他のすべてをデフォルト実装に委譲することができます。例えば:

type 
    TMyAccessibleText = class(TInterfacedObject, IAccessible) 
    private 
    fAcc: IAccessible; 
    fAccessibleText: string; 
    public: 
    constructor Create(Acc: IAccessible; AccessibleText: string); 

    function QueryInterface(const IID: TGUID; out Obj): HResult; virtual; stdcall; 

    function GetTypeInfoCount(out Count: Integer): HResult; stdcall; 
    function GetTypeInfo(Index, LocaleID: Integer; out TypeInfo): HResult; stdcall; 
    function GetIDsOfNames(const IID: TGUID; Names: Pointer; NameCount, LocaleID: Integer; DispIDs: Pointer): HResult; stdcall; 
    function Invoke(DispID: Integer; const IID: TGUID; LocaleID: Integer; Flags: Word; var Params; VarResult, ExcepInfo, ArgErr: Pointer): HResult; stdcall; 

    function Get_accParent(out ppdispParent: IDispatch): HResult; stdcall; 
    function Get_accChildCount(out pcountChildren: Integer): HResult; stdcall; 
    function Get_accChild(varChild: OleVariant; out ppdispChild: IDispatch): HResult; stdcall; 
    function Get_accName(varChild: OleVariant; out pszName: WideString): HResult; stdcall; 
    function Get_accValue(varChild: OleVariant; out pszValue: WideString): HResult; stdcall; 
    function Get_accDescription(varChild: OleVariant; out pszDescription: WideString): HResult; stdcall; 
    function Get_accRole(varChild: OleVariant; out pvarRole: OleVariant): HResult; stdcall; 
    function Get_accState(varChild: OleVariant; out pvarState: OleVariant): HResult; stdcall; 
    function Get_accHelp(varChild: OleVariant; out pszHelp: WideString): HResult; stdcall; 
    function Get_accHelpTopic(out pszHelpFile: WideString; varChild: OleVariant; out pidTopic: Integer): HResult; stdcall; 
    function Get_accKeyboardShortcut(varChild: OleVariant; out pszKeyboardShortcut: WideString): HResult; stdcall; 
    function Get_accFocus(out pvarChild: OleVariant): HResult; stdcall; 
    function Get_accSelection(out pvarChildren: OleVariant): HResult; stdcall; 
    function Get_accDefaultAction(varChild: OleVariant; out pszDefaultAction: WideString): HResult; stdcall; 
    function accSelect(flagsSelect: Integer; varChild: OleVariant): HResult; stdcall; 
    function accLocation(out pxLeft: Integer; out pyTop: Integer; out pcxWidth: Integer; out pcyHeight: Integer; varChild: OleVariant): HResult; stdcall; 
    function accNavigate(navDir: Integer; varStart: OleVariant; out pvarEndUpAt: OleVariant): HResult; stdcall; 
    function accHitTest(xLeft: Integer; yTop: Integer; out pvarChild: OleVariant): HResult; stdcall; 
    function accDoDefaultAction(varChild: OleVariant): HResult; stdcall; 
    function Set_accName(varChild: OleVariant; const pszName: WideString): HResult; stdcall; 
    function Set_accValue(varChild: OleVariant; const pszValue: WideString): HResult; stdcall; 
    end; 

constructor TMyAccessibleText.Create(Acc: IAccessible; AccessibleText: string); 
begin 
    inherited Create; 
    fAcc := Acc; 
    fAccessibleText := AccessibleText; 
end; 

function TMyAccessibleText.QueryInterface(const IID: TGUID; out Obj): HResult; virtual; stdcall; 
begin 
    if IID = IID_IAccessible then 
    Result := inherited QueryInterface(IID, Obj) 
    else 
    Result := fAcc.QueryInterface(IID, Obj); 
end; 

function TMyAccessibleText.GetTypeInfoCount(out Count: Integer): HResult; stdcall; 
begin 
    Result := fAcc.GetTypeInfoCount(Count); 
end; 

function TMyAccessibleText.GetTypeInfo(Index, LocaleID: Integer; out TypeInfo): HResult; stdcall; 
begin 
    Result := fAcc.GetTypeInfo(Index, LocaleID, TypeInfo); 
end; 

function TMyAccessibleText.GetIDsOfNames(const IID: TGUID; Names: Pointer; NameCount, LocaleID: Integer; DispIDs: Pointer): HResult; stdcall; 
begin 
    Result := fAcc.GetIDsOfNames(IID, Names, NameCount, LocaleID, DispIDs); 
end; 

function TMyAccessibleText.Invoke(DispID: Integer; const IID: TGUID; LocaleID: Integer; Flags: Word; var Params; VarResult, ExcepInfo, ArgErr: Pointer): HResult; stdcall; 
begin 
    Result := fAcc.Invoke(DispID, IID, LocaleID, Flags, Params, VarResult, ExcepInfo, ArgErr); 
end; 

function TMyAccessibleText.Get_accParent(out ppdispParent: IDispatch): HResult; stdcall; 
begin 
    Result := fAcc.Get_accParent(ppdispParent); 
end; 

function TMyAccessibleText.Get_accChildCount(out pcountChildren: Integer): HResult; stdcall; 
begin 
    Result := fAcc.Get_accChildCount(pcountChildren); 
end; 

function TMyAccessibleText.Get_accChild(varChild: OleVariant; out ppdispChild: IDispatch): HResult; stdcall; 
begin 
    Result := fAcc.Get_accChild(varChild, ppdispChild); 
end; 

function TMyAccessibleText.Get_accName(varChild: OleVariant; out pszName: WideString): HResult; stdcall; 
begin 
    Result := fAcc.Get_accName(varChild, pszName); 
end; 

function TMyAccessibleText.Get_accValue(varChild: OleVariant; out pszValue: WideString): HResult; stdcall; 
begin 
    if varChild = CHILDID_SELF then 
    begin 
    pszValue := fAccessibleText; 
    Result := S_OK; 
    end else 
    Result := fAcc.Get_accValue(varChild, pszValue); 
end; 

function TMyAccessibleText.Get_accDescription(varChild: OleVariant; out pszDescription: WideString): HResult; stdcall; 
begin 
    Result := fAcc.Get_accDescription(varChild, pszDescription); 
end; 

function TMyAccessibleText.Get_accRole(varChild: OleVariant; out pvarRole: OleVariant): HResult; stdcall; 
begin 
    Result := fAcc.Get_accRole(varChild, pvarRole); 
end; 

function TMyAccessibleText.Get_accState(varChild: OleVariant; out pvarState: OleVariant): HResult; stdcall; 
begin 
    Result := fAcc.Get_accState(varChild, pvarState); 
end; 

function TMyAccessibleText.Get_accHelp(varChild: OleVariant; out pszHelp: WideString): HResult; stdcall; 
begin 
    Result := fAcc.Get_accHelp(varChild, pszHelp); 
end; 

function TMyAccessibleText.Get_accHelpTopic(out pszHelpFile: WideString; varChild: OleVariant; out pidTopic: Integer): HResult; stdcall; 
begin 
    Result := fAcc.Get_accHelpTopic(pszHelpFile, varChild, pidTopic); 
end; 

function TMyAccessibleText.Get_accKeyboardShortcut(varChild: OleVariant; out pszKeyboardShortcut: WideString): HResult; stdcall; 
begin 
    Result := fAcc.Get_accKeyboardShortcut(varChild, pszKeyboardShortcut); 
end; 

function TMyAccessibleText.Get_accFocus(out pvarChild: OleVariant): HResult; stdcall; 
begin 
    Result := fAcc.Get_accFocus(pvarChild); 
end; 

function TMyAccessibleText.Get_accSelection(out pvarChildren: OleVariant): HResult; stdcall; 
begin 
    Result := fAcc.Get_accSelection(pvarChildren); 
end; 

function TMyAccessibleText.Get_accDefaultAction(varChild: OleVariant; out pszDefaultAction: WideString): HResult; stdcall; 
begin 
    Result := fAcc.Get_accDefaultAction(varChild, pszDefaultAction); 
end; 

function TMyAccessibleText.accSelect(flagsSelect: Integer; varChild: OleVariant): HResult; stdcall; 
begin 
    Result := fAcc.accSelect(flagsSelect, varChild); 
end; 

function TMyAccessibleText.accLocation(out pxLeft: Integer; out pyTop: Integer; out pcxWidth: Integer; out pcyHeight: Integer; varChild: OleVariant): HResult; stdcall; 
begin 
    Result := fAcc.accLocation(pxLeft, pyTop, pcxWidth, pcyHeight, varChild); 
end; 

function TMyAccessibleText.accNavigate(navDir: Integer; varStart: OleVariant; out pvarEndUpAt: OleVariant): HResult; stdcall; 
begin 
    Result := fAcc.accNavigate(navDir, varStart, pvarEndUpAt); 
end; 

function TMyAccessibleText.accHitTest(xLeft: Integer; yTop: Integer; out pvarChild: OleVariant): HResult; stdcall; 
begin 
    Result := fAcc.accHitTest(xLeft, yTop, pvarChild); 
end; 

function TMyAccessibleText.accDoDefaultAction(varChild: OleVariant): HResult; stdcall; 
begin 
    Result := fAcc.accDoDefaultAction(varChild); 
end; 

function TMyAccessibleText.Set_accName(varChild: OleVariant; const pszName: WideString): HResult; stdcall; 
begin 
    Result := fAcc.Set_accName(varChild, pszName); 
end; 

function TMyAccessibleText.Set_accValue(varChild: OleVariant; const pszValue: WideString): HResult; stdcall; 
begin 
    if varChild = CHILDID_SELF then 
    begin 
    fAccessibleText := pszValue; 
    Result := S_OK; 
    end else 
    Result := fAcc.Set_accValue(varChild, pszValue); 
end; 
のTGraphicから派生形態の画像についても同様

type 
    TBitBtn = class(Vcl.Buttons.TBitBtn) 
    private 
    procedure WMGetObject(var Message: TMessage): message WM_GETOBJECT; 
    public 
    MyAccessibleText: string; 
    end; 

    TMyForm = class(TForm) 
    Button1: TBitBtn; 
    ... 
    procedure FormCreate(Sender: TObject); 
    ... 
    end; 

procedure TMyForm.FormCreate(Sender: TObject); 
begin 
    Button1.MyAccessibleText := 'There is an image here'; 
end; 

procedure TBitBtn.WMGetObject(var Message: TMessage); 
var 
    Acc: IAccessible; 
begin 
    inherited; 
    if (Message.LParam = OBJID_CLIENT) and (Message.Result > 0) and (Caption = '') and (MyAccessibleText <> '') then 
    begin 
    if ObjectFromLresult(Message.Result, IAccessible, Message.WParam, Acc) = S_OK then 
    begin 
     Acc := TMyAccessibleText.Create(Acc, MyAccessibleText) as IAccessible; 
     Message.Result := LresultFromObject(IAccessible, Message.WParam, Acc); 
    end; 
    end; 
end; 

。オブジェクトがフォーカスを取得したときに何を言うべきかをスクリーンリーダーに伝えるにはどうすればよいですか?

まず、TGraphicはコンポーネントクラスではありません。これは、TPictureによって使用される画像データのラッパーであり、それ自体は例えばTImageによって使用されるヘルパーです。代わりにTGraphicControlを意味すると仮定します(TImageから派生します)。

TGraphicControlベースのコンポーネントは、独自のウィンドウを持たないため、デフォルトでスクリーンリーダーに直接アクセスすることはできず、OS自体にも知られていません。

スクリーンリーダーをグラフィカルコントロールとやり取りする場合は、Parentコンポーネント(ウィンドウはあります)からIAccessibleの完全実装を提供し、そのグラフィカルな子どもに関する追加のアクセシビリティ情報を公開する必要があります。

私はIAccessibleラッパーを調べましたが、できる限り使用しているすべてのコントロールを拡張したくないです。

申し訳ありませんが、必要な処理を行うサードパーティの実装が見つからない限り、必要があります。 VCLは単にIAccessibleの機能を実装していないため、OSが提供する機能を超えてカスタマイズする必要がある場合は、独自のコードで手動で実装する必要があります。

+0

@KenWhite:OS自体は、ボタンを含む多くの標準UIコントロールのデフォルト実装を提供します。 –

+0

@KenWhite:追加のブックマークとして、[DelphiでアクセシブルなUIコンポーネントを作成する](http://stackoverflow.com/questions/16320914)[my answer](http://stackoverflow.com/a/16322828/65863)を参照してください。 /)は数年前からです。 –

+0

私はそれを見るのを完全に忘れてしまった。私はちょうど見て、私はそれをupvotedしているだけでなく、質問が好きだったので、私は参照としてそれを持っていただろう。私は年を取る必要があります。 :-) 念押し有難う。 –

関連する問題