How do I change the screen brightness in windows using python? - python

How do I change the screen brightness in windows using python, without using any extra python packages?
I'd also like a way of getting what the screen brightness is currently at.
I'm thinking that will need to be by using ctypes, but I can't find any information on how to do it.
It annoys me the way the screen brightness buttons on windows adjust the screen brightness in very large increments, so I made a python tkinter program to display the current screen brightness on the taskbar and when I scroll the mouse wheel on the tkinter window it changes the screen brightness:
import subprocess
from tkinter import Canvas, Tk
win = Tk()
win.overrideredirect(True)
canvas = Canvas(win, bg = "#101010", highlightthickness = 0)
canvas.pack(fill = "both", expand = True)
def trim(string, l = None, r = None, include = False, flip = False):
string = str(string)
if l and l in string:
string = string[(string.rindex(l) if flip else string.index(l)) + (0 if include else len(l)):]
if r and r in string:
string = string[:(string.index(r) if flip else string.rindex(r)) + (len(r) if include else 0)]
return string
def set_screen_brightness():
subprocess.run(
["powershell",
f"(Get-WmiObject -Namespace root/WMI -Class WmiMonitorBrightnessMethods).WmiSetBrightness(1,{current_brightness})"],
stdout = subprocess.PIPE, stderr = subprocess.STDOUT, shell = True)
def get_screen_brightness():
value = subprocess.check_output(
["powershell", f"Get-Ciminstance -Namespace root/WMI -ClassName WmiMonitorBrightness"],
shell = True)
return int(trim(value, l = "CurrentBrightness : ", r = r"\r\nInstanceName : "))
current_brightness = get_screen_brightness()
brightness_text = canvas.create_text(30, 25, text = current_brightness,
font = ("Segue ui", 14, "bold"), fill = "White", anchor = "w")
sw, sh = win.winfo_screenwidth(), win.winfo_screenheight()
win.geometry(f"69x50+{sw - 505}+{sh - 49}")
def mouse_wheel_screen_brightness(scroll):
global current_brightness, mouse_wheel_screen_brightness_wa
if "mouse_wheel_screen_brightness_wa" in globals():
win.after_cancel(mouse_wheel_screen_brightness_wa)
current_brightness += 2 if scroll else -2
if current_brightness < 0: current_brightness = 0
if current_brightness > 100: current_brightness = 100
canvas.itemconfig(brightness_text, text = current_brightness)
mouse_wheel_screen_brightness_wa = win.after(100, lambda: set_screen_brightness())
win.bind("<MouseWheel>", lambda e: mouse_wheel_screen_brightness(e.delta > 0))
def topmost():
win.attributes("-topmost", True)
win.after(100, topmost)
topmost()
win.mainloop()
I'm sure there must be a fast way of changing the screen brightness in ctypes, without any extra python packages. With using a subprocess call to Powershell the screen brightness text keeps freezing.
I want to do it without using any extra python packages because when I try to install a python package it says that there was a problem confirming the ssl certificate. I googled it and tried to fix it, but I can't get it to work.

The another way to do it without any library is:
import subprocess
def run(cmd):
completed = subprocess.run(["powershell", "-Command", cmd], capture_output=True)
return completed
if __name__ == '__main__':
take_brightness = input("Please enter the brightness level: ")
command = "(Get-WmiObject -Namespace root/WMI -Class WmiMonitorBrightnessMethods).WmiSetBrightness(1," + take_brightness + ")"
hello_command = f"Write-Host {command}"
hello_info = run(hello_command)

by the help of PowerShell commands we can easily increase or decrease the brightness of windows without any external packages
WmiSetBrightness(1,<brightness % goes here>)
import subprocess
subprocess.run(["powershell", "(Get-WmiObject -Namespace root/WMI -Class WmiMonitorBrightnessMethods).WmiSetBrightness(1,40)"])
the subprocess is the internal library that comes with python.
just run the above code,
hope this will work.

Install screen brightness control using pip
Windows: pip install screen-brightness-control
Mac/Linux: pip3 install screen-brightness-control I guess
Then use this code
import screen_brightness_control as sbc
sbc.set_brightness(25) # Number will be any number between 0 and hundred
# Sets screen brightness to 25%
I found info on the screen brightness module here

