tkwin11fpsmon 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- tkwin11fpsmon-0.1.0/MANIFEST.in +8 -0
- tkwin11fpsmon-0.1.0/PKG-INFO +46 -0
- tkwin11fpsmon-0.1.0/README.md +35 -0
- tkwin11fpsmon-0.1.0/pyproject.toml +19 -0
- tkwin11fpsmon-0.1.0/setup.cfg +4 -0
- tkwin11fpsmon-0.1.0/tkwin11fpsmon/__init__.py +0 -0
- tkwin11fpsmon-0.1.0/tkwin11fpsmon/__main__.py +200 -0
- tkwin11fpsmon-0.1.0/tkwin11fpsmon.egg-info/PKG-INFO +46 -0
- tkwin11fpsmon-0.1.0/tkwin11fpsmon.egg-info/SOURCES.txt +11 -0
- tkwin11fpsmon-0.1.0/tkwin11fpsmon.egg-info/dependency_links.txt +1 -0
- tkwin11fpsmon-0.1.0/tkwin11fpsmon.egg-info/entry_points.txt +2 -0
- tkwin11fpsmon-0.1.0/tkwin11fpsmon.egg-info/requires.txt +1 -0
- tkwin11fpsmon-0.1.0/tkwin11fpsmon.egg-info/top_level.txt +1 -0
@@ -0,0 +1,46 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: tkwin11fpsmon
|
3
|
+
Version: 0.1.0
|
4
|
+
Summary: Lightweight FPS overlay for Windows 11 using tkinter and DWM flush
|
5
|
+
Author-email: Amanokawa Kaede <73207881+KAEDEAK@users.noreply.github.com>
|
6
|
+
License: MIT
|
7
|
+
Project-URL: Homepage, https://github.com/KAEDEAK/tkwin11fpsmon
|
8
|
+
Requires-Python: >=3.8
|
9
|
+
Description-Content-Type: text/markdown
|
10
|
+
Requires-Dist: pywin32
|
11
|
+
|
12
|
+
# tkwin11fpsmon
|
13
|
+
|
14
|
+
`tkwin11fpsmon` is a minimal FPS monitor overlay for Windows 11 using `tkinter` and `DWM Flush`.
|
15
|
+
It displays the actual screen refresh rate on a selected monitor without relying on external overlays or game hooks.
|
16
|
+
|
17
|
+
## Features
|
18
|
+
|
19
|
+
- Real-time FPS measurement based on DWM frame flush
|
20
|
+
- Simple overlay using tkinter (no external dependencies)
|
21
|
+
- Supports monitor-specific targeting
|
22
|
+
- Lightweight and privacy-friendly (no tracking)
|
23
|
+
|
24
|
+
## Installation
|
25
|
+
|
26
|
+
```
|
27
|
+
pip install tkwin11fpsmon
|
28
|
+
```
|
29
|
+
|
30
|
+
## Usage
|
31
|
+
|
32
|
+
```
|
33
|
+
tkwin11fpsmon # Show monitor list with overlay
|
34
|
+
tkwin11fpsmon -display 1 # Show FPS overlay on monitor 1
|
35
|
+
tkwin11fpsmon -t 60 # Run for 60 seconds
|
36
|
+
tkwin11fpsmon -unlimited # Run until manually closed
|
37
|
+
```
|
38
|
+
|
39
|
+
## Author
|
40
|
+
|
41
|
+
Amanokawa Kaede
|
42
|
+
GitHub: https://github.com/KAEDEAK
|
43
|
+
|
44
|
+
## License
|
45
|
+
|
46
|
+
MIT
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# tkwin11fpsmon
|
2
|
+
|
3
|
+
`tkwin11fpsmon` is a minimal FPS monitor overlay for Windows 11 using `tkinter` and `DWM Flush`.
|
4
|
+
It displays the actual screen refresh rate on a selected monitor without relying on external overlays or game hooks.
|
5
|
+
|
6
|
+
## Features
|
7
|
+
|
8
|
+
- Real-time FPS measurement based on DWM frame flush
|
9
|
+
- Simple overlay using tkinter (no external dependencies)
|
10
|
+
- Supports monitor-specific targeting
|
11
|
+
- Lightweight and privacy-friendly (no tracking)
|
12
|
+
|
13
|
+
## Installation
|
14
|
+
|
15
|
+
```
|
16
|
+
pip install tkwin11fpsmon
|
17
|
+
```
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
```
|
22
|
+
tkwin11fpsmon # Show monitor list with overlay
|
23
|
+
tkwin11fpsmon -display 1 # Show FPS overlay on monitor 1
|
24
|
+
tkwin11fpsmon -t 60 # Run for 60 seconds
|
25
|
+
tkwin11fpsmon -unlimited # Run until manually closed
|
26
|
+
```
|
27
|
+
|
28
|
+
## Author
|
29
|
+
|
30
|
+
Amanokawa Kaede
|
31
|
+
GitHub: https://github.com/KAEDEAK
|
32
|
+
|
33
|
+
## License
|
34
|
+
|
35
|
+
MIT
|
@@ -0,0 +1,19 @@
|
|
1
|
+
[project]
|
2
|
+
name = "tkwin11fpsmon"
|
3
|
+
version = "0.1.0"
|
4
|
+
description = "Lightweight FPS overlay for Windows 11 using tkinter and DWM flush"
|
5
|
+
readme = "README.md"
|
6
|
+
authors = [
|
7
|
+
{ name = "Amanokawa Kaede", email = "73207881+KAEDEAK@users.noreply.github.com" }
|
8
|
+
]
|
9
|
+
license = {text = "MIT"}
|
10
|
+
requires-python = ">=3.8"
|
11
|
+
dependencies = [
|
12
|
+
"pywin32"
|
13
|
+
]
|
14
|
+
|
15
|
+
[project.urls]
|
16
|
+
Homepage = "https://github.com/KAEDEAK/tkwin11fpsmon"
|
17
|
+
|
18
|
+
[project.scripts]
|
19
|
+
tkwin11fpsmon = "tkwin11fpsmon.__main__:main"
|
File without changes
|
@@ -0,0 +1,200 @@
|
|
1
|
+
# File: fpsmon.py
|
2
|
+
|
3
|
+
import argparse
|
4
|
+
import sys
|
5
|
+
import time
|
6
|
+
import ctypes
|
7
|
+
|
8
|
+
import win32api
|
9
|
+
import win32con
|
10
|
+
import tkinter as tk
|
11
|
+
|
12
|
+
# ─── Initialize DWM API ───────────────────────────────
|
13
|
+
# API for synchronizing with Desktop Window Manager frame completion
|
14
|
+
_dwm = ctypes.WinDLL("dwmapi")
|
15
|
+
DwmFlush = _dwm.DwmFlush
|
16
|
+
|
17
|
+
|
18
|
+
def list_monitors():
|
19
|
+
"""
|
20
|
+
Enumerate connected monitors in the order returned by EnumDisplayMonitors,
|
21
|
+
and return a list of tuples:
|
22
|
+
[(num, DeviceName, DeviceString, (left, top, right, bottom)), ...].
|
23
|
+
`num` is a 1-based index.
|
24
|
+
"""
|
25
|
+
# 1) Get monitor handles and rectangles
|
26
|
+
entries = []
|
27
|
+
for hMon, _, _ in win32api.EnumDisplayMonitors(None, None):
|
28
|
+
info = win32api.GetMonitorInfo(hMon)
|
29
|
+
entries.append((info["Device"], info["Monitor"]))
|
30
|
+
|
31
|
+
# 2) Build a map from DeviceName to description string via EnumDisplayDevices
|
32
|
+
desc_map = {}
|
33
|
+
idx = 0
|
34
|
+
while True:
|
35
|
+
try:
|
36
|
+
dev = win32api.EnumDisplayDevices(None, idx)
|
37
|
+
except Exception:
|
38
|
+
break
|
39
|
+
if dev.StateFlags & win32con.DISPLAY_DEVICE_ATTACHED_TO_DESKTOP:
|
40
|
+
desc_map[dev.DeviceName] = dev.DeviceString
|
41
|
+
idx += 1
|
42
|
+
|
43
|
+
# 3) Assign 1-based indices and return the list
|
44
|
+
monitors = []
|
45
|
+
for i, (name, rect) in enumerate(entries):
|
46
|
+
desc = desc_map.get(name, "")
|
47
|
+
monitors.append((i + 1, name, desc, rect))
|
48
|
+
return monitors
|
49
|
+
|
50
|
+
|
51
|
+
def show_identifiers(monitors, duration_ms=3000):
|
52
|
+
"""
|
53
|
+
- Print the monitor list to the console
|
54
|
+
- Display an overlay with numbers 1..N at the center of each monitor for duration_ms milliseconds
|
55
|
+
"""
|
56
|
+
print("=== Available Displays (Monitor Order) ===")
|
57
|
+
for num, name, desc, _ in monitors:
|
58
|
+
print(f"{num}. {name} → {desc}")
|
59
|
+
print("\nUsage examples:")
|
60
|
+
print(" py fpsmon.py -display 1")
|
61
|
+
print(" py fpsmon.py -display \"\\\\.\\DISPLAY2\" -t 60")
|
62
|
+
print(" py fpsmon.py -display 1 -unlimited\n")
|
63
|
+
|
64
|
+
root = tk.Tk()
|
65
|
+
root.withdraw()
|
66
|
+
|
67
|
+
windows = []
|
68
|
+
for num, _, _, rect in monitors:
|
69
|
+
left, top, right, bottom = rect
|
70
|
+
width, height = right - left, bottom - top
|
71
|
+
|
72
|
+
win = tk.Toplevel(root)
|
73
|
+
win.overrideredirect(True)
|
74
|
+
win.attributes('-topmost', True)
|
75
|
+
win.configure(bg='black')
|
76
|
+
x = left + (width // 2) - 150
|
77
|
+
y = top + (height // 2) - 100
|
78
|
+
win.geometry(f"300x200+{x}+{y}")
|
79
|
+
|
80
|
+
lbl = tk.Label(
|
81
|
+
win,
|
82
|
+
text=str(num),
|
83
|
+
font=("Helvetica", 48, "bold"),
|
84
|
+
fg="white",
|
85
|
+
bg="black"
|
86
|
+
)
|
87
|
+
lbl.pack(expand=True, fill="both")
|
88
|
+
windows.append(win)
|
89
|
+
|
90
|
+
def close_all():
|
91
|
+
for w in windows:
|
92
|
+
w.destroy()
|
93
|
+
root.quit()
|
94
|
+
|
95
|
+
root.after(duration_ms, close_all)
|
96
|
+
root.mainloop()
|
97
|
+
|
98
|
+
|
99
|
+
def show_fps_overlay(monitors, selection, duration_s, unlimited):
|
100
|
+
"""
|
101
|
+
Overlay the measured FPS / configured refresh rate on a specified monitor.
|
102
|
+
selection: 1-based index or DeviceName (string)
|
103
|
+
duration_s: duration in seconds (None for unlimited)
|
104
|
+
"""
|
105
|
+
# 1) Determine the target monitor
|
106
|
+
target = None
|
107
|
+
for num, name, desc, rect in monitors:
|
108
|
+
if (isinstance(selection, int) and num == selection) or (selection == name):
|
109
|
+
target = (num, name, desc, rect)
|
110
|
+
break
|
111
|
+
if target is None:
|
112
|
+
print(f"Error: Monitor '{selection}' not found.")
|
113
|
+
sys.exit(1)
|
114
|
+
_, name, _, rect = target
|
115
|
+
|
116
|
+
# 2) Get the configured refresh rate
|
117
|
+
dm = win32api.EnumDisplaySettings(name, win32con.ENUM_CURRENT_SETTINGS)
|
118
|
+
configured = dm.DisplayFrequency
|
119
|
+
|
120
|
+
# 3) Create the overlay window
|
121
|
+
left, top, right, bottom = rect
|
122
|
+
width, height = right - left, bottom - top
|
123
|
+
|
124
|
+
root = tk.Tk()
|
125
|
+
root.overrideredirect(True)
|
126
|
+
root.attributes('-topmost', True)
|
127
|
+
root.configure(bg='black')
|
128
|
+
x = left + (width // 2) - 100
|
129
|
+
y = top + (height // 2) - 50
|
130
|
+
root.geometry(f"200x100+{x}+{y}")
|
131
|
+
|
132
|
+
lbl = tk.Label(
|
133
|
+
root,
|
134
|
+
text="--/--",
|
135
|
+
font=("Helvetica", 32, "bold"),
|
136
|
+
fg="lime",
|
137
|
+
bg="black"
|
138
|
+
)
|
139
|
+
lbl.pack(expand=True, fill="both")
|
140
|
+
|
141
|
+
# 4) Frame synchronization count using DwmFlush
|
142
|
+
start = time.time()
|
143
|
+
last = start
|
144
|
+
count = 0
|
145
|
+
|
146
|
+
while unlimited or (time.time() - start) < duration_s:
|
147
|
+
# Block until the next frame is completed
|
148
|
+
DwmFlush()
|
149
|
+
count += 1
|
150
|
+
now = time.time()
|
151
|
+
if now - last >= 1.0:
|
152
|
+
fps = count
|
153
|
+
lbl.config(text=f"{fps}/{configured}")
|
154
|
+
count = 0
|
155
|
+
last = now
|
156
|
+
# Update UI
|
157
|
+
root.update_idletasks()
|
158
|
+
root.update()
|
159
|
+
|
160
|
+
root.destroy()
|
161
|
+
|
162
|
+
|
163
|
+
def parse_args():
|
164
|
+
p = argparse.ArgumentParser(description="Simple FPS monitor for Windows")
|
165
|
+
p.add_argument(
|
166
|
+
"-display",
|
167
|
+
help="Specify target monitor by 1-based index or DeviceName"
|
168
|
+
)
|
169
|
+
p.add_argument(
|
170
|
+
"-t", type=int, metavar="SECONDS",
|
171
|
+
help="Number of seconds to run (default: 30)"
|
172
|
+
)
|
173
|
+
p.add_argument(
|
174
|
+
"-unlimited", action="store_true",
|
175
|
+
help="Run until manually closed (Ctrl+C to exit)"
|
176
|
+
)
|
177
|
+
return p.parse_args()
|
178
|
+
|
179
|
+
|
180
|
+
def main():
|
181
|
+
args = parse_args()
|
182
|
+
monitors = list_monitors()
|
183
|
+
|
184
|
+
# No display specified -> show monitor index overlays
|
185
|
+
if not args.display:
|
186
|
+
show_identifiers(monitors)
|
187
|
+
return
|
188
|
+
|
189
|
+
# Interpret selection
|
190
|
+
try:
|
191
|
+
sel = int(args.display)
|
192
|
+
except ValueError:
|
193
|
+
sel = args.display
|
194
|
+
|
195
|
+
duration = None if args.unlimited else (args.t if args.t is not None else 30)
|
196
|
+
show_fps_overlay(monitors, sel, duration, args.unlimited)
|
197
|
+
|
198
|
+
|
199
|
+
if __name__ == "__main__":
|
200
|
+
main()
|
@@ -0,0 +1,46 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: tkwin11fpsmon
|
3
|
+
Version: 0.1.0
|
4
|
+
Summary: Lightweight FPS overlay for Windows 11 using tkinter and DWM flush
|
5
|
+
Author-email: Amanokawa Kaede <73207881+KAEDEAK@users.noreply.github.com>
|
6
|
+
License: MIT
|
7
|
+
Project-URL: Homepage, https://github.com/KAEDEAK/tkwin11fpsmon
|
8
|
+
Requires-Python: >=3.8
|
9
|
+
Description-Content-Type: text/markdown
|
10
|
+
Requires-Dist: pywin32
|
11
|
+
|
12
|
+
# tkwin11fpsmon
|
13
|
+
|
14
|
+
`tkwin11fpsmon` is a minimal FPS monitor overlay for Windows 11 using `tkinter` and `DWM Flush`.
|
15
|
+
It displays the actual screen refresh rate on a selected monitor without relying on external overlays or game hooks.
|
16
|
+
|
17
|
+
## Features
|
18
|
+
|
19
|
+
- Real-time FPS measurement based on DWM frame flush
|
20
|
+
- Simple overlay using tkinter (no external dependencies)
|
21
|
+
- Supports monitor-specific targeting
|
22
|
+
- Lightweight and privacy-friendly (no tracking)
|
23
|
+
|
24
|
+
## Installation
|
25
|
+
|
26
|
+
```
|
27
|
+
pip install tkwin11fpsmon
|
28
|
+
```
|
29
|
+
|
30
|
+
## Usage
|
31
|
+
|
32
|
+
```
|
33
|
+
tkwin11fpsmon # Show monitor list with overlay
|
34
|
+
tkwin11fpsmon -display 1 # Show FPS overlay on monitor 1
|
35
|
+
tkwin11fpsmon -t 60 # Run for 60 seconds
|
36
|
+
tkwin11fpsmon -unlimited # Run until manually closed
|
37
|
+
```
|
38
|
+
|
39
|
+
## Author
|
40
|
+
|
41
|
+
Amanokawa Kaede
|
42
|
+
GitHub: https://github.com/KAEDEAK
|
43
|
+
|
44
|
+
## License
|
45
|
+
|
46
|
+
MIT
|
@@ -0,0 +1,11 @@
|
|
1
|
+
MANIFEST.in
|
2
|
+
README.md
|
3
|
+
pyproject.toml
|
4
|
+
tkwin11fpsmon/__init__.py
|
5
|
+
tkwin11fpsmon/__main__.py
|
6
|
+
tkwin11fpsmon.egg-info/PKG-INFO
|
7
|
+
tkwin11fpsmon.egg-info/SOURCES.txt
|
8
|
+
tkwin11fpsmon.egg-info/dependency_links.txt
|
9
|
+
tkwin11fpsmon.egg-info/entry_points.txt
|
10
|
+
tkwin11fpsmon.egg-info/requires.txt
|
11
|
+
tkwin11fpsmon.egg-info/top_level.txt
|
@@ -0,0 +1 @@
|
|
1
|
+
|
@@ -0,0 +1 @@
|
|
1
|
+
pywin32
|
@@ -0,0 +1 @@
|
|
1
|
+
tkwin11fpsmon
|