ショートストーリー
ゲームはフルスクリーンで開始されますが、フルスクリーンの directX ウィンドウです。ゲームはウィンドウをサポートしていますが、手動で行う必要があります。Delphi で、境界線とキャプションなしで(システム全体のホットキーを使用して)画面に合わせてウィンドウを拡大/サイズ変更するプログラムを作成したため、フルスクリーンのように見えますが、ハードウェアへの直接アクセスはトリガーされません。ハードウェアへの直接アクセスで使用されるトリックをサポートしていない DisplayLink アダプターを使用しているが、醜い境界線なしでフルスクリーンで再生したいので、これは重要です。全画面表示の DirectX ウィンドウ以外の任意のウィンドウのサイズを変更できます。手動で全画面表示モードをウィンドウ表示に変更する必要があります。これを自動化したいのです。
長い話(質問を知りたい場合は下にスクロールしてください)
コンピューターから 5 メートル離れた場所に TV 画面を備えた DisplayLink アダプターがあります。ソファからゲームをプレイできるように、それを使用してゲームを実行したいと考えています。ただし、ほとんどのゲームはデスクトップ ウィンドウ マネージャー (DWM) をバイパスして、フル スクリーン時にグラフィックス ハードウェアに直接アクセスするため、DisplayLink ドライバーはほとんどのゲームをフル スクリーンで再生できません。
これは、DisplayLink の一般的な既知の問題です。ウィンドウ モードでは、アダプターは非常にうまく機能するので、Delphi で小さなプログラムを作成して、ウィンドウを最大化して全画面表示にするのではなく、ウィンドウを全画面表示にする代わりに、ウィンドウを全画面表示にすることを考えました。
私が作成したプログラムはかなりうまく動作しますが、directx 画面が既にウィンドウ化されている場合にのみ機能します (ゲームはフルスクリーンで開始されるため、ウィンドウ化するにはウィンドウ化されたアイコンを 1 回クリックする必要があります)。ゲームには、起動時にウィンドウを表示するオプションが既にありますが、固定解像度の可能性は低くなります。フルスクリーンで起動したときにこのプロセスを自動化したい。directx画面をウィンドウ表示に変更したいのですが、この後、最大化せずにフルスクリーンにサイズ変更/ストレッチします。
プログラムの仕組み
プログラムは、システム全体のキーボード ホットキーを定義します。ホットキーを押すと、プログラムはアクティブなフォアグラウンド ウィンドウ (windows API getForeGroundWindow()
) をフルスクリーンに引き伸ばして最大化し、ボーダーレス ウィンドウにしてフルスクリーンのように見せます。これにより、システムのメイン画面だけでなく、好きな画面でゲームを実行することもできます。ホットキーをもう一度押すと、ウィンドウは以前の状態 (トグル) に戻ります。「パッチ」を適用する前に、ウィンドウの種類もチェックするため、サイズ変更できないウィンドウでは使用できません。
質問
フルスクリーンに拡大/サイズ変更する必要があるウィンドウのハンドルを知っています。フルスクリーンの DirectX ウィンドウの場合、ウィンドウ化されていない限り何もできません。このウィンドウ ハンドル ( ) にメッセージを送信して、状態をウィンドウ表示に変更するにはどうすればよいですかsendMessage()
。とにかくこれは可能ですか?
いくつかのコード(舞台裏で何が起こっているかを理解するため)
function TWinSpread.setWindowStyleBounds( h : hWnd; lStyle : LongInt = 0; pR : PRect = nil ) : LongInt;
var
bRestore : Boolean;
r : TRect;
pMouse : TPoint;
rStyle : TStyleStruct;
begin
Result:=0;
if( h <= 0 ) then
Exit;
bRestore:=( lStyle > 0 );
if( NOT bRestore ) then
begin
lStyle:=getWindowLong( h, GWL_STYLE );
Result:=lStyle;
lStyle:=lStyle and not WS_BORDER and not WS_SIZEBOX and not WS_DLGFRAME;
if( Assigned( pR )) then
begin
r:=pR^;
end
else begin
getWindowRect( h, r );
r:=getDisplayRect( getDisplayNumFromPoint( Point( r.left+2, r.top+2 ) ) );
end;
end
else begin
Result:=lStyle;
end;
rStyle.styleOld:=Result;
rStyle.styleNew:=lStyle;
if( Result = lStyle ) then
begin
rStyle.styleOld:=getWindowLong( h, GWL_STYLE );
end;
sendMessage( h, WM_ENTERSIZEMOVE, 0, 0 );
__restoreWindow( h );
setWindowLong( h, GWL_STYLE, lStyle );
if( NOT bRestore ) then
begin
setWindowPos( h, HWND_TOP, r.left,r.top,r.right-r.left,r.bottom-r.top, SWP_FRAMECHANGED and WS_SIZEBOX );
moveWindow( h, r.left,r.top,r.right-r.left,r.bottom-r.top, TRUE );
sendMessage( h, WM_SIZE, SIZE_RESTORED, makeLong( r.right-r.left,r.bottom-r.top ));
end
else begin
// updateWindowFrame( h );
setWindowPos( h, 0, 0,0,0,0, SWP_FRAMECHANGED or SWP_NOMOVE or SWP_NOSIZE or SWP_NOZORDER or SWP_NOOWNERZORDER );
getWindowRect( h, r );
end;
sendMessage( h, WM_EXITSIZEMOVE, 0, 0 );
sendMessage( h, WM_STYLECHANGED, GWL_STYLE, longInt( Pointer( @rStyle )));
activateWindow( h );
windows.setFocus( h );
if( __mousePresent() ) then
begin
pMouse:=__getMousePos();
// Simulate click to focus window
__setMousePos( Point( r.left+2, r.top+2 ));
mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
// restore mouse
__setMousePos( pMouse );
end;
end;
procedure TWinSpread.shHotKeyHotKey(Sender: TObject; Index: Integer);
var
h : hWnd;
sHandle : string;
lStyle : LongInt;
bNoBorder : Boolean;
begin
h:=getForeGroundWindow();
if( h <= 0 ) then
exit;
if( h = handle ) then
begin
showMessage( 'It works!' );
exit;
end;
sHandle:=ItoA( h );
if( scWinStyles.Count > 0 ) then
begin
lStyle:=AtoI( scWinStyles.list.Values[sHandle] );
if( lStyle > 0 ) then
begin
scWinStyles.list.delete( scWinStyles.list.IndexOfName(sHandle));
setWindowStyleBounds( h, lStyle );
Exit;
end;
end;
bNoBorder:=windowIsBorderless( h );
if( isMaximized( h ) or bNoBorder ) then
begin
// does not work for ActiveX fullscreen window :-(
//if( bNoBorder ) then
// setWindowSizeable( h, TRUE );
__maximizeWindow( h );
__restoreWindow( h );
showWindow( h, SW_SHOWNORMAL );
end;
if( windowIsSizeable( h ) ) then
begin
lStyle:=setWindowStyleBounds( h );
scWinStyles.list.Values[sHandle]:=ItoA( lStyle );
end
else Windows.Beep( 600, 200 );
end;
いくつかのスクリーンショット
注意: この図にはタイプミスがあります。ActiveX は DirectX でなければなりません ;-)
DisplayLink の問題に関する詳細情報: http://support.displaylink.com/knowledgebase/articles/543922-games-do-not-work-on-windows-with-displaylink-soft