Example #1
0
LRESULT
CALLBACK
DetourWindowProc ( _In_  HWND   hWnd,
                   _In_  UINT   uMsg,
                   _In_  WPARAM wParam,
                   _In_  LPARAM lParam )
{
  // Block keyboard input to the game while the console is visible
  if (uMsg == WM_INPUT && ad::InputManager::Hooker::getInstance ()->isVisible ())
    return 0;


  // Allow the game to run in the background
  if (uMsg == WM_ACTIVATEAPP) {
    bool last_active = window.active;

    window.active = wParam;

    //
    // The window activation state is changing, among other things we can take
    //   this opportunity to setup a special framerate limit.
    //
    if (window.active != last_active) {
      eTB_CommandProcessor* pCommandProc =
        SK_GetCommandProcessor           ();

#if 0
      eTB_CommandResult     result       =
        pCommandProc->ProcessCommandLine ("TargetFPS");

      eTB_VarStub <float>* pOriginalLimit = (eTB_VarStub <float>*)result.getVariable ();
#endif
      // Went from active to inactive (enforce background limit)
      if (! window.active)
        pCommandProc->ProcessCommandFormatted ("TargetFPS %f", config.render.background_fps);

      // Went from inactive to active (restore foreground limit)
      else
        pCommandProc->ProcessCommandFormatted ("TargetFPS %f", config.render.foreground_fps);
    }

    // Unrestrict the mouse when the app is deactivated
    if ((! window.active) && config.render.allow_background) {
      LONG dwStyle   = GetWindowLong (ad::RenderFix::hWndDevice, GWL_STYLE);
      LONG dwStyleEx = GetWindowLong (ad::RenderFix::hWndDevice, GWL_EXSTYLE);

      dwStyle   &= ~(WS_CAPTION | WS_THICKFRAME | WS_MINIMIZE | WS_MAXIMIZE | WS_SYSMENU);
      dwStyleEx &= ~(WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE);

      SetWindowLong (ad::RenderFix::hWndDevice, GWL_STYLE,   dwStyle);
      SetWindowLong (ad::RenderFix::hWndDevice, GWL_EXSTYLE, dwStyleEx);

      SetWindowPos  ( ad::RenderFix::hWndDevice,
                        NULL,
                          0,0,ad::RenderFix::width,ad::RenderFix::height,
                            SWP_FRAMECHANGED |
                            SWP_NOZORDER     | SWP_NOOWNERZORDER );

      ClipCursor_Original (nullptr);
    }

    // Restore it when the app is activated
    else {
      ClipCursor_Original (&window.cursor_clip);
    }

    if (config.render.allow_background) {
      CallWindowProc (original_wndproc, hWnd, uMsg, FALSE, ad::RenderFix::dwRenderThreadID);
      CallWindowProc (original_wndproc, hWnd, uMsg, TRUE,  ad::RenderFix::dwRenderThreadID);
      //window.activating = true;
      return 0;
    }
  }


  // Don't let the game do anything with the mouse or keyboard when
  //   the game is not active
  if (config.render.allow_background) {
    if ((! window.active) && uMsg >= WM_MOUSEFIRST && uMsg <= WM_MOUSELAST)
      return 0;

    if ((! window.active) && uMsg >= WM_KEYFIRST && uMsg <= WM_KEYLAST)
      return 0;
  }


  if (uMsg >= WM_MOUSEFIRST && uMsg <= WM_MOUSELAST) {
    static POINT last_p = { LONG_MIN, LONG_MIN };

    POINT p;

    p.x = MAKEPOINTS (lParam).x;
    p.y = MAKEPOINTS (lParam).y;

    if (/*game_state.needsFixedMouseCoords () &&*/config.render.aspect_correction) {
      // Only do this if cursor actually moved!
      //
      //   Otherwise, it tricks the game into thinking the input device changed
      //     from gamepad to mouse (and changes buessagetton icons).
      if (last_p.x != p.x || last_p.y != p.y) {
        ad::InputManager::CalcCursorPos (&p);

        last_p = p;
      }

      return CallWindowProc (original_wndproc, hWnd, uMsg, wParam, MAKELPARAM (p.x, p.y));
    }

    last_p = p;
  }

  return CallWindowProc (original_wndproc, hWnd, uMsg, wParam, lParam);
}
Example #2
0
LRESULT
CALLBACK
DetourWindowProc ( _In_  HWND   hWnd,
                   _In_  UINT   uMsg,
                   _In_  WPARAM wParam,
                   _In_  LPARAM lParam )
{
  bool last_active = pp::window.active;

  pp::window.active = GetForegroundWindow_Original () == pp::window.hwnd/* ||
                      GetForegroundWindow_Original () == nullptr*/;

  bool console_visible   =
    pp::InputManager::Hooker::getInstance ()->isVisible ();

  bool background_render =
    config.render.allow_background && (! pp::window.active);

  //
  // The window activation state is changing, among other things we can take
  //   this opportunity to setup a special framerate limit.
  //
  if (pp::window.active != last_active) {
    eTB_CommandProcessor* pCommandProc =
      SK_GetCommandProcessor           ();

#if 0
    eTB_CommandResult     result       =
      pCommandProc->ProcessCommandLine ("TargetFPS");

    eTB_VarStub <float>* pOriginalLimit = (eTB_VarStub <float>*)result.getVariable ();
#endif

#if 0
    // Went from active to inactive (enforce background limit)
    if (! pp::window.active)
      pCommandProc->ProcessCommandFormatted ("TargetFPS %f", config.window.background_fps);

    // Went from inactive to active (restore foreground limit)
    else {
      pCommandProc->ProcessCommandFormatted ("TargetFPS %f", config.window.foreground_fps);
    }
#endif

#if 0
    // Unrestrict the mouse when the app is deactivated
    if ((! pp::window.active) && config.render.allow_background) {
      ClipCursor_Original (nullptr);
      SetCursorPos        (pp::window.cursor_pos.x, pp::window.cursor_pos.y);
      ShowCursor          (TRUE);
    }

    // Restore it when the app is activated
    else {
      GetCursorPos        (&pp::window.cursor_pos);
      ShowCursor          (FALSE);
      ClipCursor_Original (&pp::window.cursor_clip);
    }
#endif
  }

#if 0
  // Ignore this event
  if (uMsg == WM_MOUSEACTIVATE && config.render.allow_background) {
    return DefWindowProc (hWnd, uMsg, wParam, lParam);
  }

  // Allow the game to run in the background
  if (uMsg == WM_ACTIVATEAPP || uMsg == WM_ACTIVATE || uMsg == WM_NCACTIVATE /*|| uMsg == WM_MOUSEACTIVATE*/) {
    if (config.render.allow_background) {
      // We must fully consume one of these messages or audio will stop playing
      //   when the game loses focus, so do not simply pass this through to the
      //     default window procedure.
      return 0;//DefWindowProc (hWnd, uMsg, wParam, lParam);
    }
  }
#endif

  // Block keyboard input to the game while the console is visible
  if (console_visible/* || background_render*/) {
    // Only prevent the mouse from working while the window is in the bg
    //if (background_render && uMsg >= WM_MOUSEFIRST && uMsg <= WM_MOUSELAST)
      //return DefWindowProc (hWnd, uMsg, wParam, lParam);

    if (uMsg >= WM_KEYFIRST && uMsg <= WM_KEYLAST)
      return DefWindowProc (hWnd, uMsg, wParam, lParam);

    // Block RAW Input
    if (uMsg == WM_INPUT)
      return DefWindowProc (hWnd, uMsg, wParam, lParam);
  }

#if 0
  // Block the menu key from messing with stuff*
  if (config.input.block_left_alt &&
      (uMsg == WM_SYSKEYDOWN || uMsg == WM_SYSKEYUP)) {
    // Make an exception for Alt+Enter, for fullscreen mode toggle.
    //   F4 as well for exit
    if (wParam != VK_RETURN && wParam != VK_F4)
      return DefWindowProc (hWnd, uMsg, wParam, lParam);
  }
#endif

  // What an ugly mess, this is crazy :)
  if (config.input.cursor_mgmt) {
    extern bool IsControllerPluggedIn (UINT uJoyID);

    struct {
      POINTS pos      = { 0 }; // POINT (Short) - Not POINT plural ;)
      DWORD  sampled  = 0UL;
      bool   cursor   = true;

      int    init     = false;
      int    timer_id = 0x68992;
    } static last_mouse;

   auto ActivateCursor = [](bool changed = false)->
    bool
     {
       bool was_active = last_mouse.cursor;

       if (! last_mouse.cursor) {
         while (ShowCursor (TRUE) < 0) ;
         last_mouse.cursor = true;
       }

       if (changed)
         last_mouse.sampled = timeGetTime ();

       return (last_mouse.cursor != was_active);
     };

   auto DeactivateCursor = []()->
    bool
     {
       if (! last_mouse.cursor)
         return false;

       bool was_active = last_mouse.cursor;

       if (last_mouse.sampled <= timeGetTime () - config.input.cursor_timeout) {
         while (ShowCursor (FALSE) >= 0) ;
         last_mouse.cursor = false;
       }

       return (last_mouse.cursor != was_active);
     };

    if (! last_mouse.init) {
      SetTimer (hWnd, last_mouse.timer_id, config.input.cursor_timeout / 2, nullptr);
      last_mouse.init = true;
    }

    bool activation_event =
      (uMsg == WM_MOUSEMOVE);

    // Don't blindly accept that WM_MOUSEMOVE actually means the mouse moved...
    if (activation_event) {
      const short threshold = 2;

      // Filter out small movements
      if ( abs (last_mouse.pos.x - GET_X_LPARAM (lParam)) < threshold &&
           abs (last_mouse.pos.y - GET_Y_LPARAM (lParam)) < threshold )
        activation_event = false;

      last_mouse.pos = MAKEPOINTS (lParam);
    }

    // We cannot use WM_KEYDOWN as a condition, because the game is constantly
    //   flooding the message pump with this message !!!
    if (config.input.activate_on_kbd)
      activation_event |= ( uMsg == WM_CHAR       ||
                            uMsg == WM_SYSKEYDOWN ||
                            uMsg == WM_SYSKEYUP );

    if (activation_event)
      ActivateCursor (true);

    else if (uMsg == WM_TIMER && wParam == last_mouse.timer_id) {
      if (IsControllerPluggedIn (config.input.gamepad_slot))
        DeactivateCursor ();

      else
        ActivateCursor ();
    }
  }

#if 0
  // The game can process WM_CHAR, rather than these events that
  //   fire at a ridiculous rate...
  if (uMsg >= WM_KEYFIRST && uMsg <= WM_KEYLAST && uMsg != WM_CHAR)
    return 0;
#endif

  //
  // This isn't much better than what NISA was already doing
  //   with their keybd_event spam.
  //
  if (config.input.alias_wasd && (uMsg == WM_KEYDOWN || uMsg == WM_KEYUP))
  {
    DWORD dwFlags = (uMsg == WM_KEYUP ? KEYEVENTF_KEYUP :
                                        0UL);
    switch (wParam)
    {
      case VK_UP:
        keybd_event_Original ('W', 0, dwFlags, (ULONG_PTR)nullptr);
        break;
      case VK_DOWN:
        keybd_event_Original ('S', 0, dwFlags, (ULONG_PTR)nullptr);
        break;
      case VK_LEFT:
        keybd_event_Original ('A', 0, dwFlags, (ULONG_PTR)nullptr);
        break;
      case VK_RIGHT:
        keybd_event_Original ('D', 0, dwFlags, (ULONG_PTR)nullptr);
        break;
    }
  }

  return CallWindowProc (pp::window.WndProc_Original, hWnd, uMsg, wParam, lParam);
}