As I was looking for an app that supports auto lock when I’m away from my desk… I couldn’t find any that works with my Android phone, not even Microsoft’s native one. So I decided to write one myself.
First time writing a program with GUI, with the help of chatGPT… we have this one.
Setting a shortcut pointing to this target:
"pythonw.exe" bluetoothlocker.py
and it works.
import tkinter as tk
import time
import bluetooth
import logging
import ctypes
import threading
global socket
global thread
MAC_ADDRESS = <MAC>
BT_NAME = <NAME>
PORT = 2
def lock_windows_screen():
"""Using the LockWorkStation to lock windows screen
resume the program when the foreground window is not the locked window
"""
ctypes.windll.user32.LockWorkStation()
time.sleep(3)
locked_window = ctypes.windll.user32.GetForegroundWindow()
while ctypes.windll.user32.GetForegroundWindow() == locked_window:
time.sleep(10)
time.sleep(15)
class App:
def __init__(self) -> None:
# create the window
root = tk.Tk()
root.title("Bluetooth locker")
self.root = root
# create the start button and add click event handler
start_button = tk.Button(root, text="Start", command=self.start_button_click)
start_button.pack()
self.start_button = start_button
# create the stop button and disable it
stop_button = tk.Button(root, text="Stop", command=self.stop_button_click, state="disabled")
stop_button.pack()
self.stop_button = stop_button
self.stop_button_pressed = tk.BooleanVar()
# create a text widget to display logger's output
logger_text = tk.Text(root, height=10, width=60)
logger_text.pack()
# create a handler for the logger to output to the text widget
class WidgetHandler(logging.Handler):
def emit(self, record):
msg = self.format(record) + '\n'
root.after(0, lambda: logger_text.insert('end', msg))
# configure logger to output to both console and text widget
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(asctime)s - %(levelname)s : %(message)s')
widget_handler = WidgetHandler(logging.DEBUG)
widget_handler.setFormatter(formatter)
logger.addHandler(widget_handler)
self.logger = logger
def start_button_click(self):
# disable the start button
self.start_button.config(state="disabled")
# enable the stop button
self.stop_button.config(state="normal")
# disable the close button
self.root.protocol("WM_DELETE_WINDOW", "")
self.stop_button_pressed.set(False)
thread = threading.Thread(target=self.main_loop)
thread.start()
def stop_button_click(self):
self.logger.debug("stop button clicked")
self.stop_button_pressed.set(True)
def main_loop(self):
"""run an infinite loop that test connection to the mac_address every 10 seconds:
using socket.connect for the first time to connect to the mac_address,
then use test_if_connected to test if still connected
If connection is broken, reconnect using socket.connect,
and lock the windows screen
"""
mac_address = MAC_ADDRESS
bt_name = BT_NAME
port = PORT
socket = self.try_connect(mac_address, port, bt_name)
while True:
time.sleep(3)
self.logger.debug("test connection again...")
if not self.test_if_connected(socket, bt_name):
lock_windows_screen()
socket = self.try_connect(mac_address, port, bt_name)
# check if stop button is pressed
if self.stop_button_pressed.get():
# if yes, close the socket connection
socket.close()
# change state of buttons
self.start_button.config(state="normal")
self.stop_button.config(state="disabled")
# enable the close button
# root.protocol("WM_DELETE_WINDOW", on_close)
return
def try_connect(self, mac_address, port, bt_name):
try:
global socket
socket = bluetooth.BluetoothSocket(bluetooth.RFCOMM)
socket.connect((mac_address, port))
except OSError:
self.logger.debug("Failed to connect to %s", mac_address)
socket.close()
return None
else:
self.logger.debug("Connected to %s", bt_name)
self.logger.debug("MAC: %s", mac_address)
return socket
def test_if_connected(self, socket, bt_name):
if socket is None:
self.logger.debug("Lost connection to %s", bt_name)
return False
try:
socket.send("1")
except OSError:
self.logger.debug("Lost connection to %s", bt_name)
socket.close()
return False
else:
self.logger.debug("Still connected to %s", bt_name)
return True
app = App()
# start the window's event loop
app.root.mainloop()