I used the WMI library and it really worked fine. Here is the code, but this is for Windows. I think it is OS specific so if it doesn't work for you, you should look for a better solution.
import wmi
brightness = 40 # percentage [0-100] For changing thee screen
c = wmi.WMI(namespace='wmi')
methods = c.WmiMonitorBrightnessMethods()[0]
methods.WmiSetBrightness(brightness, 0)
Please upvote and accept the answer if you like it.

Related

Calling a function from another python file takes 15 seconds, compared to running it in the same module

So, in an effort to refactor my code into a more modular project, i decided to export some of my most used functions, method and classes to separate py modules, so that i can simply "from x import y" and then use method y instead of copy-pasting the code (yes, i know that's horrible, but when you get "implement this yesterday" requests there is only so much you can do".
As an example, i often have to scan COM ports in my system and pick one or more, so i created this module:
from serial.tools import list_ports
from serial import Serial, SerialException
import tkinter as tk
from functools import partial
def COMScanner():
allports = []
ports = list_ports.comports()
for port, desc, hwid in sorted(ports):
hwid = hwid.split(" SER")[0]
# print("{}: {} [{}]".format(port, desc, hwid)) #DBG
try:
s = Serial(port)
s.close()
state = "FREE"
except (OSError, SerialException):
state = "BUSY"
pass
allports.append([port, hwid, state])
return allports
def targetSelector(COMS):
global sel_com
sel_com = None
# Once all COM ports are detected, if there are more than one, the user must pick one
# to connect to the testing board, the user must click the button with the name of
# the desired COM port and dismiss the dialog
if COMS and len(COMS) > 1:
COMSelector = tk.Tk()
baseWidth = 8 * len("".join(max(COMS, key=len)))
baseHeight = 35 * len(COMS)
finalWidth = baseWidth + 10
finalHeight = baseHeight # * len(COMS)
screen_width = COMSelector.winfo_screenwidth()
screen_height = COMSelector.winfo_screenheight()
x_coordinate = int((screen_width / 2) - (finalWidth / 2))
y_coordinate = int((screen_height / 2) - (finalHeight / 2))
COMSelector.geometry("{}x{}+{}+{}".format(finalWidth, finalHeight, x_coordinate, y_coordinate))
COMSelector.update_idletasks()
COMSelector.title("Select Target")
def save_action(selection):
global sel_com, user_pass
sel_com = str(selection)
COMSelector.destroy()
for id, COM in enumerate(COMS):
COM_HANDLE = str(COM[0])
COM_PID = str(COM[1])
COM_STATE = str(COM[2])
action = partial(save_action, COM_HANDLE)
COMLabel = tk.Label(master=COMSelector, text=COM_PID, borderwidth=0.5, relief="solid")
COMButton = tk.Button(master=COMSelector,
text=("[" + COM_STATE + "] " + COM_HANDLE),
command=action
)
if COM_STATE == "FREE":
COMButton.config(state="active")
else:
COMButton.config(state="disabled")
COMButton.grid(row=id, column=0, pady=5, padx=5, sticky="WE")
COMLabel.grid(row=id, column=1, pady=5, padx=5, sticky="WE")
COMSelector.mainloop()
else:
sel_com = COMS[0]
try:
return sel_com
except:
return "No target selected."
A typical usage might be, use COMScanner() to get the relevant port info and then targetSelector() to display the UI and let the user choose.
By defining the functions inside my program, both functions execute instantly (as expected)
By instead creating a module, in a folder I.E. "Snippets\COMSelector.py" and then using something like
from Snippets import COMSelector
[...]
start_time datetime.now()
available_COMS = COMSelector.COMScanner()
target = COMSelector.targetSelector(available_COMS)
print(datetime.now() - start_time)
with only one COM interface connected to the system, to eliminate the human clicking speed factor
i get 0:00:15.245072
Since i'm a beginner, i might be missing something crucial, please help!
There apparently was an issue with my USB controller, rebooting didn't fix it, had to disable and re-enable the driver in my device manager, somehow it took a really long time executing the
"from serial.tools import list_ports" and
"from serial import Serial, SerialException" lines
about 7.4 - 7.5s each, not only that, each time i tried importing anything from the pyserial module it took that long.
i have no idea what caused this but, it's fixed now, marking as solved.

How to retain variable information in Tkinter?

I am trying to convert a text adventure originally made in vanilla Python to a Tkinter format. My attempt at this was to create a dictionary that would be updated whenever information was entered, but the dictionary information isn't saving and seems to revert back to an empty dict every time.
How would I do this ? Apologies if the question is unclear, I am very new to Tkinter and have been struggling with this for a long time.
Here is my code, all it needs to do is figure out if the player wants to activate the tutorial :
from tkinter import *
# Storage
game_text = {}
cmd = {}
root = Tk()
# Configuration
root.geometry ("1000x1000")
root.title("A New Dawn")
icon = PhotoImage(file = "C:/Users/gwynn/Desktop/wcnd_icon.png")
root.iconphoto(False, icon)
root.configure(bg="#006644")
# Parsers
def parse(tag, line):
game_text[tag] = Text(root, width = 200, height = 1)
game_text[tag].insert(INSERT, line)
game_text[tag].pack()
game_text[tag].tag_add(tag, '1.0', 'end')
game_text[tag].tag_config(tag, background = "#006644", foreground = "#8cd98c")
def cmd_parse(cmd_box):
cmd['cmd'] = cmd_box.widget.get()
cmd['cmd'] = cmd['cmd'].lower()
print(cmd['cmd'])
# The Game
parse('tutorial', "Welcome to WC : A New Dawn ! Before we begin - would you like to activate the tutorial ? [Y/N]")
cmd_box = Entry(root, background = '#096', foreground = "#b3e6b3", width = 200, border = 3)
cmd_box.pack()
cmd_box.bind("<Return>", cmd_parse)
print(cmd)
if 'cmd' in list(cmd):
if cmd['cmd'] == "y":
parse('tutorial_y', "Excellent ! The tutorial has been activated.")
elif cmd['cmd'] == "n":
parse('tutorial_n', "Excellent ! The tutorial has been deactivated.")
root.mainloop()
You are trying to manage cmd conditions before the user has even had the chance to type. You have to move your conditions (or call a function of your conditions) after you have actually retrieved the typed data.
def cmd_parse(event):
cmd = event.widget.get().lower()
if cmd == "y":
parse('tutorial_y', "Excellent ! The tutorial has been activated.")
elif cmd == "n":
parse('tutorial_n', "Excellent ! The tutorial has been deactivated.")

Screen rotation in windows with python

I am trying to write a python script to rotate screen in Windows.
I have clues of doing it with Win32api.
What are the other possibilities or commands to achieve so(Win32api included).
you can use below code for screen rotation in any angle, I changed the code given by Mxl above.
import win32api as win32
import win32con
import sys
import re
x = 0
args=sys.argv[1].lower()
rotation_val=0
m = re.search("(?<=^-rotate=)\S+", args) # Use non-white character wildcard instead of d decimal
if (m != None):
print m.group(0)
if ((m.group(0) == "180")):
rotation_val=win32con.DMDO_180
elif((m.group(0) == "90")):
rotation_val=win32con.DMDO_270
elif ((m.group(0) == "270")):
rotation_val=win32con.DMDO_90
else:
rotation_val=win32con.DMDO_DEFAULT
device = win32.EnumDisplayDevices(None,x)
dm = win32.EnumDisplaySettings(device.DeviceName,win32con.ENUM_CURRENT_SETTINGS)
if((dm.DisplayOrientation + rotation_val)%2==1):
dm.PelsWidth, dm.PelsHeight = dm.PelsHeight, dm.PelsWidth
dm.DisplayOrientation = rotation_val
win32.ChangeDisplaySettingsEx(device.DeviceName,dm)
for running this script you will need to give the following command:-
filename.py -rotate=180
filename.py -rotate=0
filename.py -rotate=90
filename.py -rotate=270
you can simply use rotate-screen library to do screen rotations. (Only support for Windows right now)
import rotatescreen
screen = rotatescreen.get_primary_display()
screen.rotate_to(90) # rotate to 90 degrees
This is (a sligtly modified version of) the code that worked for me from the answer given above prvided by lbenini. Possible screen rotation values are win32con.DMDO_DEFAULT (0°), win32con.DMDO_90, win32con.DMDO_180 and win32con.DMDO_270 (one can obtain a list by typing help(win32con))
import win32api as win32
import win32con
def printAllScreen():
i = 0
while True:
try:
device = win32.EnumDisplayDevices(None,i);
print("[%d] %s (%s)"%(i,device.DeviceString,device.DeviceName));
i = i+1;
except:
break;
return i
screen_count=printAllScreen()
x = int(input("\nEnter a display number [0-%d]: "%screen_count))
device = win32.EnumDisplayDevices(None,x);
print("Rotate device %s (%s)"%(device.DeviceString,device.DeviceName));
dm = win32.EnumDisplaySettings(device.DeviceName,win32con.ENUM_CURRENT_SETTINGS)
dm.DisplayOrientation = win32con.DMDO_180
dm.PelsWidth, dm.PelsHeight = dm.PelsHeight, dm.PelsWidth
dm.Fields = dm.Fields & win32con.DM_DISPLAYORIENTATION
win32.ChangeDisplaySettingsEx(device.DeviceName,dm)
If you have the rotate shortcut active in windows (CTRL+ALT+ARROW KEY) you can use pyautogui.hotkey function.

Why is the Windows prompt unresponsive after using a python curses window?

First of all, I'm a newby in python. Had to take a course of it in college and got hooked by its efficiency.
I have this sticky problem where the Windows 7 prompt becomes unresponsive after using a curses window. In Windows 10 it works well. Note that I'm using the Win7 terminal with its default settings. In my code I create a curses window to show 2 simultaneous progress bars, each for a file download. I implemented this by passing the curses window to a FileDownload class (one class instance for each download) that handles its progress bar inside this window. Oddly, in Windows 7 when the downloads are done and the control returns to the prompt, it becomes unresponsive to the keyboard. I worked around this by invoking curses.endwin() after using the window, but this causes the prompt to display all the way down the screen buffer, what hides the curses window.
Here is my code. Any ideas are greatly appreciated. Thanks!
# Skeleton version for simulations.
# Downloads 2 files simultaneously and shows a progress bar for each.
# Each file download is a FileDownload object that interacts with a
# common curses window passed as an argument.
import requests, math, threading, curses, datetime
class FileDownload:
def __init__(self, y_pos, window, url):
# Y position of the progress bar in the download queue window.
self.__bar_pos = int(y_pos)
self.__progress_window = window
self.__download_url = url
# Status of the file download object.
self.__status = "queued"
t = threading.Thread(target=self.__file_downloader)
t.start()
# Downloads selected file and handles its progress bar.
def __file_downloader(self):
file = requests.get(self.__download_url, stream=True)
self.__status = "downloading"
self.__progress_window.addstr(self.__bar_pos + 1, 1, "0%" + " " * 60 + "100%")
size = int(file.headers.get('content-length'))
win_prompt = "Downloading " + format(size, ",d") + " Bytes:"
self.__progress_window.addstr(self.__bar_pos, 1, win_prompt)
file_name = str(datetime.datetime.now().strftime("%Y-%m-%d_%H.%M.%d"))
dump = open(file_name, "wb")
# Progress bar length.
bar_space = 58
# Same as an index.
current_iteration = 0
# Beginning position of the progress bar.
progress_position = 4
# How many iterations will be needed (in chunks of 1 MB).
iterations = math.ceil(size / 1024 ** 2)
# Downloads the file in 1MB chunks.
for block in file.iter_content(1024 ** 2):
dump.write(block)
# Progress bar controller.
current_iteration += 1
step = math.floor(bar_space / iterations)
if current_iteration > 1:
progress_position += step
if current_iteration == iterations:
step = bar_space - step * (current_iteration - 1)
# Updates the progress bar.
self.__progress_window.addstr(self.__bar_pos + 1, progress_position,
"#" * step)
dump.close()
self.__status = "downloaded"
# Returns the current status of the file download ("queued", "downloading" or
# "downloaded").
def get_status(self):
return self.__status
# Instantiates each file download.
def files_downloader():
# Creates curses window.
curses.initscr()
win = curses.newwin(8, 70)
win.border(0)
win.immedok(True)
# Download URLs.
urls = ["http://ipv4.download.thinkbroadband.com/10MB.zip",
"http://ipv4.download.thinkbroadband.com/5MB.zip"]
downloads_dct = {}
for n in range(len(urls)):
# Progress bar position in the window for the file.
y_pos = n * 4 + 1
downloads_dct[n + 1] = FileDownload(y_pos, win, urls[n])
# Waits for all files to be downloaded before passing control of the terminal
# to the user.
all_downloaded = False
while not all_downloaded:
all_downloaded = True
for key, file_download in downloads_dct.items():
if file_download.get_status() != "downloaded":
all_downloaded = False
# Prevents the prompt from returning inside the curses window.
win.addstr(7, 1, "-")
# This solves the unresponsive prompt issue but hides the curses window if the screen buffer
# is higher than the window size.
# curses.endwin()
while input("\nEnter to continue: ") == "":
files_downloader()
Perhaps you're using cygwin (and ncurses): ncurses (like any other curses implementation) changes the terminal I/O mode when it is running. The changes that you probably are seeing is that
input characters are not echoed
you have to type controlJ to end an input line, rather than just Enter
output is not flushed automatically at the end of each line
It makes those changes to allow it to read single characters and also to use the terminal more efficiently.
To change back to the terminal's normal I/O mode, you would use the endwin function. The reset_shell_mode function also would be useful.
Further reading:
endwin (ncurses manual)
reset_shell_mode (ncurses manual)

PythonWin saving session state

I would like to be able to save my session state within the PythonWin editor (e.g. these three files are opened and positioned in these particular locations within the PythonWin window). I can get handles to each of the child windows within PythonWin using win32gui, as well as the titles of each of the files and the positions/sizes of the windows. I'm unclear though in how to get the full path for the file listed as the child window name (i.e. if child window name is test.py and test.py lives at c:\python\test.py, I don't know how to get c:\python). I was thinking I would write out which files were opened plus their window positions to a small file that I would then call at PythonWin start time for loading.
Any ideas on how to get the full paths to the child window names?
Alternatively if someone already has a more elegant solution for saving session state in PythonWin please pass it along.
Below is the code I'm using right now (thanks to Michal Niklas for the starter code for using win32gui).
import win32gui
import re
MAIN_HWND = 0
def is_win_ok(hwnd, starttext):
s = win32gui.GetWindowText(hwnd)
if s.startswith(starttext):
global MAIN_HWND
MAIN_HWND = hwnd
return None
return 1
def find_main_window(starttxt):
global MAIN_HWND
win32gui.EnumChildWindows(0, is_win_ok, starttxt)
return MAIN_HWND
def winPos(hwnd):
if type(hwnd) == type(1): ( left, top, right, bottom ) = win32gui.GetWindowRect(hwnd)
return "%i, %i, %i, %i" % (left, right, top, bottom)
def winName(hwnd, children):
s = win32gui.GetWindowText(hwnd)
rePy = re.compile(r'[a-zA-Z1-9_ ]*.py')
rePySearch = rePy.search(s)
if rePySearch is not None:
if rePySearch.group()[0:7] != "Running":
s = s + ',' + winPos(hwnd) + '\n'
children.append(s)
return 1
def main():
children = []
main_app = 'PythonWin'
hwnd = win32gui.FindWindow(None, main_app)
if hwnd < 1:
hwnd = find_main_window(main_app)
if hwnd:
win32gui.EnumChildWindows(hwnd, winName, children)
filename = "sessionInfo.txt"
sessionFile = os.path.join(sys.path[0],filename)
fp=open(sessionFile, 'wb')
for i in range(len(children)):
fp.write(children[i])
fp.close()
main()
I could be wrong, but isn't PythonWin written in Python?
Have you tried reading the source to the "Save" command to figure out where it stores its full paths?
(I'd take a look myself, but I haven't used Windows in half a decade)

Categories

Resources