diff --git a/core/include/gui_bindings/window_ctrl.hpp b/core/include/gui_bindings/window_ctrl.hpp index 1c005128..b2ba7eda 100644 --- a/core/include/gui_bindings/window_ctrl.hpp +++ b/core/include/gui_bindings/window_ctrl.hpp @@ -7,8 +7,8 @@ namespace WindowCtrl { - bool is_valid_hwnd(HWND hwnd) ; - bool is_valid_rect(HWND hwnd, RECT& rect) ; + bool is_visible_hwnd(HWND hwnd) ; + bool is_window_mode(HWND hwnd, RECT& rect) ; } struct OpenNewCurrentWindow : public BindedFuncWithCreator diff --git a/core/include/screen_metrics.hpp b/core/include/screen_metrics.hpp index f8f6143d..f74cb899 100644 --- a/core/include/screen_metrics.hpp +++ b/core/include/screen_metrics.hpp @@ -79,7 +79,7 @@ namespace ScreenMetrics { lhs.bottom == rhs.bottom ; } - inline auto is_bigger_tran(const RECT& lhs, const RECT& rhs) noexcept { + inline auto is_bigger_than(const RECT& lhs, const RECT& rhs) noexcept { return lhs.left <= rhs.left && lhs.top <= rhs.top && lhs.right >= rhs.right && lhs.bottom >= rhs.bottom ; } @@ -103,22 +103,21 @@ namespace ScreenMetrics { copy(*rect, minfo.rcMonitor) ; } - inline void get_monitor_metrics(HWND hwnd, RECT* const rect, RECT* const work_rect=NULL, HMONITOR* monitor=NULL) { - const auto hmonitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST) ; - MONITORINFO minfo ; - minfo.cbSize = sizeof(MONITORINFO) ; - if(!GetMonitorInfo(hmonitor, &minfo)) { + struct MonitorInfo { + RECT rect = {0, 0, 0, 0} ; + RECT work_rect = {0, 0, 0, 0} ; + HMONITOR hmonitor = NULL ; + } ; + inline void get_monitor_metrics(HWND hwnd, MonitorInfo& minfo) { + minfo.hmonitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST) ; + MONITORINFO native_minfo ; + native_minfo.cbSize = sizeof(MONITORINFO) ; + if(!GetMonitorInfo(minfo.hmonitor, &native_minfo)) { throw RUNTIME_EXCEPT("Could not get monitor infomation.") ; } - copy(*rect, minfo.rcMonitor) ; - - if(work_rect != NULL) { - copy(*work_rect, minfo.rcWork) ; - } - if(monitor != NULL) { - *monitor = hmonitor ; - } + copy(minfo.rect, native_minfo.rcMonitor) ; + copy(minfo.work_rect, native_minfo.rcWork) ; } namespace Debug { diff --git a/core/src/gui_bindings/easy_click.cpp b/core/src/gui_bindings/easy_click.cpp index d4690c6c..cd8a8fc2 100644 --- a/core/src/gui_bindings/easy_click.cpp +++ b/core/src/gui_bindings/easy_click.cpp @@ -86,7 +86,7 @@ namespace EsyClk } } ; - static std::vector g_objpos ; + static std::vector g_obj_points ; inline static auto& get_cache_req() { static auto g_cache_req = UIA::make_SmartCacheReq(nullptr) ; @@ -94,7 +94,7 @@ namespace EsyClk } void initialize() { - g_objpos.reserve(2048) ; + g_obj_points.reserve(2048) ; decltype(auto) cuia = UIA::get_global_cuia() ; @@ -136,7 +136,7 @@ namespace EsyClk if(LONG* ppvdata ; SUCCEEDED(SafeArrayAccessData(val.parray, reinterpret_cast(&ppvdata)))) { - g_objpos.emplace_back(ppvdata[0], ppvdata[1]) ; + g_obj_points.emplace_back(ppvdata[0], ppvdata[1]) ; SafeArrayUnaccessData(val.parray) ; } } @@ -149,6 +149,7 @@ namespace EsyClk UIA::SmartElement& elem, const RECT& window_rect, const BOOL parent_is_focasuable=FALSE) { + if(!parent_is_focasuable) { BOOL flag ; if(FAILED(elem->get_CachedIsKeyboardFocusable(&flag))) { @@ -159,6 +160,7 @@ namespace EsyClk return ; } } + RECT rect ; if(FAILED(elem->get_CachedBoundingRectangle(&rect))) { return ; @@ -168,7 +170,7 @@ namespace EsyClk return ; } - g_objpos.emplace_back( + g_obj_points.emplace_back( rect.left + (rect.right - rect.left) / 2, rect.top + (rect.bottom - rect.top) / 2) ; } @@ -283,7 +285,7 @@ namespace EsyClk return TRUE ; } - g_objpos.emplace_back( + g_obj_points.emplace_back( rect.left + (rect.right - rect.left) / 2, rect.top + (rect.bottom - rect.top) / 2) ; return TRUE ; @@ -317,10 +319,10 @@ namespace EsyClk EnumWindows(EnumWindowsProc, static_cast(procid)) ; - Utility::remove_deplication(EsyClk::g_objpos) ; + Utility::remove_deplication(EsyClk::g_obj_points) ; } - static HWND g_prehwnd = nullptr ; + static HWND g_prehwnd = NULL ; static RECT g_prerect = {0, 0, 0, 0} ; inline static bool need_update(HWND hwnd) { @@ -476,6 +478,7 @@ namespace EsyClk const std::vector& matched_list, const bool exist) { + //Handles auto delete_hdc = [] (HDC h) { if(h != nullptr) DeleteDC(h) ; } ; @@ -496,6 +499,7 @@ namespace EsyClk throw RUNTIME_EXCEPT("SelectObject") ; } + //Colors auto [bk_r, bk_g, bk_b] = Utility::hex2rgb(iParams::get_s("easy_click_font_bkcolor")) ; auto bkcolor = RGB(bk_r, bk_g, bk_b) ; @@ -522,6 +526,7 @@ namespace EsyClk throw RUNTIME_EXCEPT("SetTextColor") ; } + //Drawing auto draw = [&hdc, &delta] (auto&& str, auto&& point) { if(SetTextCharacterExtra(hdc.get(), 1) == static_cast(0x80000000)) { throw RUNTIME_EXCEPT("SetTextCharacterExtra") ; @@ -554,6 +559,7 @@ namespace EsyClk throw RUNTIME_EXCEPT("SetTextColor") ; } + //overdraw with the weak text color. for(std::size_t i = 0 ; i < hints_str.size() ; i ++) { if(matched_list[i] == 0) continue ; draw(" " + hints_str[i].substr(0, matched_list[i]), points[i]) ; @@ -561,6 +567,9 @@ namespace EsyClk } } + // [Return value] + // >= 0 : matched something + // < 0 : matched nothing inline static long match_with_hints( const KeyLogger& lgr, const std::vector& hints, @@ -619,6 +628,8 @@ namespace EsyClk static constexpr auto DRAW_INTERVAL_TIME = 600ms ; while(win_vind::update_background()) { + + // The drawing process is very heavy, so draw in the interval. if(system_clock::now() - drawn_point > DRAW_INTERVAL_TIME) { EsyClk::draw_identifiers(points, hints_str, matched_num_list, at_least_exist) ; drawn_point = system_clock::now() ; @@ -650,7 +661,7 @@ namespace EsyClk } remove_from_back(lgr, 2) ; KeyAbsorber::release_virtually(VKC_BKSPACE) ; - match_with_hints(lgr, hints, matched_num_list, at_least_exist) ; + match_with_hints(lgr, hints, matched_num_list, at_least_exist) ; //update matching list continue ; } @@ -660,7 +671,7 @@ namespace EsyClk } - long full_match_idx = match_with_hints(lgr, hints, matched_num_list, at_least_exist) ; + const auto full_match_idx = match_with_hints(lgr, hints, matched_num_list, at_least_exist) ; if(full_match_idx >= 0) { SetCursorPos(points[full_match_idx].x(), points[full_match_idx].y()) ; if(sendkey != VKC_UNDEFINED) { @@ -685,18 +696,19 @@ namespace EsyClk inline static void common_process(const unsigned char sendkey) { if(need_update(GetForegroundWindow())) { - g_objpos.clear() ; + g_obj_points.clear() ; scan_gui_objects() ; - g_hints = assign_identifiers_label(g_objpos.size()) ; + g_hints = assign_identifiers_label(g_obj_points.size()) ; g_hints_str = convert_hints_to_str(g_hints) ; } - if(!g_objpos.empty()) { + if(!g_obj_points.empty()) { update_font() ; - loop_for_key_matching(g_objpos, g_hints, g_hints_str, sendkey) ; + loop_for_key_matching(g_obj_points, g_hints, g_hints_str, sendkey) ; } + //release all keys for(auto& key : KeyAbsorber::get_pressed_list()) { KeyAbsorber::release_virtually(key) ; } @@ -782,11 +794,10 @@ void UpdateEasyClick::sprocess( return ; } - - g_objpos.clear() ; + g_obj_points.clear() ; scan_gui_objects() ; - g_hints = assign_identifiers_label(g_objpos.size()) ; + g_hints = assign_identifiers_label(g_obj_points.size()) ; g_hints_str = convert_hints_to_str(g_hints) ; } diff --git a/core/src/gui_bindings/resize_window.cpp b/core/src/gui_bindings/resize_window.cpp index 86b1f16e..0d5d0e87 100644 --- a/core/src/gui_bindings/resize_window.cpp +++ b/core/src/gui_bindings/resize_window.cpp @@ -53,10 +53,12 @@ void MinimizeCurrentWindow::sprocess( } namespace ResizeWindow { - inline static void resize_window(HWND hwnd, LONG left, LONG top, LONG width, LONG height) { - if(hwnd == NULL) { - throw RUNTIME_EXCEPT("There is not the foreground window.") ; - } + inline static void resize( + HWND hwnd, + LONG left, + LONG top, + LONG width, + LONG height) { if(!MoveWindow(hwnd, left, top, width, height, TRUE)) { throw RUNTIME_EXCEPT("Could not change window size") ; @@ -68,24 +70,24 @@ namespace ResizeWindow { } if(ScreenMetrics::width(rect) != width || ScreenMetrics::height(rect) != height) { + //If a window is Chromium browser (e.g. GoogleChrome or Microsoft Edge) and when it is full screen, + //could not resize its size, so cancel full screen. - RECT mrect ; - RECT mrect_work ; - ScreenMetrics::get_monitor_metrics(hwnd, &mrect, &mrect_work) ; + ScreenMetrics::MonitorInfo minfo ; + ScreenMetrics::get_monitor_metrics(hwnd, minfo) ; - if(!ScreenMetrics::is_bigger_tran(rect, mrect_work)) { + //Whether it is a full screen ? + if(!ScreenMetrics::is_bigger_than(rect, minfo.work_rect)) { return ; } - //If a window is Chromium browser (e.g. GoogleChrome or Microsoft Edge) and when it is full screen, - //could not resize its size, so cancel full screen. if(!SetForegroundWindow(hwnd)) { throw RUNTIME_EXCEPT("Could not set a foreground window.") ; } - //minimize once + //minimize it once KeybrdEventer::pushup(VKC_LWIN, VKC_DOWN) ; - Sleep(50) ; + Sleep(50) ; //50ms if(!MoveWindow(hwnd, left, top, width, height, TRUE)) { throw RUNTIME_EXCEPT("Could not change window size in twice.") ; @@ -115,16 +117,15 @@ void SnapCurrentWindow2Left::sprocess( throw RUNTIME_EXCEPT("There is not the foreground window.") ; } - RECT rect ; - RECT rect_work ; - ScreenMetrics::get_monitor_metrics(hwnd, &rect, &rect_work) ; + ScreenMetrics::MonitorInfo minfo ; + ScreenMetrics::get_monitor_metrics(hwnd, minfo) ; - ResizeWindow::resize_window( + ResizeWindow::resize( hwnd, - rect_work.left, - rect_work.top, - ScreenMetrics::width(rect_work) / 2, - ScreenMetrics::height(rect_work)) ; + minfo.work_rect.left, + minfo.work_rect.top, + ScreenMetrics::width(minfo.work_rect) / 2, + ScreenMetrics::height(minfo.work_rect)) ; } @@ -147,17 +148,16 @@ void SnapCurrentWindow2Right::sprocess( throw RUNTIME_EXCEPT("There is not the foreground window.") ; } - RECT rect ; - RECT rect_work ; - ScreenMetrics::get_monitor_metrics(hwnd, &rect, &rect_work) ; + ScreenMetrics::MonitorInfo minfo ; + ScreenMetrics::get_monitor_metrics(hwnd, minfo) ; - const auto half_of_width = ScreenMetrics::width(rect_work) / 2 ; - ResizeWindow::resize_window( + const auto half_of_width = ScreenMetrics::width(minfo.work_rect) / 2 ; + ResizeWindow::resize( hwnd, - rect_work.left + half_of_width, - rect_work.top, + minfo.work_rect.left + half_of_width, + minfo.work_rect.top, half_of_width, - ScreenMetrics::height(rect_work)) ; + ScreenMetrics::height(minfo.work_rect)) ; } @@ -180,16 +180,15 @@ void SnapCurrentWindow2Top::sprocess( throw RUNTIME_EXCEPT("There is not the foreground window.") ; } - RECT rect ; - RECT rect_work ; - ScreenMetrics::get_monitor_metrics(hwnd, &rect, &rect_work) ; + ScreenMetrics::MonitorInfo minfo ; + ScreenMetrics::get_monitor_metrics(hwnd, minfo) ; - ResizeWindow::resize_window( + ResizeWindow::resize( hwnd, - rect_work.left, - rect_work.top, - ScreenMetrics::width(rect_work), - ScreenMetrics::height(rect_work) / 2) ; + minfo.work_rect.left, + minfo.work_rect.top, + ScreenMetrics::width(minfo.work_rect), + ScreenMetrics::height(minfo.work_rect) / 2) ; } //SnapCurrentWindow2Bottom @@ -211,16 +210,15 @@ void SnapCurrentWindow2Bottom::sprocess( throw RUNTIME_EXCEPT("There is not the foreground window.") ; } - RECT rect ; - RECT rect_work ; - ScreenMetrics::get_monitor_metrics(hwnd, &rect, &rect_work) ; + ScreenMetrics::MonitorInfo minfo ; + ScreenMetrics::get_monitor_metrics(hwnd, minfo) ; - const auto half_of_height = ScreenMetrics::height(rect_work) / 2 ; - ResizeWindow::resize_window( + const auto half_of_height = ScreenMetrics::height(minfo.work_rect) / 2 ; + ResizeWindow::resize( hwnd, - rect_work.left, - rect_work.top + half_of_height, - ScreenMetrics::width(rect_work), + minfo.work_rect.left, + minfo.work_rect.top + half_of_height, + ScreenMetrics::width(minfo.work_rect), half_of_height) ; } @@ -228,36 +226,38 @@ void SnapCurrentWindow2Bottom::sprocess( namespace ResizeWindow { static std::unordered_map g_mrects ; + using ordered_hwnd_t = std::map ; - static std::unordered_map g_ordered_hwnd ; + static std::unordered_map g_m_ordered_hwnd ; static BOOL CALLBACK EnumWindowsProcForArrangement(HWND hwnd, LPARAM UNUSED(lparam)) { - if(!WindowCtrl::is_valid_hwnd(hwnd)) { + if(!WindowCtrl::is_visible_hwnd(hwnd)) { return TRUE ; //continue } RECT rect ; if(!GetWindowRect(hwnd, &rect)) { - return TRUE ; + return TRUE ; //continue } - if(!WindowCtrl::is_valid_rect(hwnd, rect)) { + if(!WindowCtrl::is_window_mode(hwnd, rect)) { return TRUE ; //continue } - HMONITOR hmonitor ; - RECT monitor_rect ; - RECT monitor_rect_work ; - ScreenMetrics::get_monitor_metrics(hwnd, &monitor_rect, &monitor_rect_work, &hmonitor) ; - - //Is in range of work area - if(ScreenMetrics::is_out_of_range(rect, monitor_rect_work)) { + //Is existed in work area? + ScreenMetrics::MonitorInfo minfo ; + ScreenMetrics::get_monitor_metrics(hwnd, minfo) ; + if(ScreenMetrics::is_out_of_range(rect, minfo.work_rect)) { return TRUE ; } + // make a unique identifier and its priority DWORD proc_id = 0 ; GetWindowThreadProcessId(hwnd, &proc_id) ; - HANDLE hproc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, proc_id) ; + + HANDLE hproc = OpenProcess( + PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, + FALSE, proc_id) ; if(!hproc) { return TRUE ; //has not permission } @@ -273,9 +273,10 @@ namespace ResizeWindow CloseHandle(hproc) ; //a key is unique and described the priority. - auto& gh = g_ordered_hwnd[hmonitor] ; - gh[pmc.WorkingSetSize + gh.size()] = hwnd ; - g_mrects[hmonitor] = std::move(monitor_rect_work) ; + auto& ordered_hwnd = g_m_ordered_hwnd[minfo.hmonitor] ; + ordered_hwnd[pmc.WorkingSetSize + ordered_hwnd.size()] = hwnd ; + + g_mrects[minfo.hmonitor] = std::move(minfo.work_rect) ; return TRUE ; } @@ -285,15 +286,17 @@ namespace ResizeWindow const auto& hmonitor = mr.first ; const auto& mrect = mr.second ; - const auto& oh = g_ordered_hwnd[hmonitor] ; + const auto& ordered_hwnd = g_m_ordered_hwnd[hmonitor] ; //Its priority is the highest (based on the memory use). - auto itr = oh.crbegin() ; + auto itr = ordered_hwnd.crbegin() ; + auto pre_hwnd = itr->second ; - rects[itr->second] = mrect ; + rects[pre_hwnd] = mrect ; + itr ++ ; - while(itr != oh.crend()) { + while(itr != ordered_hwnd.crend()) { const auto hwnd = itr->second ; auto& pre_rect = rects[pre_hwnd] ; @@ -303,11 +306,11 @@ namespace ResizeWindow const auto pre_h = ScreenMetrics::height(pre_rect) ; if(pre_w > pre_h) { pre_rect.right -= pre_w / 2 ; - rect.left += pre_w / 2 ; + rect.left += pre_w / 2 ; } else { pre_rect.bottom -= pre_h / 2 ; - rect.top += pre_h / 2 ; + rect.top += pre_h / 2 ; } rects[hwnd] = std::move(rect) ; @@ -317,12 +320,12 @@ namespace ResizeWindow } } - inline static void batch_resize(std::unordered_map& rects) { + inline static void batch_resize(const std::unordered_map& rects) { //Resize each windows for(const auto& hr : rects) { const auto hwnd = hr.first ; const auto rect = hr.second ; - resize_window(hwnd, rect.left, rect.top, + resize(hwnd, rect.left, rect.top, ScreenMetrics::width(rect), ScreenMetrics::height(rect)) ; } } @@ -349,14 +352,14 @@ void ArrangeWindows::sprocess( //Search visible windows using namespace ResizeWindow ; - g_ordered_hwnd.clear() ; + g_m_ordered_hwnd.clear() ; g_mrects.clear() ; if(!EnumWindows(EnumWindowsProcForArrangement, 0)) { throw RUNTIME_EXCEPT("Could not enumerate all top-level windows on the screen.") ; } - if(g_ordered_hwnd.empty() || g_mrects.empty()) { + if(g_m_ordered_hwnd.empty() || g_mrects.empty()) { return ; } @@ -384,26 +387,21 @@ namespace ResizeWindow throw RUNTIME_EXCEPT("Could not get monitor infomation.") ; } - if(g_ordered_hwnd.empty()) { + if(g_m_ordered_hwnd.empty()) { return ; } - try { - //rotate-shift a value in hwnd maps - auto& oh = g_ordered_hwnd.at(hmonitor) ; - if(oh.empty()) { - return ; - } - - sort_proc(oh) ; - - std::unordered_map rects ; - assign_local_area_in_monitors(rects) ; - batch_resize(rects) ; - } - catch(const std::out_of_range&) { + //rotate-shift a value in hwnd maps + auto& ordered_hwnd = g_m_ordered_hwnd.at(hmonitor) ; + if(ordered_hwnd.empty()) { return ; } + + sort_proc(ordered_hwnd) ; + + std::unordered_map rects ; + assign_local_area_in_monitors(rects) ; + batch_resize(rects) ; } } @@ -421,18 +419,18 @@ void RotateWindows::sprocess( { if(!first_call) return ; - auto sort = [repeat_num] (ResizeWindow::ordered_hwnd_t& oh) { + auto sort = [repeat_num] (ResizeWindow::ordered_hwnd_t& ordered_hwnd) { for(unsigned int i = 0 ; i < repeat_num ; i ++) { - auto itr = oh.rbegin() ; - auto head_val = itr->second ; - auto pre_itr = itr ; + auto itr = ordered_hwnd.rbegin() ; + auto pre_itr = itr ; + const auto head_hwnd = itr->second ; itr ++ ; - while(itr != oh.rend()) { + while(itr != ordered_hwnd.rend()) { pre_itr->second = itr->second ; pre_itr = itr ; itr ++ ; } - pre_itr->second = head_val ; + pre_itr->second = head_hwnd ; } } ; @@ -453,18 +451,18 @@ void RotateWindowsInReverse::sprocess( { if(!first_call) return ; - auto sort = [repeat_num] (ResizeWindow::ordered_hwnd_t& oh) { + auto sort = [repeat_num] (ResizeWindow::ordered_hwnd_t& ordered_hwnd) { for(unsigned int i = 0 ; i < repeat_num ; i ++) { - auto itr = oh.begin() ; - auto head_val = itr->second ; - auto pre_itr = itr ; + auto itr = ordered_hwnd.begin() ; + auto pre_itr = itr ; + const auto head_hwnd = itr->second ; itr ++ ; - while(itr != oh.end()) { + while(itr != ordered_hwnd.end()) { pre_itr->second = itr->second ; pre_itr = itr ; itr ++ ; } - pre_itr->second = head_val ; + pre_itr->second = head_hwnd ; } } ; @@ -475,14 +473,37 @@ namespace ResizeWindow { static std::map g_near_hwnds ; + struct ForegroundInfo { + HWND hwnd ; + HMONITOR hmonitor ; + RECT rect ; + + explicit ForegroundInfo() + : hwnd(NULL), + hmonitor(NULL), + rect{0, 0, 0, 0} + { + hwnd = GetForegroundWindow() ; + if(hwnd == NULL) { + throw RUNTIME_EXCEPT("Could not get a position of a mouse cursor.") ; + } + + hmonitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST) ; + + if(!GetWindowRect(hwnd, &rect)) { + throw RUNTIME_EXCEPT("Could not get a rectangle of a foreground window.") ; + } + } + } ; + static BOOL CALLBACK EnumWindowsProcForExchange(HWND hwnd, LPARAM lparam) { - auto target_hwnd = reinterpret_cast(lparam) ; + const auto fginfo = reinterpret_cast(lparam) ; - if(target_hwnd == hwnd) { + if(fginfo->hwnd == hwnd) { return TRUE ; } - if(!WindowCtrl::is_valid_hwnd(hwnd)) { + if(!WindowCtrl::is_visible_hwnd(hwnd)) { return TRUE ; //continue } @@ -491,29 +512,22 @@ namespace ResizeWindow return TRUE ; } - if(!WindowCtrl::is_valid_rect(hwnd, rect)) { + if(!WindowCtrl::is_window_mode(hwnd, rect)) { return TRUE ; //continue } - HMONITOR hmonitor ; - RECT monitor_rect, monitor_rect_work ; - ScreenMetrics::get_monitor_metrics(hwnd, &monitor_rect, &monitor_rect_work, &hmonitor) ; - - const auto target_hmonitor = MonitorFromWindow(target_hwnd, MONITOR_DEFAULTTONEAREST) ; - if(hmonitor != target_hmonitor) { - return TRUE ; - } - //Is in range of work area - if(ScreenMetrics::is_out_of_range(rect, monitor_rect_work)) { + ScreenMetrics::MonitorInfo minfo ; + ScreenMetrics::get_monitor_metrics(hwnd, minfo) ; + if(ScreenMetrics::is_out_of_range(rect, minfo.work_rect)) { return TRUE ; } - RECT target_rect ; - if(!GetWindowRect(target_hwnd, &target_rect)) { + if(minfo.hmonitor != fginfo->hmonitor) { return TRUE ; } - g_near_hwnds[ScreenMetrics::l2_distance_nosq(rect, target_rect) / 100] = hwnd ; + + g_near_hwnds[ScreenMetrics::l2_distance_nosq(rect, fginfo->rect) / 100] = hwnd ; return TRUE ; } } @@ -536,12 +550,8 @@ void ExchangeWindowWithNextOne::sprocess( g_near_hwnds.clear() ; - auto hwnd = GetForegroundWindow() ; - if(hwnd == NULL) { - throw RUNTIME_EXCEPT("Could not get a position of a mouse cursor.") ; - } - - if(!EnumWindows(EnumWindowsProcForExchange, reinterpret_cast(hwnd))) { + ForegroundInfo fginfo ; + if(!EnumWindows(EnumWindowsProcForExchange, reinterpret_cast(&fginfo))) { throw RUNTIME_EXCEPT("Could not enumerate all top-level windows on the screen.") ; } @@ -549,26 +559,21 @@ void ExchangeWindowWithNextOne::sprocess( return ; } - RECT rect ; - if(!GetWindowRect(hwnd, &rect)) { - throw RUNTIME_EXCEPT("Could not get a rectangle of the target window.") ; - } - auto nearest_hwnd = g_near_hwnds.begin()->second ; RECT nearest_rect ; if(!GetWindowRect(nearest_hwnd, &nearest_rect)) { throw RUNTIME_EXCEPT("Could not get a rectangle of the nearest window.") ; } - ResizeWindow::resize_window( + ResizeWindow::resize( nearest_hwnd, - rect.left, - rect.top, - ScreenMetrics::width(rect), - ScreenMetrics::height(rect)) ; + fginfo.rect.left, + fginfo.rect.top, + ScreenMetrics::width(fginfo.rect), + ScreenMetrics::height(fginfo.rect)) ; - ResizeWindow::resize_window( - hwnd, + ResizeWindow::resize( + fginfo.hwnd, nearest_rect.left, nearest_rect.top, ScreenMetrics::width(nearest_rect), @@ -590,23 +595,15 @@ void OpenNewCurWinWithHorizontalSplit::sprocess( { if(!first_call) return ; - auto hwnd = GetForegroundWindow() ; - if(hwnd == NULL) { - throw RUNTIME_EXCEPT("There is not the foreground window.") ; - } - - RECT rect ; - if(!GetWindowRect(hwnd, &rect)) { - throw RUNTIME_EXCEPT("Could not get a rectangle of a foreground window.") ; - } + ResizeWindow::ForegroundInfo fginfo ; - const auto w = ScreenMetrics::width(rect) ; - const auto h = ScreenMetrics::height(rect) ; + const auto w = ScreenMetrics::width(fginfo.rect) ; + const auto h = ScreenMetrics::height(fginfo.rect) ; //snap a original window to top - ResizeWindow::resize_window( - hwnd, - rect.left, rect.top, + ResizeWindow::resize( + fginfo.hwnd, + fginfo.rect.left, fginfo.rect.top, w, h / 2) ; OpenNewCurrentWindow::sprocess(true, 1, nullptr, nullptr) ; @@ -614,15 +611,15 @@ void OpenNewCurWinWithHorizontalSplit::sprocess( if(new_hwnd == NULL) { throw RUNTIME_EXCEPT("There is not the foreground window.") ; } - if(new_hwnd == hwnd) { + if(new_hwnd == fginfo.hwnd) { Sleep(500) ; new_hwnd = GetForegroundWindow() ; } //snap a new window to bottom - ResizeWindow::resize_window( + ResizeWindow::resize( new_hwnd, - rect.left, rect.top + h / 2, + fginfo.rect.left, fginfo.rect.top + h / 2, w, h / 2) ; } @@ -641,23 +638,15 @@ void OpenNewCurWinWithVerticalSplit::sprocess( { if(!first_call) return ; - auto hwnd = GetForegroundWindow() ; - if(hwnd == NULL) { - throw RUNTIME_EXCEPT("There is not the foreground window.") ; - } - - RECT rect ; - if(!GetWindowRect(hwnd, &rect)) { - throw RUNTIME_EXCEPT("Could not get a rectangle of a foreground window.") ; - } + ResizeWindow::ForegroundInfo fginfo ; - const auto w = ScreenMetrics::width(rect) ; - const auto h = ScreenMetrics::height(rect) ; + const auto w = ScreenMetrics::width(fginfo.rect) ; + const auto h = ScreenMetrics::height(fginfo.rect) ; //snap a original window to left - ResizeWindow::resize_window( - hwnd, - rect.left, rect.top, + ResizeWindow::resize( + fginfo.hwnd, + fginfo.rect.left, fginfo.rect.top, w / 2, h) ; OpenNewCurrentWindow::sprocess(true, 1, nullptr, nullptr) ; @@ -665,15 +654,15 @@ void OpenNewCurWinWithVerticalSplit::sprocess( if(new_hwnd == NULL) { throw RUNTIME_EXCEPT("There is not the foreground window.") ; } - if(new_hwnd == hwnd) { + if(new_hwnd == fginfo.hwnd) { Sleep(500) ; new_hwnd = GetForegroundWindow() ; } //snap a new window to right - ResizeWindow::resize_window( + ResizeWindow::resize( new_hwnd, - rect.left + w / 2, rect.top, + fginfo.rect.left + w / 2, fginfo.rect.top, w / 2, h) ; } @@ -709,33 +698,24 @@ void ResizeWindowWidth::sprocess( { if(!first_call) return ; - auto hwnd = GetForegroundWindow() ; - if(hwnd == NULL) { - throw RUNTIME_EXCEPT("There is not a foreground window.") ; - } - - RECT rect ; - if(!GetWindowRect(hwnd, &rect)) { - throw RUNTIME_EXCEPT("Could not get a rectangle of a foreground window.") ; - } + ResizeWindow::ForegroundInfo fginfo ; auto str = KyLgr::log2str(*parent_charlgr) ; if(str.empty()) return ; auto width = static_cast(KyLgr::extract_num(str)) ; - RECT mrect ; - RECT mrect_work ; - ScreenMetrics::get_monitor_metrics(hwnd, &mrect, &mrect_work) ; + ScreenMetrics::MonitorInfo minfo ; + ScreenMetrics::get_monitor_metrics(fginfo.hwnd, minfo) ; - auto max_width = mrect_work.right - rect.left ; + auto max_width = minfo.work_rect.right - fginfo.rect.left ; if(max_width < width) { width = max_width ; } - ResizeWindow::resize_window( - hwnd, rect.left, rect.top, - width, ScreenMetrics::height(rect)) ; + ResizeWindow::resize( + fginfo.hwnd, fginfo.rect.left, fginfo.rect.top, + width, ScreenMetrics::height(fginfo.rect)) ; } //IncreaseWindowWidth @@ -752,32 +732,23 @@ void IncreaseWindowWidth::sprocess( { if(!first_call) return ; - auto hwnd = GetForegroundWindow() ; - if(hwnd == NULL) { - throw RUNTIME_EXCEPT("There is not a foreground window.") ; - } - - RECT rect ; - if(!GetWindowRect(hwnd, &rect)) { - throw RUNTIME_EXCEPT("Could not get a rectangle of a foreground window.") ; - } + ResizeWindow::ForegroundInfo fginfo ; - auto width = ScreenMetrics::width(rect) ; + auto width = ScreenMetrics::width(fginfo.rect) ; width += ResizeWindow::compute_resize_delta( repeat_num, parent_charlgr, "window_width_delta") ; - RECT mrect ; - RECT mrect_work ; - ScreenMetrics::get_monitor_metrics(hwnd, &mrect, &mrect_work) ; + ScreenMetrics::MonitorInfo minfo ; + ScreenMetrics::get_monitor_metrics(fginfo.hwnd, minfo) ; - auto max_width = mrect_work.right - rect.left ; + auto max_width = minfo.work_rect.right - fginfo.rect.left ; if(max_width < width) { width = max_width ; } - ResizeWindow::resize_window( - hwnd, rect.left, rect.top, - width, ScreenMetrics::height(rect)) ; + ResizeWindow::resize( + fginfo.hwnd, fginfo.rect.left, fginfo.rect.top, + width, ScreenMetrics::height(fginfo.rect)) ; } //DecreaseWindowWidth @@ -794,28 +765,20 @@ void DecreaseWindowWidth::sprocess( { if(!first_call) return ; - auto hwnd = GetForegroundWindow() ; - if(hwnd == NULL) { - throw RUNTIME_EXCEPT("There is not a foreground window.") ; - } - - RECT rect ; - if(!GetWindowRect(hwnd, &rect)) { - throw RUNTIME_EXCEPT("Could not get a rectangle of a foreground window.") ; - } + ResizeWindow::ForegroundInfo fginfo ; const auto delta = ResizeWindow::compute_resize_delta( repeat_num, parent_charlgr, "window_width_delta") ; - auto width = ScreenMetrics::width(rect) - delta ; + auto width = ScreenMetrics::width(fginfo.rect) - delta ; if(width <= 0) { VirtualCmdLine::msgout("e: Width below zero") ; return ; } - ResizeWindow::resize_window( - hwnd, rect.left, rect.top, - width, ScreenMetrics::height(rect)) ; + ResizeWindow::resize( + fginfo.hwnd, fginfo.rect.left, fginfo.rect.top, + width, ScreenMetrics::height(fginfo.rect)) ; } //ResizeWindowHeight @@ -832,33 +795,24 @@ void ResizeWindowHeight::sprocess( { if(!first_call) return ; - auto hwnd = GetForegroundWindow() ; - if(hwnd == NULL) { - throw RUNTIME_EXCEPT("There is not a foreground window.") ; - } - - RECT rect ; - if(!GetWindowRect(hwnd, &rect)) { - throw RUNTIME_EXCEPT("Could not get a rectangle of a foreground window.") ; - } + ResizeWindow::ForegroundInfo fginfo ; auto str = KyLgr::log2str(*parent_charlgr) ; if(str.empty()) return ; auto height = static_cast(KyLgr::extract_num(str)) ; - RECT mrect ; - RECT mrect_work ; - ScreenMetrics::get_monitor_metrics(hwnd, &mrect, &mrect_work) ; + ScreenMetrics::MonitorInfo minfo ; + ScreenMetrics::get_monitor_metrics(fginfo.hwnd, minfo) ; - auto max_height = mrect_work.bottom - rect.top ; + auto max_height = minfo.work_rect.bottom - fginfo.rect.top ; if(max_height < height) { height = max_height ; } - ResizeWindow::resize_window( - hwnd, rect.left, rect.top, - ScreenMetrics::width(rect), height) ; + ResizeWindow::resize( + fginfo.hwnd, fginfo.rect.left, fginfo.rect.top, + ScreenMetrics::width(fginfo.rect), height) ; } //IncreaseWindowHeight @@ -875,32 +829,23 @@ void IncreaseWindowHeight::sprocess( { if(!first_call) return ; - auto hwnd = GetForegroundWindow() ; - if(hwnd == NULL) { - throw RUNTIME_EXCEPT("There is not a foreground window.") ; - } + ResizeWindow::ForegroundInfo fginfo ; - RECT rect ; - if(!GetWindowRect(hwnd, &rect)) { - throw RUNTIME_EXCEPT("Could not get a rectangle of a foreground window.") ; - } - - auto height = ScreenMetrics::height(rect) ; + auto height = ScreenMetrics::height(fginfo.rect) ; height += ResizeWindow::compute_resize_delta( repeat_num, parent_charlgr, "window_height_delta") ; - RECT mrect ; - RECT mrect_work ; - ScreenMetrics::get_monitor_metrics(hwnd, &mrect, &mrect_work) ; + ScreenMetrics::MonitorInfo minfo ; + ScreenMetrics::get_monitor_metrics(fginfo.hwnd, minfo) ; - auto max_height = mrect_work.bottom - rect.top ; + auto max_height = minfo.work_rect.bottom - fginfo.rect.top ; if(max_height < height) { height = max_height ; } - ResizeWindow::resize_window( - hwnd, rect.left, rect.top, - ScreenMetrics::width(rect), height) ; + ResizeWindow::resize( + fginfo.hwnd, fginfo.rect.left, fginfo.rect.top, + ScreenMetrics::width(fginfo.rect), height) ; } //DecreaseWindowHeight @@ -917,26 +862,18 @@ void DecreaseWindowHeight::sprocess( { if(!first_call) return ; - auto hwnd = GetForegroundWindow() ; - if(hwnd == NULL) { - throw RUNTIME_EXCEPT("There is not a foreground window.") ; - } - - RECT rect ; - if(!GetWindowRect(hwnd, &rect)) { - throw RUNTIME_EXCEPT("Could not get a rectangle of a foreground window.") ; - } + ResizeWindow::ForegroundInfo fginfo ; const auto delta = ResizeWindow::compute_resize_delta( repeat_num, parent_charlgr, "window_height_delta") ; - auto height = ScreenMetrics::height(rect) - delta ; + auto height = ScreenMetrics::height(fginfo.rect) - delta ; if(height <= 0) { VirtualCmdLine::msgout("e: Height below zero") ; return ; } - ResizeWindow::resize_window( - hwnd, rect.left, rect.top, - ScreenMetrics::width(rect), height) ; + ResizeWindow::resize( + fginfo.hwnd, fginfo.rect.left, fginfo.rect.top, + ScreenMetrics::width(fginfo.rect), height) ; } diff --git a/core/src/gui_bindings/select_window.cpp b/core/src/gui_bindings/select_window.cpp index 9bb94466..8da5ff8d 100644 --- a/core/src/gui_bindings/select_window.cpp +++ b/core/src/gui_bindings/select_window.cpp @@ -113,7 +113,7 @@ namespace SelectWindow return TRUE ; } - if(!WindowCtrl::is_valid_hwnd(hwnd)) { + if(!WindowCtrl::is_visible_hwnd(hwnd)) { return TRUE ; } @@ -122,14 +122,14 @@ namespace SelectWindow return TRUE ; } - if(!WindowCtrl::is_valid_rect(hwnd, rect)) { + if(!WindowCtrl::is_window_mode(hwnd, rect)) { return TRUE ; } - RECT monitor_rect, monitor_rect_work ; - ScreenMetrics::get_monitor_metrics(hwnd, &monitor_rect, &monitor_rect_work) ; + ScreenMetrics::MonitorInfo minfo ; + ScreenMetrics::get_monitor_metrics(hwnd, minfo) ; - if(ScreenMetrics::is_out_of_range(rect, monitor_rect_work)) { + if(ScreenMetrics::is_out_of_range(rect, minfo.work_rect)) { return TRUE ; } @@ -139,41 +139,42 @@ namespace SelectWindow template inline static void select_nearest_window(T1&& is_if_target, T2&& calc_distance) { - auto hwnd = GetForegroundWindow() ; - if(hwnd == NULL) { + auto fg_hwnd = GetForegroundWindow() ; + if(fg_hwnd == NULL) { throw RUNTIME_EXCEPT("There is not a foreground window.") ; } SelectWindow::g_rects.clear() ; if(!EnumWindows(SelectWindow::EnumWindowsProcForNearest, - reinterpret_cast(hwnd))) { + reinterpret_cast(fg_hwnd))) { throw RUNTIME_EXCEPT("Could not enumerate all top-level windows.") ; } - RECT rect ; - if(!GetWindowRect(hwnd, &rect)) { + RECT fg_rect ; + if(!GetWindowRect(fg_hwnd, &fg_rect)) { throw RUNTIME_EXCEPT("Could not get a rectangle of a foreground window.") ; } - std::map nearest ; - for(const auto& hr : SelectWindow::g_rects) { - auto& ehwnd = hr.first ; - auto& erect = hr.second ; + std::map distance_order_hwnd ; + for(const auto& enumed_rect : SelectWindow::g_rects) { + auto& enu_hwnd = enumed_rect.first ; + auto& enu_rect = enumed_rect.second ; - auto cx = ScreenMetrics::center_x(rect) ; - auto cy = ScreenMetrics::center_y(rect) ; - auto ecx = ScreenMetrics::center_x(erect) ; - auto ecy = ScreenMetrics::center_y(erect) ; + auto cx = ScreenMetrics::center_x(fg_rect) ; + auto cy = ScreenMetrics::center_y(fg_rect) ; + auto ecx = ScreenMetrics::center_x(enu_rect) ; + auto ecy = ScreenMetrics::center_y(enu_rect) ; - if(is_if_target(rect, erect, cx, cy, ecx, ecy)) { - nearest[calc_distance(rect, erect, cx, cy, ecx, ecy)] = ehwnd ; + if(is_if_target(fg_rect, enu_rect, cx, cy, ecx, ecy)) { + const auto distance = calc_distance(fg_rect, enu_rect, cx, cy, ecx, ecy) ; + distance_order_hwnd[distance] = enu_hwnd ; } } - if(!nearest.empty()) { - auto target_hwnd = nearest.begin()->second ; - if(!SetForegroundWindow(target_hwnd)) { + if(!distance_order_hwnd.empty()) { + auto nearest_hwnd = distance_order_hwnd.begin()->second ; + if(!SetForegroundWindow(nearest_hwnd)) { throw RUNTIME_EXCEPT("Could not set a foreground window.") ; } Sleep(50) ; diff --git a/core/src/gui_bindings/window_ctrl.cpp b/core/src/gui_bindings/window_ctrl.cpp index 0c78b4f4..fe24c960 100644 --- a/core/src/gui_bindings/window_ctrl.cpp +++ b/core/src/gui_bindings/window_ctrl.cpp @@ -23,7 +23,7 @@ namespace WindowCtrl { - bool is_valid_hwnd(HWND hwnd) { + bool is_visible_hwnd(HWND hwnd) { //is movable window ? ----------- if(hwnd == GetDesktopWindow()) { return false ; @@ -53,14 +53,18 @@ namespace WindowCtrl return true ; } - bool is_valid_rect(HWND hwnd, RECT& rect) { - const auto width = ScreenMetrics::width(rect) ; - if(width == 0) { + bool is_window_mode(HWND hwnd, RECT& rect) { + + //Is having title bar ? + if(GetWindowTextLengthW(hwnd) == 0) { + return false ; + } + + if(ScreenMetrics::width(rect) == 0) { return false ; } - const auto height = ScreenMetrics::height(rect) ; - if(height == 0) { + if(ScreenMetrics::height(rect) == 0) { return false ; } diff --git a/core/src/screen_metrics.cpp b/core/src/screen_metrics.cpp new file mode 100644 index 00000000..3d6152ff --- /dev/null +++ b/core/src/screen_metrics.cpp @@ -0,0 +1,131 @@ +#include "screen_metrics.hpp" + +#include +#include +#include +#include +#include "utility.hpp" + +namespace ScreenMetrics +{ + inline void copy(RECT& lhs, const RECT& rhs) noexcept { + lhs.left = rhs.left ; + lhs.top = rhs.top ; + lhs.right = rhs.right ; + lhs.bottom = rhs.bottom ; + } + + inline auto width(const RECT& rect) noexcept { + return rect.right - rect.left ; + } + + inline auto height(const RECT& rect) noexcept { + return rect.bottom - rect.top ; + } + + inline auto center_x(const RECT& rect) noexcept { + return rect.left + width(rect) / 2 ; + } + + inline auto center_y(const RECT& rect) noexcept { + return rect.top + height(rect) / 2 ; + } + + inline auto l1_distance(const RECT& lhs, const RECT& rhs) noexcept { + return std::abs(center_x(rhs) - center_x(lhs)) \ + + std::abs(center_y(rhs) - center_y(lhs)) ; + } + + inline auto l2_distance_nosq(const RECT& lhs, const RECT& rhs) noexcept { + auto delta_x = center_x(rhs) - center_x(lhs) ; + auto delta_y = center_y(rhs) - center_y(lhs) ; + return delta_x*delta_x + delta_y*delta_y ; + } + inline auto l2_distance_nosq(LONG x1, LONG y1, LONG x2, LONG y2) noexcept { + auto delta_x = x2 - x1 ; + auto delta_y = y2 - y1 ; + return delta_x*delta_x + delta_y*delta_y ; + } + + inline auto l2_distance(const RECT& lhs, const RECT& rhs) noexcept { + return std::sqrt(l2_distance_nosq(rhs, lhs)) ; + } + inline auto l2_distance(LONG x1, LONG y1, LONG x2, LONG y2) noexcept { + return std::sqrt(l2_distance_nosq(x1, y1, x2, y2)) ; + } + + inline auto is_out_of_range(const RECT& target, const RECT& range) noexcept { + return (target.left <= range.left && target.right <= range.left) || \ + (target.top <= range.top && target.bottom <= range.top) || \ + (target.left >= range.right && target.right >= range.right) || \ + (target.top >= range.bottom && target.bottom >= range.bottom) ; + } + + inline auto is_fully_in_range(const RECT& target, const RECT& range) noexcept { + return target.left >= range.left && target.right <= range.right && \ + target.top >= range.top && target.bottom <= range.bottom ; + } + + inline auto is_in_range(const RECT& target, const RECT& range) noexcept { + return target.left >= range.left || target.right <= range.right || \ + target.top >= range.top || target.bottom <= range.bottom ; + } + + inline auto is_equel(const RECT& lhs, const RECT& rhs) noexcept { + return lhs.left == rhs.left && \ + lhs.top == rhs.top && \ + lhs.right == rhs.right && \ + lhs.bottom == rhs.bottom ; + } + + inline auto is_bigger_than(const RECT& lhs, const RECT& rhs) noexcept { + return lhs.left <= rhs.left && lhs.top <= rhs.top && + lhs.right >= rhs.right && lhs.bottom >= rhs.bottom ; + } + + inline void get_conbined_metrics(RECT* const rect) { + WINDOWINFO winfo ; + winfo.cbSize = sizeof(WINDOWINFO) ; + if(!GetWindowInfo(GetDesktopWindow(), &winfo)) { + throw RUNTIME_EXCEPT("Could not get window infomation.") ; + } + copy(*rect, winfo.rcWindow) ; + } + + inline void get_primary_metrics(RECT* const rect) { + MONITORINFO minfo ; + minfo.cbSize = sizeof(MONITORINFO) ; + const auto hmonitor = MonitorFromWindow(GetDesktopWindow(), MONITOR_DEFAULTTOPRIMARY) ; + if(!GetMonitorInfo(hmonitor, &minfo)) { + throw RUNTIME_EXCEPT("Could not get primary monitor infomation.") ; + } + copy(*rect, minfo.rcMonitor) ; + } + + struct MonitorInfo { + RECT rect = {0, 0, 0, 0} ; + RECT work_rect = {0, 0, 0, 0} ; + HMONITOR hmonitor = NULL ; + } ; + inline void get_monitor_metrics(HWND hwnd, MonitorInfo& minfo) { + minfo.hmonitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST) ; + MONITORINFO native_minfo ; + native_minfo.cbSize = sizeof(MONITORINFO) ; + if(!GetMonitorInfo(minfo.hmonitor, &native_minfo)) { + throw RUNTIME_EXCEPT("Could not get monitor infomation.") ; + } + + copy(minfo.rect, native_minfo.rcMonitor) ; + copy(minfo.work_rect, native_minfo.rcWork) ; + } + + namespace Debug { + inline static std::string info(const RECT& rect) { + std::stringstream ss ; + ss << "(" << rect.left << ", " << rect.top << ")\t" ; + ss << "(" << rect.right << ", " << rect.bottom << ")\t" ; + ss << "w: " << width(rect) << ", h:" << height(rect) ; + return ss.str() ; + } + } +}