使用Python實現(xiàn)一鍵隱藏屏幕并鎖定輸入
1. 概述
你是否曾在辦公時被人從背后偷看屏幕?或者在咖啡廳、圖書館等公共場合不想讓別人看到你的私人內(nèi)容?今天,我們將帶你使用 Python 編寫一個一鍵隱藏屏幕并鎖定輸入的黑科技程序,能夠在指定熱鍵觸發(fā)后立即遮擋屏幕,并禁止一切鍵盤鼠標(biāo)輸入。
這款工具基于 Tkinter 和 pynput,不僅能夠全屏覆蓋你的電腦,還支持自定義遮罩圖片和文本,無論是工作還是娛樂,都能幫你有效防止信息泄露。
接下來,我們將詳細講解其功能、代碼實現(xiàn),并帶你手把手打造屬于你的專屬隱私屏!
2. 功能亮點
本項目具備以下核心功能:
一鍵觸發(fā)隱私屏 :用戶可以自定義觸發(fā)熱鍵(默認 Ctrl + Menu),快速激活或隱藏隱私屏。
全屏黑色遮罩 :當(dāng)觸發(fā)后,屏幕會變成黑色,并阻止用戶查看當(dāng)前內(nèi)容。
自定義遮罩內(nèi)容 :
- 可選擇圖片(如公司 Logo)作為屏保;
- 可設(shè)置文本(如“請勿打擾”)。
輸入鎖定 :程序運行時,鍵盤和鼠標(biāo)都會被禁用,確保電腦處于“凍結(jié)”狀態(tài)。
后臺日志記錄 :所有操作都會被記錄,方便調(diào)試與監(jiān)控。
3.代碼實現(xiàn)
以下是完整的 Python 代碼:
import sys import os import ctypes import tkinter as tk import datetime import threading import time from tkinter import Label from PIL import Image, ImageTk import configparser from pynput import keyboard import logging from logging.handlers import TimedRotatingFileHandler # 設(shè)置日志 def setup_logging(): log_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'logs') if not os.path.exists(log_dir): os.makedirs(log_dir) log_file = os.path.join(log_dir, 'app.log') handler = TimedRotatingFileHandler( log_file, when="midnight", interval=1, backupCount=31, encoding='utf-8' ) handler.suffix = "%Y-%m-%d.log" formatter = logging.Formatter('[%(asctime)s] %(message)s', datefmt='%H:%M:%S') handler.setFormatter(formatter) logger = logging.getLogger() logger.setLevel(logging.DEBUG) logger.addHandler(handler) setup_logging() screen_visible = False hotkey_combination = [] show_debugger = False _blocking_thread = None _stop_blocking = False def _lock_input_periodically(screen = None): global _stop_blocking, hotkey_combination while not _stop_blocking: ctypes.windll.user32.BlockInput(True) screen and screen.getFocus() set_keys = set(hotkey_combination) if {'Ctrl_l', 'Ctrl_r'} & set_keys and {'Alt_l', 'Alt_gr'} & set_keys and 'Delete' in set_keys: hotkey_combination = [k for k in hotkey_combination if k not in {'Ctrl_l', 'Ctrl_r', 'Alt_l', 'Alt_gr', 'Delete'}] if show_debugger: logging.debug("輸入&焦點 鎖定") time.sleep(0.5) class PrivacyScreen: def __init__(self, root, config): start_time = datetime.datetime.now() self.root = root self.config = config self.initUI() elapsed_time = (datetime.datetime.now() - start_time).total_seconds() logging.debug(f"創(chuàng)建完成 - {elapsed_time}s") def initUI(self): logging.debug("開始初始化窗口") self.root.attributes('-fullscreen', True) self.root.configure(background='black') self.root.attributes('-topmost', True) self.root.bind("<Escape>", lambda e: None) self.root.config(cursor="none") self.center_frame = tk.Frame(self.root, bg='black') self.center_frame.pack(expand=True, fill="both") widgets = [] if 'covimg' in self.config and self.config['covimg'] != '': image_path = self.config['covimg'] if os.path.exists(image_path): try: logging.debug(f"加載圖片 - {image_path}") image = Image.open(image_path) self.image = ImageTk.PhotoImage(image) self.image_label = Label(self.center_frame, image=self.image, bg="black") widgets.append(self.image_label) except Exception as e: logging.error(f"圖片錯誤 - {e}") if 'covtxt' in self.config and self.config['covtxt'] != '': text = self.config['covtxt'] self.text_label = Label(self.center_frame, text=text, fg='#999', bg='black', font=('Microsoft YaHei', 48, 'bold')) widgets.append(self.text_label) if len(widgets) == 2: y_offset = -60 else: y_offset = 0 if len(widgets) > 0: for i, widget in enumerate(widgets): widget.place(relx=0.5, rely=0.5, anchor="center", y=y_offset) y_offset += 215 def showScreen(self): global screen_visible screen_visible = True self.root.deiconify() block_input(True, self) logging.debug("繪制組件 - ■") def hideScreen(self): global screen_visible screen_visible = False self.root.withdraw() block_input(False) logging.debug("繪制組件 - □") def getFocus(self): self.root.focus_force() def get_log_time(): return datetime.datetime.now().strftime("%H:%M:%S") def block_input(block, screen = None): global _blocking_thread, _stop_blocking try: logging.debug(f"阻塞輸入 - {'■' if block else '□'}") if block: if _blocking_thread is None or not _blocking_thread.is_alive(): _stop_blocking = False _blocking_thread = threading.Thread(target=_lock_input_periodically, args=(screen,)) _blocking_thread.daemon = True _blocking_thread.start() else: _stop_blocking = True if _blocking_thread is not None and _blocking_thread.is_alive(): _blocking_thread.join() ctypes.windll.user32.BlockInput(False) except Exception as e: logging.error(f"阻塞失敗 - {e}") def toggle_privacy_screen(screen): if screen_visible: logging.debug("隱私窗口 - □") screen.hideScreen() else: logging.debug("隱私窗口 - ■") screen.showScreen() def get_config_path(): if hasattr(sys, '_MEIPASS'): base_path = sys._MEIPASS else: base_path = os.path.dirname(os.path.abspath(__file__)) config_path = os.path.join(base_path, 'psc.conf') logging.debug(f"配置文件路徑: {config_path}") return config_path def read_config(): config = configparser.ConfigParser() config_file = get_config_path() if not os.path.exists(config_file): logging.error(f"配置丟失: {config_file}") sys.exit(1) with open(config_file, 'r', encoding='utf-8') as f: logging.debug("讀取配置 - Start") config.read_file(f) settings = { 'hotkey': config.get('DEFAULT', 'hotkey', fallback='Ctrl_r+Menu'), 'covimg': config.get('DEFAULT', 'covimg', fallback=''), 'covtxt': config.get('DEFAULT', 'covtxt', fallback='該設(shè)備已鎖定'), 'strict': config.get('DEFAULT', 'strict', fallback=True), 'debugs': config.get('DEFAULT', 'debugs', fallback=False) } settings['strict'] = str(settings['strict']).lower() == 'true' or settings['strict'] == '1' settings['debugs'] = str(settings['debugs']).lower() == 'true' or settings['debugs'] == '1' global show_debugger show_debugger = settings['debugs'] logging.debug(f"配置加載 - Success") logging.debug(f"配置內(nèi)容 - {settings}") return settings def parse_hotkey(hotkey_str): keys = hotkey_str.split('+') logging.debug(f"解析熱鍵: {hotkey_str} -> {keys}") return [key.strip() for key in keys] def convert_special_key(input_string): return "" if any(f'F{i}' in input_string.upper() for i in range(13, 25)) else ''.join(chr(ord(c) + 64) if 1 <= ord(c) <= 26 else c for c in input_string or "") def register_hotkey(hotkey, callback, strict): def on_press(key): global hotkey_combination try: key_name = convert_special_key(key.char if hasattr(key, 'char') else key.name) if key_name: key_name = key_name.capitalize() if key_name not in hotkey_combination: hotkey_combination.append(key_name) if show_debugger: logging.debug(f"i 按鍵 - ■ - {key_name} 當(dāng)前 - {hotkey_combination}") if strict == 0: if all(k in hotkey_combination for k in hotkey): logging.info("★ 熱鍵觸發(fā)") callback() else: if sorted(hotkey_combination) == sorted(hotkey): logging.info("★ 熱鍵觸發(fā)") callback() except AttributeError: pass def on_release(key): global hotkey_combination try: key_name = convert_special_key(key.char if hasattr(key, 'char') else key.name) if key_name: key_name = key_name.capitalize() if key_name in hotkey_combination: hotkey_combination.remove(key_name) if key_name.startswith("Shift") and all(len(i) == 1 for i in hotkey_combination): hotkey_combination = [] if show_debugger: logging.debug(f"i 按鍵 - □ - {key_name} 當(dāng)前 - {hotkey_combination}") except AttributeError: pass listener = keyboard.Listener(on_press=on_press, on_release=on_release) listener.start() logging.debug("鍵盤監(jiān)聽 - Running") return listener def main(): logging.debug("") logging.debug("# ========== 程序啟動 ========== #") logging.debug("") try: config = read_config() hotkey = parse_hotkey(config['hotkey']) root = tk.Tk() root.withdraw() privacy_screen = PrivacyScreen(root, config) register_hotkey(hotkey, lambda: toggle_privacy_screen(privacy_screen), config['strict']) root.mainloop() except Exception as e: logging.error(f"未知異常 - {e}", exc_info=True) raise if __name__ == "__main__": main()
代碼解析:
日志管理:程序會在 logs/ 目錄下自動創(chuàng)建日志文件,按日期存儲。
熱鍵監(jiān)聽:使用 pynput 監(jiān)聽鍵盤輸入,檢測到特定按鍵組合時觸發(fā)屏幕遮罩。
隱私屏 UI:
- 采用 Tkinter 全屏窗口,背景黑色。
- 支持加載本地圖片和文本。
鍵盤鼠標(biāo)鎖定:調(diào)用 ctypes.windll.user32.BlockInput(True) 禁用所有輸入。
配置文件 **psc.conf**:
hotkey:設(shè)置觸發(fā)熱鍵。
covimg:遮罩圖片路徑。
covtxt:遮罩文本內(nèi)容。
strict:是否啟用嚴(yán)格模式。
debugs:是否開啟調(diào)試信息。
4.使用方法
1. 運行環(huán)境
Windows 系統(tǒng)(目前僅支持 Windows,Mac/Linux 需額外適配)
Python 3.7+
依賴庫安裝:
pip install pillow pynput
2. 配置文件
創(chuàng)建 psc.conf 文件,填入以下內(nèi)容:
[DEFAULT] hotkey=Ctrl_r+Menu covimg= covtxt=該設(shè)備已鎖定 strict=True debugs=False
3. 運行程序
在終端執(zhí)行:
python privacy_screen.py
按下 Ctrl + Menu 觸發(fā)隱私屏,再次按下相同熱鍵可解除。
5. 展示效果
6. 代碼優(yōu)化與拓展
目前的版本已經(jīng)實現(xiàn)了基礎(chǔ)功能,后面將進行進行以下優(yōu)化:
提升安全性:
- 目前的 BlockInput(True) 在某些情況下可能會失效,可以結(jié)合 Windows API 進一步增強鎖定能力。
- 添加密碼解鎖功能,防止誤操作。
增強兼容性:
- 適配 Mac 和 Linux,使用 Xlib 或 pyautogui 進行輸入鎖定。
- 提供跨平臺 GUI,如 PyQt。
新增遠程控制:
- 通過 Flask 或 WebSocket 遠程控制隱私屏。
- 在手機端發(fā)送指令激活/解除鎖定。
7. 總結(jié)
本項目提供了一種便捷的隱私保護方案,適用于程序員、設(shè)計師、財務(wù)人員、商務(wù)人士等需要保護屏幕內(nèi)容的用戶。它具有 快速響應(yīng)、完全遮擋、可定制、輸入鎖定 等特點,是一個實用的 Python 黑科技工具。
到此這篇關(guān)于使用Python實現(xiàn)一鍵隱藏屏幕并鎖定輸入的文章就介紹到這了,更多相關(guān)Python屏幕隱藏與鎖定內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python在for循環(huán)里處理大數(shù)據(jù)的推薦方法實例
這篇文章主要介紹了Python在for循環(huán)里處理大數(shù)據(jù)的推薦方法實例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2024-01-01FastApi如何快速構(gòu)建一個web項目的實現(xiàn)
本文主要介紹了FastApi如何快速構(gòu)建一個web項目的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-03-03使用pandas讀取表格數(shù)據(jù)并進行單行數(shù)據(jù)拼接的詳細教程
這篇文章主要介紹了使用pandas讀取表格數(shù)據(jù)并進行單行數(shù)據(jù)拼接的詳細教程,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03Python+OpenCV檢測燈光亮點的實現(xiàn)方法
這篇文章主要介紹了Python+OpenCV檢測燈光亮點的實現(xiàn)方法,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11