diff --git a/mian.py b/mian.py new file mode 100644 index 0000000000000000000000000000000000000000..53c8fd02d5248d05c2528487a7a8a0d940e26269 --- /dev/null +++ b/mian.py @@ -0,0 +1,97 @@ +import sys +import win32gui +import win32con +from PySide6.QtWidgets import QApplication, QWidget, QLabel, QVBoxLayout +from PySide6.QtCore import Qt, QPoint + +TARGET_HWND = 0x328108 # 你的目标窗口句柄 +MAX_W, MAX_H = 2000, 1200 # 避免 CreateDIBSection 失败 + + +class DraggableWidget(QWidget): + def __init__(self): + super().__init__() + self.dragging = False + self.drag_pos = QPoint() + + self.setWindowFlags(Qt.FramelessWindowHint) + self.setAttribute(Qt.WA_NoSystemBackground, False) + self.setAttribute(Qt.WA_TranslucentBackground, False) + + layout = QVBoxLayout(self) + layout.setContentsMargins(0, 0, 0, 0) + + label = QLabel("点击拖动我!\n这是挂在 HWND 下的 UI") + label.setStyleSheet("font-size:16px; background:#202020; color:white; padding:8px;") + label.setAlignment(Qt.AlignCenter) + layout.addWidget(label) + + self.resize(300, 120) + + # ---------------- 鼠标拖动 ---------------- + def mousePressEvent(self, e): + if e.button() == Qt.LeftButton: + self.dragging = True + self.drag_pos = e.globalPosition().toPoint() + + def mouseMoveEvent(self, e): + if not self.dragging: + return + delta = e.globalPosition().toPoint() - self.drag_pos + self.drag_pos = e.globalPosition().toPoint() + + hwnd = int(self.winId()) + if not win32gui.IsWindow(hwnd): + return + + x, y, r, b = win32gui.GetWindowRect(hwnd) + width, height = r - x, b - y + + # 移动窗口 + new_x = x + delta.x() + new_y = y + delta.y() + new_x = max(0, min(new_x, MAX_W)) + new_y = max(0, min(new_y, MAX_H)) + + win32gui.SetWindowPos( + hwnd, None, new_x, new_y, width, height, + win32con.SWP_NOZORDER | win32con.SWP_NOACTIVATE + ) + + def mouseReleaseEvent(self, e): + self.dragging = False + + +def embed_widget(widget: QWidget, parent_hwnd: int): + hwnd = int(widget.winId()) + + # 设置为子窗口 + style = win32gui.GetWindowLong(hwnd, win32con.GWL_STYLE) + style &= ~win32con.WS_POPUP + style |= win32con.WS_CHILD + win32gui.SetWindowLong(hwnd, win32con.GWL_STYLE, style) + + win32gui.SetParent(hwnd, parent_hwnd) + + # 使用 widget 自己的大小(不要拉满) + w, h = widget.width(), widget.height() + + win32gui.SetWindowPos( + hwnd, + None, + 50, 50, # 初始位置 + w, h, # 使用自身尺寸 + win32con.SWP_NOZORDER | win32con.SWP_SHOWWINDOW + ) + + + +if __name__ == "__main__": + app = QApplication(sys.argv) + + widget = DraggableWidget() + widget.show() + + embed_widget(widget, TARGET_HWND) + + sys.exit(app.exec()) diff --git "a/\344\273\273\345\212\241\346\240\217\351\274\240\346\240\207\346\273\232\345\212\250/detection_taskbar.py" "b/\344\273\273\345\212\241\346\240\217\351\274\240\346\240\207\346\273\232\345\212\250/detection_taskbar.py" new file mode 100644 index 0000000000000000000000000000000000000000..e13b2a89a171327eb3f92380316b769e879d0e24 --- /dev/null +++ "b/\344\273\273\345\212\241\346\240\217\351\274\240\346\240\207\346\273\232\345\212\250/detection_taskbar.py" @@ -0,0 +1,89 @@ +# taskbar_mouse.py +import ctypes +from ctypes import wintypes +from pynput import mouse +import time + +user32 = ctypes.windll.user32 + +# ----------------------------- +# 获取鼠标下窗口句柄 +# ----------------------------- +def get_hwnd_under_mouse(): + pt = wintypes.POINT() + user32.GetCursorPos(ctypes.byref(pt)) + return user32.WindowFromPoint(pt) + +# ----------------------------- +# 获取窗口类名 +# ----------------------------- +def get_class_name(hwnd): + if not hwnd: + return "" + buf = ctypes.create_unicode_buffer(256) + user32.GetClassNameW(hwnd, buf, 256) + return buf.value + +# ----------------------------- +# 检测鼠标是否在任务栏 +# ----------------------------- +def is_mouse_over_taskbar(): + hwnd = get_hwnd_under_mouse() + while hwnd: + if get_class_name(hwnd) == "Shell_TrayWnd": + return True + hwnd = user32.GetParent(hwnd) + return False + +# ----------------------------- +# 鼠标滚轮监听(只在任务栏触发) +# ----------------------------- +def start_taskbar_wheel_listener(on_scroll_up=None, on_scroll_down=None, throttle=0.1): + """ + 启动滚轮监听,只在任务栏上触发 + throttle: 两次触发最小间隔(秒) + """ + last_time = 0 + + def on_scroll(x, y, dx, dy): + nonlocal last_time + if not is_mouse_over_taskbar(): + return + now = time.time() + if now - last_time < throttle: + return # 节流 + last_time = now + if dy > 0 and on_scroll_up: + on_scroll_up() + elif dy < 0 and on_scroll_down: + on_scroll_down() + + listener = mouse.Listener(on_scroll=on_scroll) + listener.start() + return listener + + +# ----------------------------- +# 测试示例 +# ----------------------------- +if __name__ == "__main__": + print("任务栏鼠标滚轮检测示例") + + def up_action(): + print("鼠标在任务栏,滚轮向上") + + def down_action(): + print("鼠标在任务栏,滚轮向下") + + listener = start_taskbar_wheel_listener(up_action, down_action, throttle=0.1) + + try: + while True: + if is_mouse_over_taskbar(): + print("鼠标在任务栏") + else: + print("鼠标不在任务栏") + time.sleep(1) + except KeyboardInterrupt: + print("退出检测") + listener.stop() diff --git "a/\344\273\273\345\212\241\346\240\217\351\274\240\346\240\207\346\273\232\345\212\250/main.py" "b/\344\273\273\345\212\241\346\240\217\351\274\240\346\240\207\346\273\232\345\212\250/main.py" new file mode 100644 index 0000000000000000000000000000000000000000..33db3c578d4ee694fa97b37931f36ba0cf151364 --- /dev/null +++ "b/\344\273\273\345\212\241\346\240\217\351\274\240\346\240\207\346\273\232\345\212\250/main.py" @@ -0,0 +1,21 @@ +from detection_taskbar import start_taskbar_wheel_listener +from switch_desktop import ctrl_win_left_arrow, ctrl_win_right_arrow +import time + +# 滚轮回调 +def up_action(): + ctrl_win_left_arrow() + +def down_action(): + ctrl_win_right_arrow() + +# 启动滚轮监听 +listener = start_taskbar_wheel_listener(up_action, down_action, throttle=0.0000001) + +print("任务栏滚轮检测已启动,Ctrl+C 退出") + +try: + input("按任意键继续...") +except KeyboardInterrupt: + print("退出检测") + listener.stop() diff --git "a/\344\273\273\345\212\241\346\240\217\351\274\240\346\240\207\346\273\232\345\212\250/switch_desktop.py" "b/\344\273\273\345\212\241\346\240\217\351\274\240\346\240\207\346\273\232\345\212\250/switch_desktop.py" new file mode 100644 index 0000000000000000000000000000000000000000..885f4531844b36fc767a4539456b6bd8bed43aed --- /dev/null +++ "b/\344\273\273\345\212\241\346\240\217\351\274\240\346\240\207\346\273\232\345\212\250/switch_desktop.py" @@ -0,0 +1,37 @@ +from pynput.keyboard import Controller, Key +import time + +# 全局键盘控制器 +kb = Controller() + +# ----------------------------- +# 模拟 Ctrl + Win + 左箭头 +# ----------------------------- +def ctrl_win_left_arrow(): + kb.press(Key.ctrl) # 按下 Ctrl + kb.press(Key.cmd) # 按下 Win + kb.press(Key.left) # 按下左箭头 + kb.release(Key.left) + kb.release(Key.cmd) + kb.release(Key.ctrl) + +# ----------------------------- +# 模拟 Ctrl + Win + 右箭头 +# ----------------------------- +def ctrl_win_right_arrow(): + kb.press(Key.ctrl) # 按下 Ctrl + kb.press(Key.cmd) # 按下 Win + kb.press(Key.right) # 按下右箭头 + kb.release(Key.right) + kb.release(Key.cmd) + kb.release(Key.ctrl) + +# ----------------------------- +# 测试示例 +# ----------------------------- +if __name__ == "__main__": + print("模拟 Ctrl + Win + 右箭头(切换到右侧桌面)") + ctrl_win_right_arrow() + time.sleep(0.5) + print("模拟 Ctrl + Win + 左箭头(切换到左侧桌面)") + ctrl_win_left_arrow() \ No newline at end of file diff --git "a/\344\273\273\345\212\241\346\240\217\351\274\240\346\240\207\346\273\232\345\212\250/task_switch.py" "b/\344\273\273\345\212\241\346\240\217\351\274\240\346\240\207\346\273\232\345\212\250/task_switch.py" new file mode 100644 index 0000000000000000000000000000000000000000..8b60a51f86dbe904099baff5f5153fa036b64906 --- /dev/null +++ "b/\344\273\273\345\212\241\346\240\217\351\274\240\346\240\207\346\273\232\345\212\250/task_switch.py" @@ -0,0 +1,81 @@ +import win32gui +from pynput.keyboard import Controller, Key + +# ----------------------------- +# 全局键盘控制器 +# ----------------------------- +kb = Controller() + +# ----------------------------- +# 检测 Alt+Tab(任务切换)窗口是否存在 +# ----------------------------- +def is_task_switch_active(): + """检查任务切换界面是否存在""" + found = False + def enum_cb(hwnd, _): + nonlocal found + if win32gui.IsWindowVisible(hwnd): + if win32gui.GetClassName(hwnd) == "XamlExplorerHostIslandWindow" and win32gui.GetWindowText(hwnd) == "任务切换": + found = True + win32gui.EnumWindows(enum_cb, None) + return found + +# ----------------------------- +# 按 ESC 关闭任务切换 +# ----------------------------- +def exit_task_switch(): + """如果任务切换界面存在,则按 ESC 关闭""" + if is_task_switch_active(): + kb.press(Key.esc) + kb.release(Key.esc) + +# ----------------------------- +# 模拟 Ctrl+Alt+Tab 触发任务切换 +# ----------------------------- +def trigger_task_switch(): + """模拟一次性按下 Ctrl+Alt+Tab 触发任务切换界面""" + kb.press(Key.ctrl) + kb.press(Key.alt) + kb.press(Key.tab) + kb.release(Key.tab) + kb.release(Key.alt) + kb.release(Key.ctrl) + + +# ----------------------------- +# 模拟按下键盘左箭头 +# ----------------------------- +def left_arrow(): + kb.press(Key.left) # 按下左箭头 + kb.release(Key.left) # 松开左箭头 + +# ----------------------------- +# 模拟按下键盘右箭头 +# ----------------------------- +def right_arrow(): + kb.press(Key.right) # 按下右箭头 + kb.release(Key.right) # 松开右箭头 + + + +# ----------------------------- +# 示例调用 +# ----------------------------- +if __name__ == "__main__": + print("模拟 Ctrl+Alt+Tab → 触发任务切换") + trigger_task_switch() + + # 给系统一点时间显示任务切换界面 + import time + time.sleep(1) + + print("模拟按下左箭头") + left_arrow() + time.sleep(1) + print("模拟按下右箭头") + right_arrow() + time.sleep(1) + + print("检测并按 ESC 关闭任务切换") + exit_task_switch() + print("完成") diff --git "a/\346\211\223\345\214\205\345\221\275\344\273\244.txt" "b/\346\211\223\345\214\205\345\221\275\344\273\244.txt" index f0f6e05decfd8a0be4fe233b1a984bf1c5a319cb..a34904e1e283e8ce03c7c3e7092c063d896ebc36 100644 --- "a/\346\211\223\345\214\205\345\221\275\344\273\244.txt" +++ "b/\346\211\223\345\214\205\345\221\275\344\273\244.txt" @@ -1 +1 @@ -pyinstaller --name "桌面切换器" --windowed --onefile --icon "C:\Users\lqvsy\桌面\工作\logo.jpg" "C:\Users\lqvsy\桌面\工作\Windows-optimization\桌面切换\main.py" +pyinstaller --name "桌面切换器" --windowed --onefile --icon "C:\Users\lqvsy\桌面\1_Work\logo.jpg" "C:\Users\lqvsy\桌面\1_Work\Windows-optimization\桌面切换\main.py" diff --git "a/\346\241\214\351\235\242\345\210\207\346\215\242/desktop_component.py" "b/\346\241\214\351\235\242\345\210\207\346\215\242/desktop_component.py" new file mode 100644 index 0000000000000000000000000000000000000000..c27228a4bcf4535442b57a849aa08dde3c4fe7c8 --- /dev/null +++ "b/\346\241\214\351\235\242\345\210\207\346\215\242/desktop_component.py" @@ -0,0 +1,58 @@ +import ctypes + +user32 = ctypes.windll.user32 + +GWL_STYLE = -16 +WS_CHILD = 0x40000000 +WS_VISIBLE = 0x10000000 + +def get_desktop_listview_hwnd(): + """ + 获取桌面图标列表窗口的句柄 (SysListView32) + 返回句柄,找不到返回 None + """ + defview = None + worker = None + + while True: + worker = user32.FindWindowExW(None, worker, "WorkerW", None) + if not worker: + break + defview = user32.FindWindowExW(worker, None, "SHELLDLL_DefView", None) + if defview: + break + + listview = user32.FindWindowExW(defview, None, "SysListView32", None) if defview else None + return listview + +def attach_window_to_desktop_only(hwnd): + """ + 只将指定窗口挂到桌面图标窗口上,不修改窗口样式 + hwnd: 目标窗口句柄 + 返回 True/False + """ + if not hwnd: + return False + + # 获取桌面图标窗口句柄 + desktop = get_desktop_listview_hwnd() + if not desktop: + return False + + # 只设置父窗口为桌面图标窗口 + user32.SetParent(hwnd, desktop) + + return True + + +# ------------------------- +if __name__ == "__main__": + import win32gui + + # 直接用 Notepad 窗口的 NativeWindowHandle + hwnd = win32gui.FindWindow("Notepad", "无标题 - Notepad") + + if attach_window_to_desktop_only(hwnd): + print("Notepad 窗口已挂到桌面 ✅") + else: + print("挂载失败 ❌") diff --git "a/\346\241\214\351\235\242\345\210\207\346\215\242/main.py" "b/\346\241\214\351\235\242\345\210\207\346\215\242/main.py" index a773bdbdfccbe04cb0ed16b8c89c8042918ea935..e558d98ec7cd366c3fae2398a570061a309dc2d0 100644 --- "a/\346\241\214\351\235\242\345\210\207\346\215\242/main.py" +++ "b/\346\241\214\351\235\242\345\210\207\346\215\242/main.py" @@ -8,10 +8,8 @@ from PySide6.QtWidgets import ( from PySide6.QtCore import Qt, QPoint from PySide6.QtGui import QCursor -from desktop_dirs import get_dirs, find_index_matching_current_dir from switch_desktop import switch_desktop_path - class DesktopWidget(QWidget): def __init__(self, entries): super().__init__() @@ -124,6 +122,9 @@ class DesktopWidget(QWidget): # ---------------------------- 程序入口 ---------------------------- if __name__ == "__main__": + from desktop_dirs import get_dirs, find_index_matching_current_dir + from desktop_component import attach_window_to_desktop_only + app = QApplication(sys.argv) entries = get_dirs() @@ -147,4 +148,12 @@ if __name__ == "__main__": # 否则不高亮,但组件仍显示 widget.show() + + # 获取 Qt 窗口句柄并挂到桌面 + hwnd = int(widget.winId()) # Qt 原生窗口句柄 + if attach_window_to_desktop_only(hwnd): + print("已挂到桌面 ✅") + else: + print("挂到桌面失败 ❌") + sys.exit(app.exec()) diff --git "a/\346\241\214\351\235\242\345\210\207\346\215\242/main_cli.py" "b/\346\241\214\351\235\242\345\210\207\346\215\242/main_cli.py" new file mode 100644 index 0000000000000000000000000000000000000000..fc52ab271c4f66b4fae621d02759e32d978a50f2 --- /dev/null +++ "b/\346\241\214\351\235\242\345\210\207\346\215\242/main_cli.py" @@ -0,0 +1,19 @@ +import switch_desktop +import argparse + +def main(): + parser = argparse.ArgumentParser(description="接收一个路径参数并切换桌面") + parser.add_argument("path", help="输入的路径") + args = parser.parse_args() + + # 直接打印参数 + print(args.path) + + # 切换桌面 + if switch_desktop.switch_desktop_path(args.path): + print("✅ 桌面切换完成并刷新") + else: + print("❌ 桌面切换失败") + +if __name__ == "__main__": + main() diff --git "a/\346\241\214\351\235\242\345\210\207\346\215\242/refresh_desktop.py" "b/\346\241\214\351\235\242\345\210\207\346\215\242/refresh_desktop.py" index 00a4b58e5a54f9eac2c4c20cf88526a0eea0a035..ed5e632dbba9268a47d97ae6eab3930dd29ac10e 100644 --- "a/\346\241\214\351\235\242\345\210\207\346\215\242/refresh_desktop.py" +++ "b/\346\241\214\351\235\242\345\210\207\346\215\242/refresh_desktop.py" @@ -9,30 +9,23 @@ user32 = ctypes.windll.user32 def refresh_desktop(): """ 刷新 Windows 桌面(模拟 F5)。 + 使用 Progman 窗口。 返回 True 表示刷新成功,False 表示未找到桌面窗口。 """ - defview = None - worker = None - while True: - worker = user32.FindWindowExW(None, worker, "WorkerW", None) - if not worker: - break - defview = user32.FindWindowExW(worker, None, "SHELLDLL_DefView", None) - if defview: - break + # 直接获取桌面主窗口 Progman + desktop = user32.FindWindowW("Progman", None) + if not desktop: + return False - listview = user32.FindWindowExW(defview, None, "SysListView32", None) if defview else None + # 发送 F5 消息 + user32.PostMessageW(desktop, WM_KEYDOWN, VK_F5, 0) + user32.PostMessageW(desktop, WM_KEYUP, VK_F5, 0) - if listview: - user32.PostMessageW(listview, WM_KEYDOWN, VK_F5, 0) - user32.PostMessageW(listview, WM_KEYUP, VK_F5, 0) - return True - else: - return False + return True # --------------------------------- if __name__ == "__main__": if refresh_desktop(): print("桌面已刷新 ✅") else: - print("找不到桌面图标窗口 ❌") + print("找不到桌面窗口 ❌") diff --git "a/\350\257\225\351\252\214main.py" "b/\350\257\225\351\252\214main.py" new file mode 100644 index 0000000000000000000000000000000000000000..cd2e3084eade9cb597e2ce50ffe2bde62f378edc --- /dev/null +++ "b/\350\257\225\351\252\214main.py" @@ -0,0 +1,98 @@ +import sys +import ctypes +import win32gui +import win32con +from PySide6.QtWidgets import QApplication, QWidget, QLabel, QVBoxLayout +from PySide6.QtCore import Qt, QPoint + +# ----------------- 拖动可用 ----------------- +MAX_W, MAX_H = 2000, 1200 # 最大尺寸限制 + +class DesktopOverlay(QWidget): + def __init__(self): + super().__init__() + self.dragging = False + self.drag_pos = QPoint() + + # 无边框 + self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint) + self.setAttribute(Qt.WA_TranslucentBackground, False) + + layout = QVBoxLayout(self) + layout.setContentsMargins(0, 0, 0, 0) + + label = QLabel("这是桌面浮层\n可拖动,不挡图标") + label.setStyleSheet("font-size:16px; background:#202020; color:white; padding:8px;") + label.setAlignment(Qt.AlignCenter) + layout.addWidget(label) + + self.resize(300, 120) + + # ----------------- 拖动 ----------------- + def mousePressEvent(self, e): + if e.button() == Qt.LeftButton: + self.dragging = True + self.drag_pos = e.globalPosition().toPoint() + + def mouseMoveEvent(self, e): + if not self.dragging: + return + delta = e.globalPosition().toPoint() - self.drag_pos + self.drag_pos = e.globalPosition().toPoint() + + new_x = self.x() + delta.x() + new_y = self.y() + delta.y() + new_x = max(0, min(new_x, MAX_W - self.width())) + new_y = max(0, min(new_y, MAX_H - self.height())) + + self.move(new_x, new_y) + + def mouseReleaseEvent(self, e): + self.dragging = False + +# ----------------- 找到桌面 WorkerW ----------------- +def get_desktop_hwnd(): + progman = win32gui.FindWindow("Progman", None) + # 发送消息强制创建 WorkerW + win32gui.SendMessageTimeout(progman, 0x052C, 0, 0, win32con.SMTO_NORMAL, 1000) + workerw = None + + def enum_windows(hwnd, lParam): + nonlocal workerw + class_name = win32gui.GetClassName(hwnd) + if class_name == "WorkerW": + child = win32gui.FindWindowEx(hwnd, 0, "SHELLDLL_DefView", None) + if child != 0: + workerw = hwnd + return True + + win32gui.EnumWindows(enum_windows, None) + if workerw: + return workerw + return progman # 回退到 Progman + +# ----------------- 挂到桌面 ----------------- +def attach_to_desktop(widget: QWidget): + hwnd = int(widget.winId()) + desktop_hwnd = get_desktop_hwnd() + + # 设置 WS_CHILD + style = win32gui.GetWindowLong(hwnd, win32con.GWL_STYLE) + style &= ~win32con.WS_POPUP + style |= win32con.WS_CHILD + win32gui.SetWindowLong(hwnd, win32con.GWL_STYLE, style) + + # 父窗口 + win32gui.SetParent(hwnd, desktop_hwnd) + + # 放到左上角 + win32gui.SetWindowPos(hwnd, None, 50, 50, widget.width(), widget.height(), + win32con.SWP_NOZORDER | win32con.SWP_SHOWWINDOW) + + +if __name__ == "__main__": + app = QApplication(sys.argv) + widget = DesktopOverlay() + widget.show() + attach_to_desktop(widget) + sys.exit(app.exec())