[Python] 纯文本查看 复制代码
import hashlib
import hmac
import tkinter as tk
from tkinter import messagebox
import pyperclip
import sys
import os
import subprocess
import platform
import ctypes
from ctypes import wintypes
# ===================== Win7/10/11 通用 IME 底层API封装 =====================
HWND = wintypes.HWND
HIMC = wintypes.HANDLE
WPARAM = wintypes.WPARAM
LPARAM = wintypes.LPARAM
# 兼容Win7旧ctypes,手动定义LRESULT
if ctypes.sizeof(ctypes.c_void_p) == 4:
LRESULT = ctypes.c_long
else:
LRESULT = ctypes.c_longlong
# IMM 消息常量
WM_IME_SETCONTEXT = 0x0281
WM_IME_COMPOSITION = 0x0283
IMM_DISABLE_IME = 0x0008
IMM_GETCONTEXT = 0x0001
IME_CLOSE = 0
IME_OPEN = 1
# 系统DLL,全Windows版本通用
try:
user3 = ctypes.WinDLL("user32", use_last_error=True)
imm3 = ctypes.WinDLL("imm32", use_last_error=True)
except:
user3 = None
imm3 = None
# 绑定API,增加判空兼容
if user3:
user3.SendMessageW.argtypes = [HWND, wintypes.UINT, WPARAM, LPARAM]
user3.SendMessageW.restype = LRESULT
if imm3:
imm3.ImmGetContext.argtypes = [HWND]
imm3.ImmGetContext.restype = HIMC
imm3.ImmSetOpenStatus.argtypes = [HIMC, wintypes.BOOL]
imm3.ImmSetOpenStatus.restype = wintypes.BOOL
imm3.ImmReleaseContext.argtypes = [HWND, HIMC]
imm3.ImmReleaseContext.restype = wintypes.BOOL
class WinIMEBlocker:
"""全Windows兼容 单控件禁用输入法"""
@staticmethod
def disable_ime_for_hwnd(hwnd):
if platform.system() != "Windows" or not user3 or not imm3:
return
try:
hwnd = HWND(hwnd)
himc = imm3.ImmGetContext(hwnd)
if himc:
imm3.ImmSetOpenStatus(himc, IME_CLOSE)
user3.SendMessageW(hwnd, WM_IME_SETCONTEXT, IMM_DISABLE_IME, 0)
imm3.ImmReleaseContext(hwnd, himc)
user3.SendMessageW(hwnd, WM_IME_COMPOSITION, 0, 0)
except Exception:
pass
@staticmethod
def enable_ime_for_hwnd(hwnd):
if platform.system() != "Windows" or not user3 or not imm3:
return
try:
hwnd = HWND(hwnd)
himc = imm3.ImmGetContext(hwnd)
if himc:
imm3.ImmSetOpenStatus(himc, IME_OPEN)
user3.SendMessageW(hwnd, WM_IME_SETCONTEXT, IMM_GETCONTEXT, 0)
imm3.ImmReleaseContext(hwnd, himc)
except Exception:
pass
# ===================== 资源路径 全系统兼容 =====================
def resource_path(relative_path):
try:
base_path = sys._MEIPASS
except Exception:
base_path = os.path.dirname(os.path.abspath(sys.argv[0]))
return os.path.join(base_path, relative_path)
# ===================== HMAC-MD5 大小写密码生成 =====================
class FlowerPassword:
def generate_password(self, memory, distinguish):
if not memory or not distinguish:
return ""
msg = f"{memory}:{distinguish}".encode("utf-8")
hmac_key = b"52pj"
hmac_obj = hmac.new(hmac_key, msg, digestmod=hashlib.md5)
full_hex = hmac_obj.hexdigest()
# 奇偶交替大小写
mixed_chars = []
for idx, char in enumerate(full_hex):
mixed_chars.append(char.upper() if idx % 2 == 0 else char.lower())
mixed_hex = "".join(mixed_chars)
return mixed_hex[8:24]
# ===================== GUI界面(Win7字体/Emoji兼容) =====================
class FlowerPasswordGUI:
def __init__(self, root):
self.root = root
self.root.title("52pj密码生成器")
self.root.geometry("320x350")
self.root.resizable(False, False)
self.root.configure(bg='#f0f0f0')
self.fp = FlowerPassword()
self.show_full_password = False
self.create_widgets()
self.bind_events()
def create_widgets(self):
main_frame = tk.Frame(self.root, bg='#f0f0f0', padx=30, pady=20)
main_frame.pack(fill=tk.BOTH, expand=True)
# 字体兜底:Win7无微软雅黑自动切换Arial
def get_font(size, bold=False):
try:
return ("微软雅黑", size, "bold" if bold else "")
except:
return ("Arial", size, "bold" if bold else "")
title_label = tk.Label(
main_frame,
text="52pj密码生成器",
font=get_font(22, True),
bg='#f0f0f0', fg='#333333'
)
title_label.pack(pady=(10, 5))
desc_label = tk.Label(
main_frame,
text="输入记忆密码和区分代码,自动生成16位密码",
font=get_font(9),
bg='#f0f0f0', fg='#888888'
)
desc_label.pack(pady=(0, 20))
# 记忆密码框
tk.Label(
main_frame, text="记忆密码:",
font=get_font(10, True), bg='#f0f0f0', fg='#555555', anchor='w'
).pack(fill=tk.X, pady=(0, 3))
self.memory_var = tk.StringVar()
self.memory_var.trace_add('write', lambda *args: self.auto_generate())
self.memory_password = tk.Entry(
main_frame, font=get_font(11), show="*", relief=tk.SOLID, bd=1,
textvariable=self.memory_var
)
self.memory_password.pack(fill=tk.X, pady=(0, 15))
self.memory_password.bind('<FocusIn>', self.cancel_ime_composition)
self.memory_password.bind('<Key>', self.kill_ime_now)
# 区分代码框
tk.Label(
main_frame, text="区分代码 (支持中文):",
font=get_font(10, True), bg='#f0f0f0', fg='#555555', anchor='w'
).pack(fill=tk.X, pady=(0, 3))
self.code_var = tk.StringVar()
self.code_var.trace_add('write', lambda *args: self.auto_generate())
self.distinguish_code = tk.Entry(
main_frame, font=get_font(11), relief=tk.SOLID, bd=1, textvariable=self.code_var
)
self.distinguish_code.pack(fill=tk.X, pady=(0, 20))
self.distinguish_code.bind('<FocusIn>', lambda e: WinIMEBlocker.enable_ime_for_hwnd(self.distinguish_code.winfo_id()))
# 密码输出行
tk.Label(
main_frame, text="生成密码:",
font=get_font(10, True), bg='#f0f0f0', fg='#555555', anchor='w'
).pack(fill=tk.X, pady=(0, 3))
container = tk.Frame(main_frame, bg='white', relief=tk.SUNKEN, bd=2)
container.pack(fill=tk.X)
self.result_var = tk.StringVar()
self.displayed_var = tk.StringVar()
left_wrap = tk.Frame(container, bg="white")
left_wrap.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=(5,0), pady=2)
self.result_display = tk.Entry(
left_wrap, font=("Consolas", 13, "bold"), state='readonly',
readonlybackground='white', bd=0, justify='center',
textvariable=self.displayed_var, width=16
)
self.result_display.pack(side=tk.LEFT)
right_wrap = tk.Frame(container, bg="white")
right_wrap.pack(side=tk.RIGHT, padx=(0,5), pady=2)
# Win7兼容:Emoji失效时显示文字替代
self.eye_btn = tk.Button(
right_wrap,
text="👁" if platform.release() not in ("7",) else "显隐",
command=self.toggle_password_display,
font=("Segoe UI Emoji", 12) if platform.release() not in ("7",) else get_font(9),
bg='white', activebackground='white', fg='#666666',
bd=0, highlightthickness=0, relief=tk.FLAT, padx=2, pady=0, cursor='hand2'
)
self.eye_btn.pack(side=tk.LEFT, padx=(0,3))
self.copy_btn = tk.Button(
right_wrap, text="复制", command=self.copy_password,
font=get_font(9), bg='#2196F3', fg='white', relief=tk.FLAT,
padx=8, pady=2, cursor='hand2'
)
self.copy_btn.pack(side=tk.LEFT)
def cancel_ime_composition(self, event):
try:
hwnd = self.memory_password.winfo_id()
WinIMEBlocker.disable_ime_for_hwnd(hwnd)
event.widget.event_generate('<Escape>')
except:
pass
def kill_ime_now(self, event):
try:
hwnd = self.memory_password.winfo_id()
WinIMEBlocker.disable_ime_for_hwnd(hwnd)
except:
pass
def bind_events(self):
self.memory_password.bind('<Return>', lambda e: self.distinguish_code.focus_set())
self.distinguish_code.bind('<Return>', lambda e: self.copy_password())
def auto_generate(self, *args):
mem = self.memory_var.get()
dis = self.code_var.get()
if mem and dis:
self.result_var.set(self.fp.generate_password(mem, dis))
self.update_displayed_password()
else:
self.result_var.set("")
self.displayed_var.set("")
def update_displayed_password(self):
full = self.result_var.get()
if not full:
self.displayed_var.set("")
return
if self.show_full_password:
self.displayed_var.set(full)
else:
self.displayed_var.set(full[:3] + "******" + full[-3:] if len(full)>=6 else full)
def toggle_password_display(self):
self.show_full_password = not self.show_full_password
self.update_displayed_password()
eye_text = "🔓" if self.show_full_password else "👁"
if platform.release() == "7":
eye_text = "隐藏" if self.show_full_password else "显隐"
self.eye_btn.config(text=eye_text)
def copy_password(self):
pwd = self.result_var.get()
if not pwd:
messagebox.showinfo("提示", "请先输入记忆密码和区分代码")
return
try:
pyperclip.copy(pwd)
messagebox.showinfo("复制成功", "密码已复制到剪贴板!")
print(f"已复制密码: {pwd}")
except Exception as e:
messagebox.showerror("错误", f"复制失败: {str(e)}")
# ===================== 程序入口 =====================
def main():
# Win7 关闭高DPI缩放冲突
if platform.release() == "7":
try:
ctypes.windll.user32.SetProcessDPIAware()
except:
pass
print("正在启动52pj密码生成器...")
root = tk.Tk()
app = FlowerPasswordGUI(root)
# 加载窗口图标,全容错不闪退
try:
icon_path = resource_path("52pj.ico")
if os.path.exists(icon_path):
root.iconbitmap(icon_path)
except Exception as e:
print(f"图标加载跳过: {e}")
# 窗口居中
root.update_idletasks()
w = root.winfo_width()
h = root.winfo_height()
x = (root.winfo_screenwidth() // 2) - (w // 2)
y = (root.winfo_screenheight() // 2) - (h // 2)
root.geometry(f'{w}x{y}+{x}+{y}')
root.after(100, lambda: app.memory_password.focus_set())
print("GUI已启动")
root.mainloop()
if __name__ == "__main__":
# 自动安装剪贴库,Win7兼容pip旧版本
try:
import pyperclip
except ImportError:
print("正在安装pyperclip...")
subprocess.check_call([sys.executable, "-m", "pip", "install", "pyperclip==1.8.2"])
import pyperclip
main()