Advertisement
alaestor

window cast

Dec 29th, 2018
2,583
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 7.29 KB | None | 0 0
  1. /*
  2.     2018 Window Cast
  3.     http://discord.futuregadgetlab.net
  4.  
  5.     full multi-monitor support
  6.  
  7.     HOTKEYS:
  8.     [winkey + numpad 1~9] to move and resize selected window
  9.     [winkey + numpad 5] to toggle maximizing window
  10.     [winkey + numpad 0] bring window to middle resized 800x600
  11.     [winkey + period] to print some window debug info
  12.  
  13.     set "verbose" to false to avoid spam and disable period debug
  14. */
  15.  
  16.  
  17.  
  18.  
  19.  
  20. #define WINVER _WIN32_WINNT_WIN7 // windows vista can fuck off
  21. #define WIN32_LEAN_AND_MEAN // windows junk can fuck off
  22. #define NO_STRICT // windows types can fuck off
  23.  
  24. #include <iostream>
  25. #include <stdexcept>
  26. //#include <string>
  27. #include <windows.h>
  28.  
  29. static constexpr const bool verbose{ true };
  30.  
  31.  
  32.  
  33. class ForegroundWindow
  34. {
  35.     const void* fgw;
  36.  
  37.     public:
  38.     [[nodiscard]] operator const void*() const { return fgw; }
  39.     [[nodiscard]] operator void*(){ return const_cast< void* >(fgw); }
  40.  
  41.     ForegroundWindow()
  42.     : fgw(GetForegroundWindow())
  43.     {
  44.         if (fgw == nullptr) throw std::runtime_error(
  45.             "Couldn't obtain foreground window");
  46.  
  47.         if constexpr (verbose) std::cout
  48.             << "\tForeground window obtained" << std::endl;
  49.     }
  50. };
  51.  
  52.  
  53.  
  54. typedef std::pair<long, long> Coordinate;
  55. typedef Coordinate Dimensions;
  56.  
  57. class MonitorInfoFromWindow
  58. {
  59.     typedef MONITORINFOEXA MonitorInfo_t;
  60.  
  61.     [[nodiscard]] auto check(const void* hwnd)
  62.     {
  63.         if (hwnd == nullptr) throw std::invalid_argument("hwnd was null!");
  64.         else return const_cast< void* >(hwnd);
  65.     }
  66.  
  67.     [[nodiscard]] MonitorInfo_t getMonitorInfo()
  68.     {
  69.         MonitorInfo_t monitorInfo{};
  70.         monitorInfo.cbSize = sizeof(MonitorInfo_t);
  71.         if (monitor == nullptr) throw std::runtime_error(
  72.             "MonitorFromWindow returned null");
  73.  
  74.         GetMonitorInfoA(const_cast< void* >(monitor), &monitorInfo);
  75.  
  76.         return monitorInfo;
  77.     }
  78.  
  79.     public:
  80.     const void* monitor;
  81.     const MonitorInfo_t info;
  82.     const decltype(MonitorInfo_t::szDevice)& name;
  83.     Coordinate origin;
  84.     Dimensions workspaceDimensions;
  85.  
  86.     MonitorInfoFromWindow(const void* hwnd) :
  87.         monitor(MonitorFromWindow(check(hwnd), MONITOR_DEFAULTTONEAREST)),
  88.         info(getMonitorInfo()),
  89.         name(info.szDevice),
  90.         origin(info.rcMonitor.left, info.rcMonitor.top),
  91.         workspaceDimensions(
  92.             info.rcWork.right - info.rcWork.left,
  93.             info.rcWork.bottom - info.rcWork.top)
  94.     {
  95.         if constexpr (verbose) std::cout
  96.             << "\ton \" " << name << " \""
  97.             << " with dimensions "
  98.             << workspaceDimensions.first << "x" << workspaceDimensions.second
  99.             << " at origin "
  100.             << '(' << origin.first << ',' << origin.second << ')'
  101.             << std::endl;
  102.     }
  103. };
  104.  
  105.  
  106.  
  107.  
  108. void moveWindow(const void* fgw, const Coordinate& orig, const Dimensions& dim)
  109. {
  110.     const auto& [dimension_x, dimension_y]{ dim };
  111.     const auto& [origin_x, origin_y]{ orig };
  112.     if (!SetWindowPos(
  113.         const_cast< void* >(fgw),
  114.         HWND_TOP, // it seems HWND_TOPMOST is "always ontop"
  115.         origin_x, origin_y,
  116.         dimension_x, dimension_y,
  117.         SWP_SHOWWINDOW)) throw std::runtime_error(
  118.             "Couldn't set window position");
  119.  
  120.     if constexpr (verbose) std::cout
  121.         << "\tmoved to origin "
  122.         << '(' << origin_x << ',' << origin_y << ')'
  123.         << " with dimensions "
  124.         << dimension_x << "x" << dimension_y
  125.         << std::endl;
  126. }
  127.  
  128.  
  129.  
  130.  
  131. enum Pos
  132. {
  133.     Top = (1 << 0),
  134.     Bottom = (1 << 1),
  135.     Left = (1 << 2),
  136.     Right = (1 << 3)
  137. };
  138.  
  139. [[nodiscard]] Pos operator|(Pos a, Pos b)
  140. { return Pos( int( a ) | int( b ) ); }
  141.  
  142. class Position
  143. {
  144.     const bool top:1;
  145.     const bool bottom:1;
  146.     const bool left:1;
  147.     const bool right:1;
  148.  
  149.     bool reserved:4; // padding
  150.  
  151.     public:
  152.  
  153.     [[nodiscard]] bool isBottom() const { return bottom; }
  154.     [[nodiscard]] bool isRight() const { return right; }
  155.     [[nodiscard]] bool isVertical() const { return top || bottom; }
  156.     [[nodiscard]] bool isHorizontal() const { return left || right; }
  157.  
  158.     Position(Pos p) :
  159.         top((p & Pos::Top)),
  160.         bottom((p & Pos::Bottom)),
  161.         left((p & Pos::Left)),
  162.         right((p & Pos::Right))
  163.     {
  164.         if ((top && bottom) || (left && right)) throw std::invalid_argument(
  165.             "Conflicting position arguments");
  166.  
  167.         ForegroundWindow fgw;
  168.         MonitorInfoFromWindow info(fgw);
  169.  
  170.         auto& origin{ info.origin };
  171.         auto& [origin_x, origin_y]{ origin };
  172.  
  173.         auto& dimensions{ info.workspaceDimensions };
  174.         auto& [dimension_x, dimension_y]{ dimensions };
  175.  
  176.         if (isBottom()) origin_y += dimension_y / 2;
  177.         if (isRight()) origin_x += dimension_x / 2;
  178.         if (isVertical()) dimension_y /= 2;
  179.         if (isHorizontal()) dimension_x /= 2;
  180.  
  181.         moveWindow(fgw, origin, dimensions);
  182.     }
  183. };
  184.  
  185.  
  186.  
  187.  
  188. void toggleMaximize()
  189. {
  190.     ForegroundWindow fgw;
  191.     WINDOWPLACEMENT wp{};
  192.     wp.length = sizeof(wp);
  193.     if (!GetWindowPlacement(fgw, &wp)) throw std::runtime_error(
  194.         "Couldn't get window placement");
  195.  
  196.     wp.showCmd == SW_MAXIMIZE || wp.showCmd == SW_SHOWMAXIMIZED ?
  197.         ShowWindow(fgw, SW_RESTORE) : ShowWindow(fgw, SW_SHOWMAXIMIZED);
  198.  
  199.     if constexpr (verbose) std::cout << '\t' <<
  200.         (wp.showCmd == SW_MAXIMIZE || wp.showCmd == SW_SHOWMAXIMIZED ?
  201.             "restored" : "maximized") << " window" << std::endl;
  202. }
  203.  
  204.  
  205.  
  206. void center()
  207. {
  208.     ForegroundWindow fgw;
  209.     MonitorInfoFromWindow info(fgw);
  210.  
  211.     auto& origin{ info.origin };
  212.     auto& [origin_x, origin_y]{ origin };
  213.  
  214.     auto& dimensions{ info.workspaceDimensions };
  215.     auto& [dimension_x, dimension_y]{ dimensions };
  216.  
  217.     origin_x += dimension_x / 3;
  218.     origin_y += dimension_y / 3;
  219.     dimension_x = 800;
  220.     dimension_y = 600;
  221.  
  222.     moveWindow(fgw, origin, dimensions);
  223. }
  224.  
  225.  
  226.  
  227.  
  228. void test()
  229. {
  230.     if constexpr (verbose)
  231.     {
  232.         ForegroundWindow fgw;
  233.         char t[MAX_PATH]{ '\0' };
  234.         GetWindowText(fgw, t, sizeof(t));
  235.         std::cout << "\tnamed \" " << t << " \"" << std::endl;
  236.         MonitorInfoFromWindow info(fgw);
  237.     }
  238. }
  239.  
  240.  
  241.  
  242.  
  243. // TODO "always on top" toggle via (win + numpad asterisk)?
  244.  
  245. int main([[maybe_unused]] int argc, [[maybe_unused]] char* argv[])
  246. {
  247.     // set up hotkeys
  248.     for (unsigned int k = VK_NUMPAD0; k <= VK_NUMPAD9; ++k)
  249.     {
  250.         if (!RegisterHotKey(nullptr, 0, MOD_NOREPEAT | MOD_WIN, k))
  251.             throw std::runtime_error("Failed to bind hotkey");
  252.     }
  253.  
  254.     // set up test() function hotkey if we're verbose
  255.     if constexpr (verbose)
  256.     {
  257.         if (!RegisterHotKey(nullptr, 0, MOD_NOREPEAT | MOD_WIN, VK_DECIMAL))
  258.             throw std::runtime_error("Failed to bind testing hotkey");
  259.     }
  260.  
  261.     // get response when a hotkey is pressed
  262.     MSG msg{};
  263.     while (GetMessage(&msg, nullptr, 0, 0) > 0)
  264.     {
  265.         if (msg.message == WM_HOTKEY)
  266.         {
  267.             const auto vKey{ msg.lParam >> 16 }; // high order bits is vkey
  268.             if constexpr (verbose) std::cout
  269.                 << "\n\tkey " << vKey << " pressed" << std::endl;
  270.  
  271.             try
  272.             {
  273.                 switch (vKey)
  274.                 {
  275.                 case VK_NUMPAD0: center(); break;
  276.                 case VK_NUMPAD1: Position(Pos::Bottom | Pos::Left); break;
  277.                 case VK_NUMPAD2: Position(Pos::Bottom); break;
  278.                 case VK_NUMPAD3: Position(Pos::Bottom | Pos::Right); break;
  279.                 case VK_NUMPAD4: Position(Pos::Left); break;
  280.                 case VK_NUMPAD5: toggleMaximize(); break;
  281.                 case VK_NUMPAD6: Position(Pos::Right); break;
  282.                 case VK_NUMPAD7: Position(Pos::Top | Pos::Left); break;
  283.                 case VK_NUMPAD8: Position(Pos::Top); break;
  284.                 case VK_NUMPAD9: Position(Pos::Top | Pos::Right); break;
  285.                 case VK_DECIMAL: test(); break;
  286.                 default: throw std::runtime_error("got unexpected hotkey!");
  287.                 };
  288.             }
  289.             catch (...) // all the things
  290.             {
  291.                 // TODO this part. I'm lazy. just swallow errors
  292.                 std::cerr << "[ERROR] caught exception" << std::endl;
  293.             }
  294.         }
  295.  
  296.         TranslateMessage(&msg);
  297.         DispatchMessage(&msg);
  298.     }
  299.  
  300.     return 0;
  301. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement