1

Short story

A game is started fullscreen but is a fullscreen directX window. The game supports windowed but I have to do it manually. I made a program in Delphi that stretch/resize any window to fit the screen (with use of a system-wide hotkey) without border and caption so it looks like a fullscreen but doesn't trigger direct hardware access. This is important because I'm using a DisplayLink adapter that doesn't support the tricks used by direct hardware access but want to play it full screen without ugly borders. I can resize any window except a fullscreen DirectX window, I have to manually change the full screen mode to windowed, this is what I want to automate.

Long story (scroll down if you want to know the question)

I have a DisplayLink adapter with TV-screen 5 Meters away from my computer. I want to use it to run games so I can play games from the couch. The DisplayLink driver however cannot play most games full screen because most games bypass the Desktop Window Manager (DWM) to access the graphics hardware directly when full screen.

This is a common/known problem with DisplayLink. In windowed mode the adapter performs very well so I thought to write a little program in Delphi to maximize a windowed directx screen to full screen without going full screen by maximizing it, stretching the window to full screen instead.

The program I made works pretty well however only when the directx screen is already windowed (the game starts full screen so I have to click once the windowed icon to make it windowed). The game already has an option to make it windowed at launch but with less fixed resolution possibilities. I want to automate this process when launched full screen. I want to change the directx screen to windowed and after this resize/stretch it to full screen without maximizing it.

How the program works

The program defines a system wide keyboard hotkey. When pressing the hotkey the program maximize any active foreground window (windows API getForeGroundWindow()) by stretching it to full screen and makes it a borderless window so it looks like full screen. This enable you also to run the game on any screen you like and not only on the main screen of your system. When pressing the hotkey again, the window returns to it's previous state (toggle). Before applying the 'patch', it also checks the type of window, so it cannot be used on non-resizable windows.

Question

I know the handle of the window that must be stretched/resized to fullscreen. When it is a fullscreen DirectX window I can't do anything with unless it is windowed. How can I change it's state to windowed by sending messages to this window handle (sendMessage()). Is this possible anyway?

Some code (to give you some idea what's happening behind the scenes)

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;

Some screenshots

Some screenshots

Notice: In this picture there is a typo, ActiveX must be DirectX ;-)

More info about the DisplayLink problem: http://support.displaylink.com/knowledgebase/articles/543922-games-do-not-work-on-windows-with-displaylink-soft

Codebeat
  • 6,501
  • 6
  • 57
  • 99
  • 1
    If I were you if would move the short story to the top so that people do not think this is not a programming question. Currently the first two paragraphs give the impression that this question belongs on SuperUser (whereas it is in the right place here as shown by the rest of the question). – Pascal Cuoq Aug 18 '15 at 03:18
  • Thanks for the comment. I change it right away! – Codebeat Aug 18 '15 at 03:20
  • Is the title OK anyway? – Codebeat Aug 18 '15 at 03:40
  • no-one will confuse this for a non-programming-related question. – Pascal Cuoq Aug 18 '15 at 03:49
  • I'm afraid this is not possible. Main purpose of running a game in FullScreen mode is that by doing so Windows unload its resources that are otherwise required for rendering standard desktop windows and such. Now on older computers this could inprove the game performance for quite a but but on modern computers there isn't so much noticeable difference. So best bet for you is to run your game in borderless maximized window. To do this for your specific game (Tracmania) follow instructions here: https://forum.maniaplanet.com/viewtopic.php?f=9&t=17812 – SilverWarior Aug 18 '15 at 04:05
  • I don't like to hear that it is impossible to do ;-) Joking ;-) Thanks for the quick comment and pointing me into the right direction. Well, although your comment is very game specific, they talk about ManiaPlanet which is TrackMania but the newer version and brings me up the idea of a hotkey. I have tried ALT+ENTER (like at a command line prompt to make it full screen) and it's working in both versions! Because I use a hotkey to trigger the resize behaviour I have to wait until all keys are up to send ALT+ENTER (emulate keyboard) to the window. Just have to figure out how to wait until keysup – Codebeat Aug 18 '15 at 04:50
  • ...... But when there is a better solution I want to know it. Anyway, is ALT+ENTER a standard way to maximize/restore Windows games? – Codebeat Aug 18 '15 at 05:05
  • Sorry for not commenting before but for some reason SO didn't notify me of the new comments here. To answer your last comment. ALT+ENTER is generally suggested key combination for switching windows application from windowed to full screen mode. Now this isn't implemented on an OS level but instead is suggested practice. And because of that most windows based applications that support full screen mode have the mentioned key shortcut binded to proper method to switch between windowed and full screen mode and vice versa. ... – SilverWarior Aug 21 '15 at 20:15
  • ... And yes most games have this implemented. Exceptions are mostly of older games where switching between full screen mode to windowed causes the game graphical engine to crash as it does not have proper mechanisms implemented to support this. – SilverWarior Aug 21 '15 at 20:17
  • As for your workaround by simulating ALT+ENTER. Nice way of you thinking out of the box. Now how are you trying to emulate keyboard in this case? Are you doing system wide keyboard key press emulation or are you generating and sending specific windows messages to specific window? – SilverWarior Aug 21 '15 at 20:24
  • Wow, thank you so much for all the comments right here, really appreciate it. I'm at a really good progress right now and decide to make it donationware when it is finished so you can use it for free if you want. It's not only usable for DisplayLink, you can also use it without. I also add some extra hotkeys to move the window from screen to screen, it's working fantastic! Because you cannot move a fullscreen DirectX window, I have to detect it and change it's state to windowed. Because sending a key combination to a focused window, it does not work when keys are still down....... – Codebeat Aug 22 '15 at 00:51
  • .... because of using the key combination (hotkey) to maximize or move the screen. I need to to know all keys are up before I can send the 'ALT+ENTER' to the DirectX window, otherwise it will fail. See also this question for more information: http://stackoverflow.com/questions/32143747/windows-api-wait-until-all-keyboard-keys-are-released-system-wide . I have read that 'ALT+ENTER' is a common key of DirectX to maximize/border a window but some game developers remove this support because of problems. The app will not work for every game but most of them. ...... – Codebeat Aug 22 '15 at 00:52
  • .... The app already has a meganism to detect wrong states so this hasn't have to be problem, it simply doesn't work but doesn't show any negative side-effects. I'm being aware that some games already support a borderless window as option but older games doesn't have it. – Codebeat Aug 22 '15 at 00:52
  • @Erwinus You still didn't answer me which way do you use for simulating ALT+ENTER key combination. Also you should be very careful when moving any game windows from one screen to another. If both screens are connected to the same graphics card there probably won't be any problem. But if they are connected to separate graphics cards (dual graphics card setups, or computers with both integrated and dedicated graphics card) you could cause great havoc. – SilverWarior Aug 22 '15 at 16:23
  • @SlverWarior: I'm using the class that I made in the past for a extended remote controller program for a Pinnacle TV remote, in basic it uses the Windows API function keybd_event() to simulate a (virtual) key. Moving a game from one screen to another is NOT a problem as long the game is not maximized by DirectX. WDM handles this perfectly. However, when you try to move a DirectX window when maximized, it's moves only the frame of the window so I need to detect this state and change it to windowed before moving the window. The 'simple window management option' in windows is also not a solution – Codebeat Aug 23 '15 at 19:33
  • .... The 'simple window management option' in Windows makes the same mistake by moving the frame of the window instead of the screen. You can try this yourself by using a hotkey WIN+SHIFT+LEFT (or RIGHT) when an game is running full screen. I'm using WIn7 Prof 64bit anyway. – Codebeat Aug 23 '15 at 19:36

0 Answers0