refactoring as gui application
:# Please enter the commit message for your changes. Lines starting
This commit is contained in:
parent
0b8f3ad9b6
commit
65f3a5c1da
156
__main__.py
156
__main__.py
@ -1,155 +1,5 @@
|
||||
import asyncio
|
||||
DEBUG=False
|
||||
try:
|
||||
from winrt.windows.media.control import GlobalSystemMediaTransportControlsSessionManager as MediaManager
|
||||
except:
|
||||
print("DEBUG; winrt disabled")
|
||||
DEBUG = True
|
||||
import win32com.client
|
||||
import time
|
||||
import pythoncom
|
||||
from gui import Gui
|
||||
|
||||
from resources import LineState, CLMgrMessage
|
||||
|
||||
import serial
|
||||
from serial import SerialException
|
||||
import session_event_listener as sel
|
||||
import ctypes
|
||||
|
||||
portName = 'COM3'
|
||||
|
||||
global_inactive = True
|
||||
|
||||
# Lock Screen detection
|
||||
user32 = ctypes.windll.User32
|
||||
OpenDesktop = user32.OpenDesktopA
|
||||
SwitchDesktop = user32.SwitchDesktop
|
||||
DESKTOP_SWITCHDESKTOP = 0x0100
|
||||
|
||||
global_screen_locked = False
|
||||
|
||||
def check_screen_locked():
|
||||
hDesktop = OpenDesktop ("default", 0, False, DESKTOP_SWITCHDESKTOP)
|
||||
result = SwitchDesktop (hDesktop)
|
||||
if result:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def sendSerial(byte):
|
||||
try:
|
||||
ser = serial.Serial(port=portName, baudrate=115200)
|
||||
ser.write(byte)
|
||||
except SerialException:
|
||||
print('port already open')
|
||||
|
||||
class PhoneLineEventHandler():
|
||||
phone_mgr = None
|
||||
lines = []
|
||||
line_selected = None
|
||||
connected = False
|
||||
|
||||
def OnDispOnLineMgrNotification(self, msg, param, returns=""):
|
||||
|
||||
global global_inactive, global_screen_locked
|
||||
if not self.phone_mgr:
|
||||
self.phone_mgr = win32com.client.Dispatch("CLMgr.ClientLineMgr")
|
||||
if not self.phone_mgr:
|
||||
"Swyx not connected!"
|
||||
else:
|
||||
print("Swyx connected!")
|
||||
if self.phone_mgr:
|
||||
if msg == CLMgrMessage.CLMgrLineStateChangedMessage:
|
||||
line = self.phone_mgr.DispGetLine(param)
|
||||
print("Line: {} {}".format(
|
||||
param,
|
||||
LineState.s[line.DispState])
|
||||
)
|
||||
if line.DispState != LineState.Inactive:
|
||||
if line.DispState == LineState.Ringing:
|
||||
sendSerial(b'shc000255000')
|
||||
else:
|
||||
sendSerial(b'shc255000000')
|
||||
|
||||
if not global_screen_locked:
|
||||
asyncio.run(try_pause())
|
||||
global_inactive = False
|
||||
for linenum in range(self.phone_mgr.DispNumberOfLines):
|
||||
line = self.phone_mgr.DispGetLine(linenum)
|
||||
if line.DispState != LineState.Inactive:
|
||||
return True
|
||||
|
||||
if not global_screen_locked:
|
||||
asyncio.run(try_play())
|
||||
global_inactive = True
|
||||
sendSerial(b'shc000000000')
|
||||
return True
|
||||
|
||||
# async def get_media_info():
|
||||
# sessions = await MediaManager.request_async()
|
||||
|
||||
# # This source_app_user_model_id check and if statement is optional
|
||||
# # Use it if you want to only get a certain player/program's media
|
||||
# # (e.g. only chrome.exe's media not any other program's).
|
||||
|
||||
# # To get the ID, use a breakpoint() to run sessions.get_current_session()
|
||||
# # while the media you want to get is playing.
|
||||
# # Then set TARGET_ID to the string this call returns.
|
||||
|
||||
# current_session = sessions.get_current_session()
|
||||
# if current_session: # there needs to be a media session running
|
||||
# #if current_session.source_app_user_model_id == TARGET_ID:
|
||||
# info = await current_session.try_get_media_properties_async()
|
||||
# # song_attr[0] != '_' ignores system attributes
|
||||
# info_dict = {song_attr: info.__getattribute__(song_attr) for song_attr in dir(info) if song_attr[0] != '_'}
|
||||
|
||||
# # converts winrt vector to list
|
||||
# info_dict['genres'] = list(info_dict['genres'])
|
||||
|
||||
# return info_dict
|
||||
|
||||
# # It could be possible to select a program from a list of current
|
||||
# # available ones. I just haven't implemented this here for my use case.
|
||||
# # See references for more information.
|
||||
# raise Exception('TARGET_PROGRAM is not the current media session')
|
||||
|
||||
async def try_play():
|
||||
print("try_play")
|
||||
if not DEBUG:
|
||||
sessions = await MediaManager.request_async()
|
||||
current_session = sessions.get_current_session()
|
||||
if current_session:
|
||||
await current_session.try_play_async()
|
||||
|
||||
async def try_pause():
|
||||
print("try_pause")
|
||||
if not DEBUG:
|
||||
sessions = await MediaManager.request_async()
|
||||
current_session = sessions.get_current_session()
|
||||
if current_session:
|
||||
await current_session.try_pause_async()
|
||||
|
||||
def OnSessionEvent(event: sel.SessionEvent):
|
||||
global global_inactive, global_screen_locked
|
||||
if event == sel.SessionEvent.SESSION_LOCK:
|
||||
global_screen_locked = True
|
||||
print("locked, try_pause")
|
||||
asyncio.run(try_pause())
|
||||
|
||||
if event == sel.SessionEvent.SESSION_UNLOCK:
|
||||
global_screen_locked = False
|
||||
if global_inactive:
|
||||
print("unlocked, global inactive, tryplay")
|
||||
asyncio.run(try_play())
|
||||
|
||||
if __name__ == '__main__':
|
||||
win32com.client.WithEvents("CLMgr.ClientLineMgr", PhoneLineEventHandler)
|
||||
m = sel.WorkstationMonitor()
|
||||
m.register_handler(sel.SessionEvent.ANY, handler=OnSessionEvent)
|
||||
try:
|
||||
while True:
|
||||
pythoncom.PumpWaitingMessages()
|
||||
m.listen()
|
||||
time.sleep(0.1) # Don't use up all our CPU checking constantly
|
||||
except KeyboardInterrupt:
|
||||
print("exit")
|
||||
if __name__ == "__main__":
|
||||
gui = Gui()
|
@ -21,24 +21,20 @@ pyz = PYZ(a.pure, a.zipped_data,
|
||||
cipher=block_cipher)
|
||||
|
||||
exe = EXE(pyz,
|
||||
a.scripts,
|
||||
a.scripts,
|
||||
a.binaries,
|
||||
a.zipfiles,
|
||||
a.datas,
|
||||
[],
|
||||
exclude_binaries=True,
|
||||
name='__main__',
|
||||
debug=False,
|
||||
bootloader_ignore_signals=False,
|
||||
strip=False,
|
||||
upx=True,
|
||||
upx_exclude=[],
|
||||
runtime_tmpdir=None,
|
||||
console=True,
|
||||
disable_windowed_traceback=False,
|
||||
target_arch=None,
|
||||
codesign_identity=None,
|
||||
entitlements_file=None )
|
||||
coll = COLLECT(exe,
|
||||
a.binaries,
|
||||
a.zipfiles,
|
||||
a.datas,
|
||||
strip=False,
|
||||
upx=True,
|
||||
upx_exclude=[],
|
||||
name='__main__')
|
||||
|
BIN
favicon.ico
Normal file
BIN
favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 66 KiB |
147
gui.py
Normal file
147
gui.py
Normal file
@ -0,0 +1,147 @@
|
||||
# Import the required libraries
|
||||
import logging
|
||||
from tkinter import *
|
||||
from pystray import MenuItem as item
|
||||
import pystray
|
||||
from PIL import Image, ImageTk
|
||||
import threading
|
||||
from functools import partial
|
||||
import time
|
||||
|
||||
from mediacontrol import MediaControl
|
||||
from ledcontroll import BLACK, LedControl, RED1, GREEN
|
||||
from swyxcontrol import SwyxControl, LineState
|
||||
from workstationcontrol import LockscreenMonitor, SessionEvent
|
||||
|
||||
class Gui():
|
||||
|
||||
win: Tk
|
||||
t_icon: threading.Thread
|
||||
|
||||
strvar_swyx_connected_status: StringVar
|
||||
strvar_screen_locked: StringVar
|
||||
strvar_line_inactive: StringVar
|
||||
strvar_play_state: StringVar
|
||||
|
||||
on_quit = None
|
||||
|
||||
def set_swyx_status(self, string):
|
||||
self.strvar_swyx_connected_status.set(string)
|
||||
|
||||
# Define a function for quit the window
|
||||
def quit_window(self, icon, item = None):
|
||||
self.sc.stop()
|
||||
self.wm.stop()
|
||||
self.mc.stop()
|
||||
icon.stop()
|
||||
self.win.deiconify()
|
||||
self.win.quit()
|
||||
|
||||
# Define a function to show the window again
|
||||
def show_window(self, icon, item):
|
||||
self.win.deiconify()
|
||||
|
||||
# Hide the window and show on the system taskbar
|
||||
def hide_window(self):
|
||||
self.win.withdraw()
|
||||
|
||||
def handle_lockscreen(self, event: SessionEvent):
|
||||
if event == SessionEvent.SESSION_LOCK:
|
||||
logging.debug("locked, pause")
|
||||
self.mc.pause()
|
||||
self.strvar_screen_locked.set("Locked")
|
||||
|
||||
if event == SessionEvent.SESSION_UNLOCK:
|
||||
if self.sc.all_lines_inactive:
|
||||
logging.debug("unlocked, global inactive, play")
|
||||
time.sleep(3)
|
||||
self.mc.play()
|
||||
self.strvar_screen_locked.set("Unlocked")
|
||||
|
||||
def handle_line_state_changed(self, line):
|
||||
if not line.DispState == LineState.Inactive:
|
||||
if line.DispState == LineState.Ringing:
|
||||
self.lc.show_all(GREEN)
|
||||
else:
|
||||
self.lc.show_all(RED1)
|
||||
self.mc.pause()
|
||||
self.strvar_play_state.set("try pause")
|
||||
self.strvar_line_inactive.set("False")
|
||||
if self.sc.all_lines_inactive:
|
||||
self.strvar_line_inactive.set("True")
|
||||
self.lc.show_all(BLACK)
|
||||
if not self.wm.screen_locked():
|
||||
self.mc.play()
|
||||
self.strvar_play_state.set("try play")
|
||||
|
||||
def handle_phone_mgr_connected(self):
|
||||
if self.sc.all_lines_inactive:
|
||||
self.strvar_line_inactive.set("True")
|
||||
self.lc.show_all(BLACK)
|
||||
return
|
||||
self.strvar_line_inactive.set("False")
|
||||
|
||||
def handle_media_control_init(self):
|
||||
playback_info = self.mc.get_playback_info()
|
||||
if playback_info is None:
|
||||
print(playback_info)
|
||||
self.strvar_play_state.set("no session active")
|
||||
|
||||
def __init__(self):
|
||||
|
||||
self.load_gui()
|
||||
|
||||
self.sc = SwyxControl()
|
||||
self.sc.name = "SwyxControl"
|
||||
self.sc.add_phone_mgr_connected_handler(self.handle_phone_mgr_connected)
|
||||
self.sc.add_line_state_changed_handler(self.handle_line_state_changed)
|
||||
self.sc.start()
|
||||
|
||||
self.lc = LedControl('COM3')
|
||||
|
||||
self.mc = MediaControl()
|
||||
self.mc.name = "MediaControl"
|
||||
self.mc.add_init_handler(self.handle_media_control_init)
|
||||
self.mc.start()
|
||||
|
||||
self.wm = LockscreenMonitor()
|
||||
self.wm.name = "LockscreenMonitor"
|
||||
self.wm.register_handler(self.handle_lockscreen)
|
||||
self.strvar_screen_locked.set("Locked" if self.wm.screen_locked() else "Unlocked")
|
||||
self.wm.start()
|
||||
|
||||
self.win.protocol('WM_DELETE_WINDOW', self.hide_window)
|
||||
image=Image.open("favicon.ico")
|
||||
menu=(item('Beenden', self.quit_window), item('Anzeigen', self.show_window))
|
||||
self.icon=pystray.Icon("name", image, "Swyx Media Controll", menu)
|
||||
self.t_icon = threading.Thread(target=self.icon.run)
|
||||
self.t_icon.name = "icon_thread"
|
||||
self.t_icon.start()
|
||||
self.win.mainloop()
|
||||
|
||||
|
||||
def load_gui(self):
|
||||
self.win=Tk()
|
||||
# Create an instance of tkinter frame or window
|
||||
self.win.title("Swyx Media Controll")
|
||||
# Set the size of the window
|
||||
self.win.geometry("350x150")
|
||||
self.win.resizable(False, False)
|
||||
|
||||
## Screen Lock
|
||||
Label(self.win, text="Screen Lock: ", font=("Helvetica", 10)).place(x=10, y=10)
|
||||
self.strvar_screen_locked = StringVar(self.win)
|
||||
Label(self.win, textvariable=self.strvar_screen_locked, font=("Helvetica", 10)).place(x=100, y=10)
|
||||
|
||||
## Line Inactive
|
||||
Label(self.win, text="Line Inactive: ", font=("Helvetica", 10)).place(x=10, y=30)
|
||||
self.strvar_line_inactive = StringVar(self.win)
|
||||
Label(self.win, textvariable=self.strvar_line_inactive, font=("Helvetica", 10)).place(x=100, y=30)
|
||||
|
||||
## Play State
|
||||
Label(self.win, text="Play State: ", font=("Helvetica", 10)).place(x=10, y=50)
|
||||
self.strvar_play_state = StringVar(self.win)
|
||||
Label(self.win, textvariable=self.strvar_play_state, font=("Helvetica", 10)).place(x=100, y=50)
|
||||
|
||||
if __name__ == "__main__":
|
||||
gui = Gui()
|
607
ledcontroll.py
Normal file
607
ledcontroll.py
Normal file
@ -0,0 +1,607 @@
|
||||
import serial
|
||||
|
||||
class LedControl():
|
||||
portName = ''
|
||||
|
||||
def __init__(self, portName: str) -> None:
|
||||
'''portname is the com port of the ledstrip'''
|
||||
self.portName = portName
|
||||
pass
|
||||
|
||||
def show_all(self, color:'RGB'):
|
||||
'''shows all leds in a specified color'''
|
||||
self.__sendSerial(b"shc"+color.hex_format())
|
||||
|
||||
def set_one(self, id, color: 'RGB'):
|
||||
'''sets a led to a specified color'''
|
||||
self.__sendSerial("dta{:03}".format(id).encode() + color.hex_format())
|
||||
|
||||
def show(self):
|
||||
'''shows the colors set by set_one'''
|
||||
self.__sendSerial(b'shw')
|
||||
|
||||
def __sendSerial(self, byte):
|
||||
try:
|
||||
ser = serial.Serial(port=self.portName, baudrate=115200)
|
||||
ser.write(byte)
|
||||
for line in ser.readline():
|
||||
pass
|
||||
except serial.SerialException:
|
||||
print('port already open')
|
||||
|
||||
"""Provide RGB color constants and a colors dictionary with
|
||||
elements formatted: colors[colorname] = CONSTANT"""
|
||||
from collections import namedtuple, OrderedDict
|
||||
Color = namedtuple('RGB','red, green, blue')
|
||||
colors = {} #dict of colors
|
||||
class RGB(Color):
|
||||
def hex_format(self) -> bytes:
|
||||
'''Returns color in hex format'''
|
||||
return '{:03}{:03}{:03}'.format(self.red,self.green,self.blue).encode()
|
||||
#Color Contants
|
||||
ALICEBLUE = RGB(240, 248, 255)
|
||||
ANTIQUEWHITE = RGB(250, 235, 215)
|
||||
ANTIQUEWHITE1 = RGB(255, 239, 219)
|
||||
ANTIQUEWHITE2 = RGB(238, 223, 204)
|
||||
ANTIQUEWHITE3 = RGB(205, 192, 176)
|
||||
ANTIQUEWHITE4 = RGB(139, 131, 120)
|
||||
AQUA = RGB(0, 255, 255)
|
||||
AQUAMARINE1 = RGB(127, 255, 212)
|
||||
AQUAMARINE2 = RGB(118, 238, 198)
|
||||
AQUAMARINE3 = RGB(102, 205, 170)
|
||||
AQUAMARINE4 = RGB(69, 139, 116)
|
||||
AZURE1 = RGB(240, 255, 255)
|
||||
AZURE2 = RGB(224, 238, 238)
|
||||
AZURE3 = RGB(193, 205, 205)
|
||||
AZURE4 = RGB(131, 139, 139)
|
||||
BANANA = RGB(227, 207, 87)
|
||||
BEIGE = RGB(245, 245, 220)
|
||||
BISQUE1 = RGB(255, 228, 196)
|
||||
BISQUE2 = RGB(238, 213, 183)
|
||||
BISQUE3 = RGB(205, 183, 158)
|
||||
BISQUE4 = RGB(139, 125, 107)
|
||||
BLACK = RGB(0, 0, 0)
|
||||
BLANCHEDALMOND = RGB(255, 235, 205)
|
||||
BLUE = RGB(0, 0, 255)
|
||||
BLUE2 = RGB(0, 0, 238)
|
||||
BLUE3 = RGB(0, 0, 205)
|
||||
BLUE4 = RGB(0, 0, 139)
|
||||
BLUEVIOLET = RGB(138, 43, 226)
|
||||
BRICK = RGB(156, 102, 31)
|
||||
BROWN = RGB(165, 42, 42)
|
||||
BROWN1 = RGB(255, 64, 64)
|
||||
BROWN2 = RGB(238, 59, 59)
|
||||
BROWN3 = RGB(205, 51, 51)
|
||||
BROWN4 = RGB(139, 35, 35)
|
||||
BURLYWOOD = RGB(222, 184, 135)
|
||||
BURLYWOOD1 = RGB(255, 211, 155)
|
||||
BURLYWOOD2 = RGB(238, 197, 145)
|
||||
BURLYWOOD3 = RGB(205, 170, 125)
|
||||
BURLYWOOD4 = RGB(139, 115, 85)
|
||||
BURNTSIENNA = RGB(138, 54, 15)
|
||||
BURNTUMBER = RGB(138, 51, 36)
|
||||
CADETBLUE = RGB(95, 158, 160)
|
||||
CADETBLUE1 = RGB(152, 245, 255)
|
||||
CADETBLUE2 = RGB(142, 229, 238)
|
||||
CADETBLUE3 = RGB(122, 197, 205)
|
||||
CADETBLUE4 = RGB(83, 134, 139)
|
||||
CADMIUMORANGE = RGB(255, 97, 3)
|
||||
CADMIUMYELLOW = RGB(255, 153, 18)
|
||||
CARROT = RGB(237, 145, 33)
|
||||
CHARTREUSE1 = RGB(127, 255, 0)
|
||||
CHARTREUSE2 = RGB(118, 238, 0)
|
||||
CHARTREUSE3 = RGB(102, 205, 0)
|
||||
CHARTREUSE4 = RGB(69, 139, 0)
|
||||
CHOCOLATE = RGB(210, 105, 30)
|
||||
CHOCOLATE1 = RGB(255, 127, 36)
|
||||
CHOCOLATE2 = RGB(238, 118, 33)
|
||||
CHOCOLATE3 = RGB(205, 102, 29)
|
||||
CHOCOLATE4 = RGB(139, 69, 19)
|
||||
COBALT = RGB(61, 89, 171)
|
||||
COBALTGREEN = RGB(61, 145, 64)
|
||||
COLDGREY = RGB(128, 138, 135)
|
||||
CORAL = RGB(255, 127, 80)
|
||||
CORAL1 = RGB(255, 114, 86)
|
||||
CORAL2 = RGB(238, 106, 80)
|
||||
CORAL3 = RGB(205, 91, 69)
|
||||
CORAL4 = RGB(139, 62, 47)
|
||||
CORNFLOWERBLUE = RGB(100, 149, 237)
|
||||
CORNSILK1 = RGB(255, 248, 220)
|
||||
CORNSILK2 = RGB(238, 232, 205)
|
||||
CORNSILK3 = RGB(205, 200, 177)
|
||||
CORNSILK4 = RGB(139, 136, 120)
|
||||
CRIMSON = RGB(220, 20, 60)
|
||||
CYAN2 = RGB(0, 238, 238)
|
||||
CYAN3 = RGB(0, 205, 205)
|
||||
CYAN4 = RGB(0, 139, 139)
|
||||
DARKGOLDENROD = RGB(184, 134, 11)
|
||||
DARKGOLDENROD1 = RGB(255, 185, 15)
|
||||
DARKGOLDENROD2 = RGB(238, 173, 14)
|
||||
DARKGOLDENROD3 = RGB(205, 149, 12)
|
||||
DARKGOLDENROD4 = RGB(139, 101, 8)
|
||||
DARKGRAY = RGB(169, 169, 169)
|
||||
DARKGREEN = RGB(0, 100, 0)
|
||||
DARKKHAKI = RGB(189, 183, 107)
|
||||
DARKOLIVEGREEN = RGB(85, 107, 47)
|
||||
DARKOLIVEGREEN1 = RGB(202, 255, 112)
|
||||
DARKOLIVEGREEN2 = RGB(188, 238, 104)
|
||||
DARKOLIVEGREEN3 = RGB(162, 205, 90)
|
||||
DARKOLIVEGREEN4 = RGB(110, 139, 61)
|
||||
DARKORANGE = RGB(255, 140, 0)
|
||||
DARKORANGE1 = RGB(255, 127, 0)
|
||||
DARKORANGE2 = RGB(238, 118, 0)
|
||||
DARKORANGE3 = RGB(205, 102, 0)
|
||||
DARKORANGE4 = RGB(139, 69, 0)
|
||||
DARKORCHID = RGB(153, 50, 204)
|
||||
DARKORCHID1 = RGB(191, 62, 255)
|
||||
DARKORCHID2 = RGB(178, 58, 238)
|
||||
DARKORCHID3 = RGB(154, 50, 205)
|
||||
DARKORCHID4 = RGB(104, 34, 139)
|
||||
DARKSALMON = RGB(233, 150, 122)
|
||||
DARKSEAGREEN = RGB(143, 188, 143)
|
||||
DARKSEAGREEN1 = RGB(193, 255, 193)
|
||||
DARKSEAGREEN2 = RGB(180, 238, 180)
|
||||
DARKSEAGREEN3 = RGB(155, 205, 155)
|
||||
DARKSEAGREEN4 = RGB(105, 139, 105)
|
||||
DARKSLATEBLUE = RGB(72, 61, 139)
|
||||
DARKSLATEGRAY = RGB(47, 79, 79)
|
||||
DARKSLATEGRAY1 = RGB(151, 255, 255)
|
||||
DARKSLATEGRAY2 = RGB(141, 238, 238)
|
||||
DARKSLATEGRAY3 = RGB(121, 205, 205)
|
||||
DARKSLATEGRAY4 = RGB(82, 139, 139)
|
||||
DARKTURQUOISE = RGB(0, 206, 209)
|
||||
DARKVIOLET = RGB(148, 0, 211)
|
||||
DEEPPINK1 = RGB(255, 20, 147)
|
||||
DEEPPINK2 = RGB(238, 18, 137)
|
||||
DEEPPINK3 = RGB(205, 16, 118)
|
||||
DEEPPINK4 = RGB(139, 10, 80)
|
||||
DEEPSKYBLUE1 = RGB(0, 191, 255)
|
||||
DEEPSKYBLUE2 = RGB(0, 178, 238)
|
||||
DEEPSKYBLUE3 = RGB(0, 154, 205)
|
||||
DEEPSKYBLUE4 = RGB(0, 104, 139)
|
||||
DIMGRAY = RGB(105, 105, 105)
|
||||
DIMGRAY = RGB(105, 105, 105)
|
||||
DODGERBLUE1 = RGB(30, 144, 255)
|
||||
DODGERBLUE2 = RGB(28, 134, 238)
|
||||
DODGERBLUE3 = RGB(24, 116, 205)
|
||||
DODGERBLUE4 = RGB(16, 78, 139)
|
||||
EGGSHELL = RGB(252, 230, 201)
|
||||
EMERALDGREEN = RGB(0, 201, 87)
|
||||
FIREBRICK = RGB(178, 34, 34)
|
||||
FIREBRICK1 = RGB(255, 48, 48)
|
||||
FIREBRICK2 = RGB(238, 44, 44)
|
||||
FIREBRICK3 = RGB(205, 38, 38)
|
||||
FIREBRICK4 = RGB(139, 26, 26)
|
||||
FLESH = RGB(255, 125, 64)
|
||||
FLORALWHITE = RGB(255, 250, 240)
|
||||
FORESTGREEN = RGB(34, 139, 34)
|
||||
GAINSBORO = RGB(220, 220, 220)
|
||||
GHOSTWHITE = RGB(248, 248, 255)
|
||||
GOLD1 = RGB(255, 215, 0)
|
||||
GOLD2 = RGB(238, 201, 0)
|
||||
GOLD3 = RGB(205, 173, 0)
|
||||
GOLD4 = RGB(139, 117, 0)
|
||||
GOLDENROD = RGB(218, 165, 32)
|
||||
GOLDENROD1 = RGB(255, 193, 37)
|
||||
GOLDENROD2 = RGB(238, 180, 34)
|
||||
GOLDENROD3 = RGB(205, 155, 29)
|
||||
GOLDENROD4 = RGB(139, 105, 20)
|
||||
GRAY = RGB(128, 128, 128)
|
||||
GRAY1 = RGB(3, 3, 3)
|
||||
GRAY10 = RGB(26, 26, 26)
|
||||
GRAY11 = RGB(28, 28, 28)
|
||||
GRAY12 = RGB(31, 31, 31)
|
||||
GRAY13 = RGB(33, 33, 33)
|
||||
GRAY14 = RGB(36, 36, 36)
|
||||
GRAY15 = RGB(38, 38, 38)
|
||||
GRAY16 = RGB(41, 41, 41)
|
||||
GRAY17 = RGB(43, 43, 43)
|
||||
GRAY18 = RGB(46, 46, 46)
|
||||
GRAY19 = RGB(48, 48, 48)
|
||||
GRAY2 = RGB(5, 5, 5)
|
||||
GRAY20 = RGB(51, 51, 51)
|
||||
GRAY21 = RGB(54, 54, 54)
|
||||
GRAY22 = RGB(56, 56, 56)
|
||||
GRAY23 = RGB(59, 59, 59)
|
||||
GRAY24 = RGB(61, 61, 61)
|
||||
GRAY25 = RGB(64, 64, 64)
|
||||
GRAY26 = RGB(66, 66, 66)
|
||||
GRAY27 = RGB(69, 69, 69)
|
||||
GRAY28 = RGB(71, 71, 71)
|
||||
GRAY29 = RGB(74, 74, 74)
|
||||
GRAY3 = RGB(8, 8, 8)
|
||||
GRAY30 = RGB(77, 77, 77)
|
||||
GRAY31 = RGB(79, 79, 79)
|
||||
GRAY32 = RGB(82, 82, 82)
|
||||
GRAY33 = RGB(84, 84, 84)
|
||||
GRAY34 = RGB(87, 87, 87)
|
||||
GRAY35 = RGB(89, 89, 89)
|
||||
GRAY36 = RGB(92, 92, 92)
|
||||
GRAY37 = RGB(94, 94, 94)
|
||||
GRAY38 = RGB(97, 97, 97)
|
||||
GRAY39 = RGB(99, 99, 99)
|
||||
GRAY4 = RGB(10, 10, 10)
|
||||
GRAY40 = RGB(102, 102, 102)
|
||||
GRAY42 = RGB(107, 107, 107)
|
||||
GRAY43 = RGB(110, 110, 110)
|
||||
GRAY44 = RGB(112, 112, 112)
|
||||
GRAY45 = RGB(115, 115, 115)
|
||||
GRAY46 = RGB(117, 117, 117)
|
||||
GRAY47 = RGB(120, 120, 120)
|
||||
GRAY48 = RGB(122, 122, 122)
|
||||
GRAY49 = RGB(125, 125, 125)
|
||||
GRAY5 = RGB(13, 13, 13)
|
||||
GRAY50 = RGB(127, 127, 127)
|
||||
GRAY51 = RGB(130, 130, 130)
|
||||
GRAY52 = RGB(133, 133, 133)
|
||||
GRAY53 = RGB(135, 135, 135)
|
||||
GRAY54 = RGB(138, 138, 138)
|
||||
GRAY55 = RGB(140, 140, 140)
|
||||
GRAY56 = RGB(143, 143, 143)
|
||||
GRAY57 = RGB(145, 145, 145)
|
||||
GRAY58 = RGB(148, 148, 148)
|
||||
GRAY59 = RGB(150, 150, 150)
|
||||
GRAY6 = RGB(15, 15, 15)
|
||||
GRAY60 = RGB(153, 153, 153)
|
||||
GRAY61 = RGB(156, 156, 156)
|
||||
GRAY62 = RGB(158, 158, 158)
|
||||
GRAY63 = RGB(161, 161, 161)
|
||||
GRAY64 = RGB(163, 163, 163)
|
||||
GRAY65 = RGB(166, 166, 166)
|
||||
GRAY66 = RGB(168, 168, 168)
|
||||
GRAY67 = RGB(171, 171, 171)
|
||||
GRAY68 = RGB(173, 173, 173)
|
||||
GRAY69 = RGB(176, 176, 176)
|
||||
GRAY7 = RGB(18, 18, 18)
|
||||
GRAY70 = RGB(179, 179, 179)
|
||||
GRAY71 = RGB(181, 181, 181)
|
||||
GRAY72 = RGB(184, 184, 184)
|
||||
GRAY73 = RGB(186, 186, 186)
|
||||
GRAY74 = RGB(189, 189, 189)
|
||||
GRAY75 = RGB(191, 191, 191)
|
||||
GRAY76 = RGB(194, 194, 194)
|
||||
GRAY77 = RGB(196, 196, 196)
|
||||
GRAY78 = RGB(199, 199, 199)
|
||||
GRAY79 = RGB(201, 201, 201)
|
||||
GRAY8 = RGB(20, 20, 20)
|
||||
GRAY80 = RGB(204, 204, 204)
|
||||
GRAY81 = RGB(207, 207, 207)
|
||||
GRAY82 = RGB(209, 209, 209)
|
||||
GRAY83 = RGB(212, 212, 212)
|
||||
GRAY84 = RGB(214, 214, 214)
|
||||
GRAY85 = RGB(217, 217, 217)
|
||||
GRAY86 = RGB(219, 219, 219)
|
||||
GRAY87 = RGB(222, 222, 222)
|
||||
GRAY88 = RGB(224, 224, 224)
|
||||
GRAY89 = RGB(227, 227, 227)
|
||||
GRAY9 = RGB(23, 23, 23)
|
||||
GRAY90 = RGB(229, 229, 229)
|
||||
GRAY91 = RGB(232, 232, 232)
|
||||
GRAY92 = RGB(235, 235, 235)
|
||||
GRAY93 = RGB(237, 237, 237)
|
||||
GRAY94 = RGB(240, 240, 240)
|
||||
GRAY95 = RGB(242, 242, 242)
|
||||
GRAY97 = RGB(247, 247, 247)
|
||||
GRAY98 = RGB(250, 250, 250)
|
||||
GRAY99 = RGB(252, 252, 252)
|
||||
GREEN = RGB(0, 128, 0)
|
||||
GREEN1 = RGB(0, 255, 0)
|
||||
GREEN2 = RGB(0, 238, 0)
|
||||
GREEN3 = RGB(0, 205, 0)
|
||||
GREEN4 = RGB(0, 139, 0)
|
||||
GREENYELLOW = RGB(173, 255, 47)
|
||||
HONEYDEW1 = RGB(240, 255, 240)
|
||||
HONEYDEW2 = RGB(224, 238, 224)
|
||||
HONEYDEW3 = RGB(193, 205, 193)
|
||||
HONEYDEW4 = RGB(131, 139, 131)
|
||||
HOTPINK = RGB(255, 105, 180)
|
||||
HOTPINK1 = RGB(255, 110, 180)
|
||||
HOTPINK2 = RGB(238, 106, 167)
|
||||
HOTPINK3 = RGB(205, 96, 144)
|
||||
HOTPINK4 = RGB(139, 58, 98)
|
||||
INDIANRED = RGB(176, 23, 31)
|
||||
INDIANRED = RGB(205, 92, 92)
|
||||
INDIANRED1 = RGB(255, 106, 106)
|
||||
INDIANRED2 = RGB(238, 99, 99)
|
||||
INDIANRED3 = RGB(205, 85, 85)
|
||||
INDIANRED4 = RGB(139, 58, 58)
|
||||
INDIGO = RGB(75, 0, 130)
|
||||
IVORY1 = RGB(255, 255, 240)
|
||||
IVORY2 = RGB(238, 238, 224)
|
||||
IVORY3 = RGB(205, 205, 193)
|
||||
IVORY4 = RGB(139, 139, 131)
|
||||
IVORYBLACK = RGB(41, 36, 33)
|
||||
KHAKI = RGB(240, 230, 140)
|
||||
KHAKI1 = RGB(255, 246, 143)
|
||||
KHAKI2 = RGB(238, 230, 133)
|
||||
KHAKI3 = RGB(205, 198, 115)
|
||||
KHAKI4 = RGB(139, 134, 78)
|
||||
LAVENDER = RGB(230, 230, 250)
|
||||
LAVENDERBLUSH1 = RGB(255, 240, 245)
|
||||
LAVENDERBLUSH2 = RGB(238, 224, 229)
|
||||
LAVENDERBLUSH3 = RGB(205, 193, 197)
|
||||
LAVENDERBLUSH4 = RGB(139, 131, 134)
|
||||
LAWNGREEN = RGB(124, 252, 0)
|
||||
LEMONCHIFFON1 = RGB(255, 250, 205)
|
||||
LEMONCHIFFON2 = RGB(238, 233, 191)
|
||||
LEMONCHIFFON3 = RGB(205, 201, 165)
|
||||
LEMONCHIFFON4 = RGB(139, 137, 112)
|
||||
LIGHTBLUE = RGB(173, 216, 230)
|
||||
LIGHTBLUE1 = RGB(191, 239, 255)
|
||||
LIGHTBLUE2 = RGB(178, 223, 238)
|
||||
LIGHTBLUE3 = RGB(154, 192, 205)
|
||||
LIGHTBLUE4 = RGB(104, 131, 139)
|
||||
LIGHTCORAL = RGB(240, 128, 128)
|
||||
LIGHTCYAN1 = RGB(224, 255, 255)
|
||||
LIGHTCYAN2 = RGB(209, 238, 238)
|
||||
LIGHTCYAN3 = RGB(180, 205, 205)
|
||||
LIGHTCYAN4 = RGB(122, 139, 139)
|
||||
LIGHTGOLDENROD1 = RGB(255, 236, 139)
|
||||
LIGHTGOLDENROD2 = RGB(238, 220, 130)
|
||||
LIGHTGOLDENROD3 = RGB(205, 190, 112)
|
||||
LIGHTGOLDENROD4 = RGB(139, 129, 76)
|
||||
LIGHTGOLDENRODYELLOW = RGB(250, 250, 210)
|
||||
LIGHTGREY = RGB(211, 211, 211)
|
||||
LIGHTPINK = RGB(255, 182, 193)
|
||||
LIGHTPINK1 = RGB(255, 174, 185)
|
||||
LIGHTPINK2 = RGB(238, 162, 173)
|
||||
LIGHTPINK3 = RGB(205, 140, 149)
|
||||
LIGHTPINK4 = RGB(139, 95, 101)
|
||||
LIGHTSALMON1 = RGB(255, 160, 122)
|
||||
LIGHTSALMON2 = RGB(238, 149, 114)
|
||||
LIGHTSALMON3 = RGB(205, 129, 98)
|
||||
LIGHTSALMON4 = RGB(139, 87, 66)
|
||||
LIGHTSEAGREEN = RGB(32, 178, 170)
|
||||
LIGHTSKYBLUE = RGB(135, 206, 250)
|
||||
LIGHTSKYBLUE1 = RGB(176, 226, 255)
|
||||
LIGHTSKYBLUE2 = RGB(164, 211, 238)
|
||||
LIGHTSKYBLUE3 = RGB(141, 182, 205)
|
||||
LIGHTSKYBLUE4 = RGB(96, 123, 139)
|
||||
LIGHTSLATEBLUE = RGB(132, 112, 255)
|
||||
LIGHTSLATEGRAY = RGB(119, 136, 153)
|
||||
LIGHTSTEELBLUE = RGB(176, 196, 222)
|
||||
LIGHTSTEELBLUE1 = RGB(202, 225, 255)
|
||||
LIGHTSTEELBLUE2 = RGB(188, 210, 238)
|
||||
LIGHTSTEELBLUE3 = RGB(162, 181, 205)
|
||||
LIGHTSTEELBLUE4 = RGB(110, 123, 139)
|
||||
LIGHTYELLOW1 = RGB(255, 255, 224)
|
||||
LIGHTYELLOW2 = RGB(238, 238, 209)
|
||||
LIGHTYELLOW3 = RGB(205, 205, 180)
|
||||
LIGHTYELLOW4 = RGB(139, 139, 122)
|
||||
LIMEGREEN = RGB(50, 205, 50)
|
||||
LINEN = RGB(250, 240, 230)
|
||||
MAGENTA = RGB(255, 0, 255)
|
||||
MAGENTA2 = RGB(238, 0, 238)
|
||||
MAGENTA3 = RGB(205, 0, 205)
|
||||
MAGENTA4 = RGB(139, 0, 139)
|
||||
MANGANESEBLUE = RGB(3, 168, 158)
|
||||
MAROON = RGB(128, 0, 0)
|
||||
MAROON1 = RGB(255, 52, 179)
|
||||
MAROON2 = RGB(238, 48, 167)
|
||||
MAROON3 = RGB(205, 41, 144)
|
||||
MAROON4 = RGB(139, 28, 98)
|
||||
MEDIUMORCHID = RGB(186, 85, 211)
|
||||
MEDIUMORCHID1 = RGB(224, 102, 255)
|
||||
MEDIUMORCHID2 = RGB(209, 95, 238)
|
||||
MEDIUMORCHID3 = RGB(180, 82, 205)
|
||||
MEDIUMORCHID4 = RGB(122, 55, 139)
|
||||
MEDIUMPURPLE = RGB(147, 112, 219)
|
||||
MEDIUMPURPLE1 = RGB(171, 130, 255)
|
||||
MEDIUMPURPLE2 = RGB(159, 121, 238)
|
||||
MEDIUMPURPLE3 = RGB(137, 104, 205)
|
||||
MEDIUMPURPLE4 = RGB(93, 71, 139)
|
||||
MEDIUMSEAGREEN = RGB(60, 179, 113)
|
||||
MEDIUMSLATEBLUE = RGB(123, 104, 238)
|
||||
MEDIUMSPRINGGREEN = RGB(0, 250, 154)
|
||||
MEDIUMTURQUOISE = RGB(72, 209, 204)
|
||||
MEDIUMVIOLETRED = RGB(199, 21, 133)
|
||||
MELON = RGB(227, 168, 105)
|
||||
MIDNIGHTBLUE = RGB(25, 25, 112)
|
||||
MINT = RGB(189, 252, 201)
|
||||
MINTCREAM = RGB(245, 255, 250)
|
||||
MISTYROSE1 = RGB(255, 228, 225)
|
||||
MISTYROSE2 = RGB(238, 213, 210)
|
||||
MISTYROSE3 = RGB(205, 183, 181)
|
||||
MISTYROSE4 = RGB(139, 125, 123)
|
||||
MOCCASIN = RGB(255, 228, 181)
|
||||
NAVAJOWHITE1 = RGB(255, 222, 173)
|
||||
NAVAJOWHITE2 = RGB(238, 207, 161)
|
||||
NAVAJOWHITE3 = RGB(205, 179, 139)
|
||||
NAVAJOWHITE4 = RGB(139, 121, 94)
|
||||
NAVY = RGB(0, 0, 128)
|
||||
OLDLACE = RGB(253, 245, 230)
|
||||
OLIVE = RGB(128, 128, 0)
|
||||
OLIVEDRAB = RGB(107, 142, 35)
|
||||
OLIVEDRAB1 = RGB(192, 255, 62)
|
||||
OLIVEDRAB2 = RGB(179, 238, 58)
|
||||
OLIVEDRAB3 = RGB(154, 205, 50)
|
||||
OLIVEDRAB4 = RGB(105, 139, 34)
|
||||
ORANGE = RGB(255, 128, 0)
|
||||
ORANGE1 = RGB(255, 165, 0)
|
||||
ORANGE2 = RGB(238, 154, 0)
|
||||
ORANGE3 = RGB(205, 133, 0)
|
||||
ORANGE4 = RGB(139, 90, 0)
|
||||
ORANGERED1 = RGB(255, 69, 0)
|
||||
ORANGERED2 = RGB(238, 64, 0)
|
||||
ORANGERED3 = RGB(205, 55, 0)
|
||||
ORANGERED4 = RGB(139, 37, 0)
|
||||
ORCHID = RGB(218, 112, 214)
|
||||
ORCHID1 = RGB(255, 131, 250)
|
||||
ORCHID2 = RGB(238, 122, 233)
|
||||
ORCHID3 = RGB(205, 105, 201)
|
||||
ORCHID4 = RGB(139, 71, 137)
|
||||
PALEGOLDENROD = RGB(238, 232, 170)
|
||||
PALEGREEN = RGB(152, 251, 152)
|
||||
PALEGREEN1 = RGB(154, 255, 154)
|
||||
PALEGREEN2 = RGB(144, 238, 144)
|
||||
PALEGREEN3 = RGB(124, 205, 124)
|
||||
PALEGREEN4 = RGB(84, 139, 84)
|
||||
PALETURQUOISE1 = RGB(187, 255, 255)
|
||||
PALETURQUOISE2 = RGB(174, 238, 238)
|
||||
PALETURQUOISE3 = RGB(150, 205, 205)
|
||||
PALETURQUOISE4 = RGB(102, 139, 139)
|
||||
PALEVIOLETRED = RGB(219, 112, 147)
|
||||
PALEVIOLETRED1 = RGB(255, 130, 171)
|
||||
PALEVIOLETRED2 = RGB(238, 121, 159)
|
||||
PALEVIOLETRED3 = RGB(205, 104, 137)
|
||||
PALEVIOLETRED4 = RGB(139, 71, 93)
|
||||
PAPAYAWHIP = RGB(255, 239, 213)
|
||||
PEACHPUFF1 = RGB(255, 218, 185)
|
||||
PEACHPUFF2 = RGB(238, 203, 173)
|
||||
PEACHPUFF3 = RGB(205, 175, 149)
|
||||
PEACHPUFF4 = RGB(139, 119, 101)
|
||||
PEACOCK = RGB(51, 161, 201)
|
||||
PINK = RGB(255, 192, 203)
|
||||
PINK1 = RGB(255, 181, 197)
|
||||
PINK2 = RGB(238, 169, 184)
|
||||
PINK3 = RGB(205, 145, 158)
|
||||
PINK4 = RGB(139, 99, 108)
|
||||
PLUM = RGB(221, 160, 221)
|
||||
PLUM1 = RGB(255, 187, 255)
|
||||
PLUM2 = RGB(238, 174, 238)
|
||||
PLUM3 = RGB(205, 150, 205)
|
||||
PLUM4 = RGB(139, 102, 139)
|
||||
POWDERBLUE = RGB(176, 224, 230)
|
||||
PURPLE = RGB(128, 0, 128)
|
||||
PURPLE1 = RGB(155, 48, 255)
|
||||
PURPLE2 = RGB(145, 44, 238)
|
||||
PURPLE3 = RGB(125, 38, 205)
|
||||
PURPLE4 = RGB(85, 26, 139)
|
||||
RASPBERRY = RGB(135, 38, 87)
|
||||
RAWSIENNA = RGB(199, 97, 20)
|
||||
RED1 = RGB(255, 0, 0)
|
||||
RED2 = RGB(238, 0, 0)
|
||||
RED3 = RGB(205, 0, 0)
|
||||
RED4 = RGB(139, 0, 0)
|
||||
ROSYBROWN = RGB(188, 143, 143)
|
||||
ROSYBROWN1 = RGB(255, 193, 193)
|
||||
ROSYBROWN2 = RGB(238, 180, 180)
|
||||
ROSYBROWN3 = RGB(205, 155, 155)
|
||||
ROSYBROWN4 = RGB(139, 105, 105)
|
||||
ROYALBLUE = RGB(65, 105, 225)
|
||||
ROYALBLUE1 = RGB(72, 118, 255)
|
||||
ROYALBLUE2 = RGB(67, 110, 238)
|
||||
ROYALBLUE3 = RGB(58, 95, 205)
|
||||
ROYALBLUE4 = RGB(39, 64, 139)
|
||||
SALMON = RGB(250, 128, 114)
|
||||
SALMON1 = RGB(255, 140, 105)
|
||||
SALMON2 = RGB(238, 130, 98)
|
||||
SALMON3 = RGB(205, 112, 84)
|
||||
SALMON4 = RGB(139, 76, 57)
|
||||
SANDYBROWN = RGB(244, 164, 96)
|
||||
SAPGREEN = RGB(48, 128, 20)
|
||||
SEAGREEN1 = RGB(84, 255, 159)
|
||||
SEAGREEN2 = RGB(78, 238, 148)
|
||||
SEAGREEN3 = RGB(67, 205, 128)
|
||||
SEAGREEN4 = RGB(46, 139, 87)
|
||||
SEASHELL1 = RGB(255, 245, 238)
|
||||
SEASHELL2 = RGB(238, 229, 222)
|
||||
SEASHELL3 = RGB(205, 197, 191)
|
||||
SEASHELL4 = RGB(139, 134, 130)
|
||||
SEPIA = RGB(94, 38, 18)
|
||||
SGIBEET = RGB(142, 56, 142)
|
||||
SGIBRIGHTGRAY = RGB(197, 193, 170)
|
||||
SGICHARTREUSE = RGB(113, 198, 113)
|
||||
SGIDARKGRAY = RGB(85, 85, 85)
|
||||
SGIGRAY12 = RGB(30, 30, 30)
|
||||
SGIGRAY16 = RGB(40, 40, 40)
|
||||
SGIGRAY32 = RGB(81, 81, 81)
|
||||
SGIGRAY36 = RGB(91, 91, 91)
|
||||
SGIGRAY52 = RGB(132, 132, 132)
|
||||
SGIGRAY56 = RGB(142, 142, 142)
|
||||
SGIGRAY72 = RGB(183, 183, 183)
|
||||
SGIGRAY76 = RGB(193, 193, 193)
|
||||
SGIGRAY92 = RGB(234, 234, 234)
|
||||
SGIGRAY96 = RGB(244, 244, 244)
|
||||
SGILIGHTBLUE = RGB(125, 158, 192)
|
||||
SGILIGHTGRAY = RGB(170, 170, 170)
|
||||
SGIOLIVEDRAB = RGB(142, 142, 56)
|
||||
SGISALMON = RGB(198, 113, 113)
|
||||
SGISLATEBLUE = RGB(113, 113, 198)
|
||||
SGITEAL = RGB(56, 142, 142)
|
||||
SIENNA = RGB(160, 82, 45)
|
||||
SIENNA1 = RGB(255, 130, 71)
|
||||
SIENNA2 = RGB(238, 121, 66)
|
||||
SIENNA3 = RGB(205, 104, 57)
|
||||
SIENNA4 = RGB(139, 71, 38)
|
||||
SILVER = RGB(192, 192, 192)
|
||||
SKYBLUE = RGB(135, 206, 235)
|
||||
SKYBLUE1 = RGB(135, 206, 255)
|
||||
SKYBLUE2 = RGB(126, 192, 238)
|
||||
SKYBLUE3 = RGB(108, 166, 205)
|
||||
SKYBLUE4 = RGB(74, 112, 139)
|
||||
SLATEBLUE = RGB(106, 90, 205)
|
||||
SLATEBLUE1 = RGB(131, 111, 255)
|
||||
SLATEBLUE2 = RGB(122, 103, 238)
|
||||
SLATEBLUE3 = RGB(105, 89, 205)
|
||||
SLATEBLUE4 = RGB(71, 60, 139)
|
||||
SLATEGRAY = RGB(112, 128, 144)
|
||||
SLATEGRAY1 = RGB(198, 226, 255)
|
||||
SLATEGRAY2 = RGB(185, 211, 238)
|
||||
SLATEGRAY3 = RGB(159, 182, 205)
|
||||
SLATEGRAY4 = RGB(108, 123, 139)
|
||||
SNOW1 = RGB(255, 250, 250)
|
||||
SNOW2 = RGB(238, 233, 233)
|
||||
SNOW3 = RGB(205, 201, 201)
|
||||
SNOW4 = RGB(139, 137, 137)
|
||||
SPRINGGREEN = RGB(0, 255, 127)
|
||||
SPRINGGREEN1 = RGB(0, 238, 118)
|
||||
SPRINGGREEN2 = RGB(0, 205, 102)
|
||||
SPRINGGREEN3 = RGB(0, 139, 69)
|
||||
STEELBLUE = RGB(70, 130, 180)
|
||||
STEELBLUE1 = RGB(99, 184, 255)
|
||||
STEELBLUE2 = RGB(92, 172, 238)
|
||||
STEELBLUE3 = RGB(79, 148, 205)
|
||||
STEELBLUE4 = RGB(54, 100, 139)
|
||||
TAN = RGB(210, 180, 140)
|
||||
TAN1 = RGB(255, 165, 79)
|
||||
TAN2 = RGB(238, 154, 73)
|
||||
TAN3 = RGB(205, 133, 63)
|
||||
TAN4 = RGB(139, 90, 43)
|
||||
TEAL = RGB(0, 128, 128)
|
||||
THISTLE = RGB(216, 191, 216)
|
||||
THISTLE1 = RGB(255, 225, 255)
|
||||
THISTLE2 = RGB(238, 210, 238)
|
||||
THISTLE3 = RGB(205, 181, 205)
|
||||
THISTLE4 = RGB(139, 123, 139)
|
||||
TOMATO1 = RGB(255, 99, 71)
|
||||
TOMATO2 = RGB(238, 92, 66)
|
||||
TOMATO3 = RGB(205, 79, 57)
|
||||
TOMATO4 = RGB(139, 54, 38)
|
||||
TURQUOISE = RGB(64, 224, 208)
|
||||
TURQUOISE1 = RGB(0, 245, 255)
|
||||
TURQUOISE2 = RGB(0, 229, 238)
|
||||
TURQUOISE3 = RGB(0, 197, 205)
|
||||
TURQUOISE4 = RGB(0, 134, 139)
|
||||
TURQUOISEBLUE = RGB(0, 199, 140)
|
||||
VIOLET = RGB(238, 130, 238)
|
||||
VIOLETRED = RGB(208, 32, 144)
|
||||
VIOLETRED1 = RGB(255, 62, 150)
|
||||
VIOLETRED2 = RGB(238, 58, 140)
|
||||
VIOLETRED3 = RGB(205, 50, 120)
|
||||
VIOLETRED4 = RGB(139, 34, 82)
|
||||
WARMGREY = RGB(128, 128, 105)
|
||||
WHEAT = RGB(245, 222, 179)
|
||||
WHEAT1 = RGB(255, 231, 186)
|
||||
WHEAT2 = RGB(238, 216, 174)
|
||||
WHEAT3 = RGB(205, 186, 150)
|
||||
WHEAT4 = RGB(139, 126, 102)
|
||||
WHITE = RGB(255, 255, 255)
|
||||
WHITESMOKE = RGB(245, 245, 245)
|
||||
WHITESMOKE = RGB(245, 245, 245)
|
||||
YELLOW1 = RGB(255, 255, 0)
|
||||
YELLOW2 = RGB(238, 238, 0)
|
||||
YELLOW3 = RGB(205, 205, 0)
|
||||
YELLOW4 = RGB(139, 139, 0)
|
||||
|
||||
if __name__ == "__main__":
|
||||
import time
|
||||
ledcount = 9
|
||||
lc = LedControl('COM3')
|
||||
while(True):
|
||||
for led in range(ledcount):
|
||||
lc.set_one(led, BLUEVIOLET)
|
||||
lc.show()
|
||||
time.sleep(0.1)
|
||||
lc.show_all(BLACK)
|
||||
time.sleep(0.1)
|
119
mediacontrol.py
Normal file
119
mediacontrol.py
Normal file
@ -0,0 +1,119 @@
|
||||
import asyncio
|
||||
from threading import Thread
|
||||
import logging
|
||||
import time
|
||||
|
||||
|
||||
class SessionPlaybackStatus:
|
||||
|
||||
Changing: 2 # Das Medium ändert sich.
|
||||
Closed: 0 # Das Medium ist geschlossen.
|
||||
Opened: 1 # Das Medium wird geöffnet.
|
||||
Paused: 5 # Das Medium wird angehalten.
|
||||
Playing: 4 # Die Medien werden abspielt.
|
||||
Stopped: 3 # Das Medium wird beendet.
|
||||
|
||||
|
||||
|
||||
class MediaControl(Thread):
|
||||
|
||||
__init_handler = []
|
||||
__session_changed_handler = []
|
||||
__running = True
|
||||
|
||||
|
||||
def run(self) -> None:
|
||||
from winrt.windows.media.control import GlobalSystemMediaTransportControlsSessionManager as MediaManager, CurrentSessionChangedEventArgs
|
||||
|
||||
self.MediaManager = MediaManager
|
||||
# MediaManager.add_current_session_changed(Event)
|
||||
for handler in self.__init_handler:
|
||||
handler()
|
||||
while self.__running:
|
||||
time.sleep(1)
|
||||
return super().run()
|
||||
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
|
||||
def __current_session_changed(self, **kwargs):
|
||||
print(kwargs)
|
||||
for handler in self.__session_changed_handler:
|
||||
handler()
|
||||
|
||||
def add_init_handler(self, handler):
|
||||
self.__init_handler.append(handler)
|
||||
|
||||
# def add_session_changed_handler(self, handler):
|
||||
# self.__session_changed_handler.append(handler)
|
||||
|
||||
def play(self):
|
||||
asyncio.run(self.__try_play())
|
||||
|
||||
def pause(self):
|
||||
asyncio.run(self.__try_pause())
|
||||
|
||||
def get_media_info(self):
|
||||
return asyncio.run(self.__get_media_info())
|
||||
|
||||
def get_playback_info(self):
|
||||
return asyncio.run(self.__get_playback_info())
|
||||
|
||||
def stop(self):
|
||||
self.__running = False
|
||||
|
||||
async def __try_play(self):
|
||||
logging.debug("__try_play")
|
||||
sessions = await self.MediaManager.request_async()
|
||||
current_session = sessions.get_current_session()
|
||||
if current_session:
|
||||
print("try_play!!!!!!!")
|
||||
await current_session.try_play_async()
|
||||
|
||||
async def __try_pause(self):
|
||||
logging.debug("__try_pause")
|
||||
sessions = await self.MediaManager.request_async()
|
||||
current_session = sessions.get_current_session()
|
||||
if current_session:
|
||||
await current_session.try_pause_async()
|
||||
|
||||
async def __get_media_info(self):
|
||||
sessions = await self.MediaManager.request_async()
|
||||
|
||||
current_session = sessions.get_current_session()
|
||||
if current_session: # there needs to be a media session running
|
||||
info = await current_session.try_get_media_properties_async()
|
||||
|
||||
# song_attr[0] != '_' ignores system attributes
|
||||
info_dict = {song_attr: info.__getattribute__(song_attr) for song_attr in dir(info) if song_attr[0] != '_'}
|
||||
|
||||
# converts winrt vector to list
|
||||
info_dict['genres'] = list(info_dict['genres'])
|
||||
|
||||
return info_dict
|
||||
|
||||
async def __get_playback_info(self):
|
||||
sessions = await self.MediaManager.request_async()
|
||||
|
||||
current_session = sessions.get_current_session()
|
||||
if current_session: # there needs to be a media session running
|
||||
info = current_session.get_playback_info()
|
||||
|
||||
# song_attr[0] != '_' ignores system attributes
|
||||
info_dict = {playback_attr: info.__getattribute__(playback_attr) for playback_attr in dir(info) if playback_attr[0] != '_'}
|
||||
|
||||
# converts winrt vector to list
|
||||
info_dict['controls'] = {control_attr: info.controls.__getattribute__(control_attr) for control_attr in dir(info.controls) if control_attr[0] != '_'}
|
||||
|
||||
return info_dict
|
||||
|
||||
if __name__ == "__main__":
|
||||
def handle_init():
|
||||
print(mc.get_media_info())
|
||||
print(mc.get_playback_info())
|
||||
pass
|
||||
|
||||
logging.getLogger().setLevel(logging.DEBUG)
|
||||
mc = MediaControl()
|
||||
mc.start()
|
||||
mc.add_init_handler(handle_init)
|
@ -1,3 +1,4 @@
|
||||
winrt
|
||||
pywin32
|
||||
python3-tk
|
||||
python3-tk
|
||||
pystray
|
100
resources.py
100
resources.py
@ -1,100 +0,0 @@
|
||||
|
||||
class CLMgrMessage():
|
||||
CLMgrLineStateChangedMessage = 0 # state of at least one line has changed
|
||||
CLMgrLineSelectionChangedMessage = 1 # line in focus has changed
|
||||
CLMgrLineDetailsChangedMessage = 2 # details of at least one line have changed
|
||||
CLMgrCallDetailsMessage = 4 # details of last call are available, post mortem for logging purpose
|
||||
CLMgrServerDownMessage = 5 # server goes down, keep line manager, wait for ServerUp message
|
||||
CLMgrServerUpMessage = 6 # server is up again, keep interfaces to line manger
|
||||
CLMgrWaveDeviceChanged = 7 # speaker / micro has been switched on / off
|
||||
CLMgrGroupCallNotificationMessage = 8 # notification about group call
|
||||
CLMgrNumberOfLinesChangedMessage = 10 # the number of lines has changed
|
||||
CLMgrClientShutDownRequest = 11 # Client Line Manager requests client to shutdown and release all interfaces
|
||||
CLMgrLineStateChangedMessageEx = 28 # state of certain line has changed, lParam: LOWORD: line index of line that changed its state (starting with 0) HIWORD: new state of this line
|
||||
|
||||
s = [
|
||||
"CLMgrLineStateChangedMessage",
|
||||
"CLMgrLineSelectionChangedMessage",
|
||||
"CLMgrLineDetailsChangedMessage",
|
||||
"3",
|
||||
"CLMgrCallDetailsMessage",
|
||||
"CLMgrServerDownMessage",
|
||||
"CLMgrServerUpMessage",
|
||||
"CLMgrWaveDeviceChanged",
|
||||
"CLMgrGroupCallNotificationMessage",
|
||||
"9",
|
||||
"CLMgrNumberOfLinesChangedMessage",
|
||||
"CLMgrClientShutDownRequest",
|
||||
"12",
|
||||
"13",
|
||||
"14",
|
||||
"15",
|
||||
"16",
|
||||
"17",
|
||||
"18",
|
||||
"19",
|
||||
"20",
|
||||
"21",
|
||||
"22",
|
||||
"23",
|
||||
"24",
|
||||
"25",
|
||||
"26",
|
||||
"27",
|
||||
"CLMgrLineStateChangedMessageEx"
|
||||
]
|
||||
|
||||
class LineState():
|
||||
Inactive = 0 # line is inactive
|
||||
HookOffInternal = 1 # off hook, internal dialtone
|
||||
HookOffExternal = 2 # off hook, external dialtone
|
||||
Ringing = 3 # incoming call, ringing
|
||||
Dialing = 4 # outgoing call, we are dialing, no sound
|
||||
Alerting = 5 # outgoing call, alerting = ringing on destination
|
||||
Knocking = 6 # outgoing call, knocking = second call ringing on destination
|
||||
Busy = 7 # outgoing call, destination is busy
|
||||
Active = 8 # incoming / outgoing call, logical and physical connection is established
|
||||
OnHold = 9 # incoming / outgoing call, logical connection is established, destination gets music on hold
|
||||
ConferenceActive = 10 # incoming / outgoing conference, logical and physical connection is established
|
||||
ConferenceOnHold = 11 # incoming / outgoing conference, logical connection is established, not physcically connected
|
||||
Terminated = 12 # incoming / outgoing connection / call has been disconnected
|
||||
Transferring = 13 # special LSOnHold, call is awaiting to be transferred, peer gets special music on hold
|
||||
Disabled = 14 # special LSInactive: wrap up time
|
||||
|
||||
s = [
|
||||
"Inactive",
|
||||
"HookOffInternal",
|
||||
"HookOffExternal",
|
||||
"Ringing",
|
||||
"Dialing",
|
||||
"Alerting",
|
||||
"Knocking",
|
||||
"Busy",
|
||||
"Active",
|
||||
"OnHold",
|
||||
"ConferenceActive",
|
||||
"ConferenceOnHold",
|
||||
"Terminated",
|
||||
"Transferring",
|
||||
"Disabled"
|
||||
]
|
||||
|
||||
class DisconnectReason():
|
||||
Normal = 0
|
||||
Busy = 1
|
||||
Rejected = 2
|
||||
Cancelled = 3
|
||||
Transferred = 4
|
||||
JoinedConference = 5
|
||||
NoAnswer = 6
|
||||
TooLate = 7
|
||||
DirectCallImpossible = 8
|
||||
WrongNumber = 9
|
||||
Unreachable = 10
|
||||
CallDiverted = 11
|
||||
CallRoutingFailed = 12
|
||||
PermissionDenied = 13
|
||||
NetworkCongestion = 14
|
||||
NoChannelAvailable = 15
|
||||
NumberChanged = 16
|
||||
IncompatibleDestination = 17
|
44
swyx-media-control.spec
Normal file
44
swyx-media-control.spec
Normal file
@ -0,0 +1,44 @@
|
||||
# -*- mode: python ; coding: utf-8 -*-
|
||||
|
||||
|
||||
block_cipher = None
|
||||
|
||||
|
||||
a = Analysis(['gui.py'],
|
||||
pathex=['X:\\Documents\\Projekte\\Simon\\python media controll'],
|
||||
binaries=[],
|
||||
datas=[('favicon.ico', '.')],
|
||||
hiddenimports=[],
|
||||
hookspath=[],
|
||||
hooksconfig={},
|
||||
runtime_hooks=[],
|
||||
excludes=[],
|
||||
win_no_prefer_redirects=False,
|
||||
win_private_assemblies=False,
|
||||
cipher=block_cipher,
|
||||
noarchive=False)
|
||||
pyz = PYZ(a.pure, a.zipped_data,
|
||||
cipher=block_cipher)
|
||||
|
||||
exe = EXE(pyz,
|
||||
a.scripts,
|
||||
[],
|
||||
exclude_binaries=True,
|
||||
name='swyx-media-control',
|
||||
debug=False,
|
||||
bootloader_ignore_signals=False,
|
||||
strip=False,
|
||||
upx=True,
|
||||
console=False,
|
||||
disable_windowed_traceback=False,
|
||||
target_arch=None,
|
||||
codesign_identity=None,
|
||||
entitlements_file=None , icon='favicon.ico')
|
||||
coll = COLLECT(exe,
|
||||
a.binaries,
|
||||
a.zipfiles,
|
||||
a.datas,
|
||||
strip=False,
|
||||
upx=True,
|
||||
upx_exclude=[],
|
||||
name='swyx-media-control')
|
221
swyxcontrol.py
Normal file
221
swyxcontrol.py
Normal file
@ -0,0 +1,221 @@
|
||||
import asyncio
|
||||
from threading import Thread
|
||||
import logging
|
||||
import time
|
||||
import logging
|
||||
import pythoncom
|
||||
|
||||
class CLMgrMessage():
|
||||
CLMgrLineStateChangedMessage = 0 # state of at least one line has changed
|
||||
CLMgrLineSelectionChangedMessage = 1 # line in focus has changed
|
||||
CLMgrLineDetailsChangedMessage = 2 # details of at least one line have changed
|
||||
CLMgrCallDetailsMessage = 4 # details of last call are available, post mortem for logging purpose
|
||||
CLMgrServerDownMessage = 5 # server goes down, keep line manager, wait for ServerUp message
|
||||
CLMgrServerUpMessage = 6 # server is up again, keep interfaces to line manger
|
||||
CLMgrWaveDeviceChanged = 7 # speaker / micro has been switched on / off
|
||||
CLMgrGroupCallNotificationMessage = 8 # notification about group call
|
||||
CLMgrNumberOfLinesChangedMessage = 10 # the number of lines has changed
|
||||
CLMgrClientShutDownRequest = 11 # Client Line Manager requests client to shutdown and release all interfaces
|
||||
CLMgrLineStateChangedMessageEx = 28 # state of certain line has changed, lParam: LOWORD: line index of line that changed its state (starting with 0) HIWORD: new state of this line
|
||||
|
||||
s = [
|
||||
"CLMgrLineStateChangedMessage",
|
||||
"CLMgrLineSelectionChangedMessage",
|
||||
"CLMgrLineDetailsChangedMessage",
|
||||
"3",
|
||||
"CLMgrCallDetailsMessage",
|
||||
"CLMgrServerDownMessage",
|
||||
"CLMgrServerUpMessage",
|
||||
"CLMgrWaveDeviceChanged",
|
||||
"CLMgrGroupCallNotificationMessage",
|
||||
"9",
|
||||
"CLMgrNumberOfLinesChangedMessage",
|
||||
"CLMgrClientShutDownRequest",
|
||||
"12",
|
||||
"13",
|
||||
"14",
|
||||
"15",
|
||||
"16",
|
||||
"17",
|
||||
"18",
|
||||
"19",
|
||||
"20",
|
||||
"21",
|
||||
"22",
|
||||
"23",
|
||||
"24",
|
||||
"25",
|
||||
"26",
|
||||
"27",
|
||||
"CLMgrLineStateChangedMessageEx"
|
||||
]
|
||||
|
||||
class LineState():
|
||||
Inactive = 0 # line is inactive
|
||||
HookOffInternal = 1 # off hook, internal dialtone
|
||||
HookOffExternal = 2 # off hook, external dialtone
|
||||
Ringing = 3 # incoming call, ringing
|
||||
Dialing = 4 # outgoing call, we are dialing, no sound
|
||||
Alerting = 5 # outgoing call, alerting = ringing on destination
|
||||
Knocking = 6 # outgoing call, knocking = second call ringing on destination
|
||||
Busy = 7 # outgoing call, destination is busy
|
||||
Active = 8 # incoming / outgoing call, logical and physical connection is established
|
||||
OnHold = 9 # incoming / outgoing call, logical connection is established, destination gets music on hold
|
||||
ConferenceActive = 10 # incoming / outgoing conference, logical and physical connection is established
|
||||
ConferenceOnHold = 11 # incoming / outgoing conference, logical connection is established, not physcically connected
|
||||
Terminated = 12 # incoming / outgoing connection / call has been disconnected
|
||||
Transferring = 13 # special LSOnHold, call is awaiting to be transferred, peer gets special music on hold
|
||||
Disabled = 14 # special LSInactive: wrap up time
|
||||
|
||||
s = [
|
||||
"Inactive",
|
||||
"HookOffInternal",
|
||||
"HookOffExternal",
|
||||
"Ringing",
|
||||
"Dialing",
|
||||
"Alerting",
|
||||
"Knocking",
|
||||
"Busy",
|
||||
"Active",
|
||||
"OnHold",
|
||||
"ConferenceActive",
|
||||
"ConferenceOnHold",
|
||||
"Terminated",
|
||||
"Transferring",
|
||||
"Disabled"
|
||||
]
|
||||
|
||||
class DisconnectReason():
|
||||
Normal = 0
|
||||
Busy = 1
|
||||
Rejected = 2
|
||||
Cancelled = 3
|
||||
Transferred = 4
|
||||
JoinedConference = 5
|
||||
NoAnswer = 6
|
||||
TooLate = 7
|
||||
DirectCallImpossible = 8
|
||||
WrongNumber = 9
|
||||
Unreachable = 10
|
||||
CallDiverted = 11
|
||||
CallRoutingFailed = 12
|
||||
PermissionDenied = 13
|
||||
NetworkCongestion = 14
|
||||
NoChannelAvailable = 15
|
||||
NumberChanged = 16
|
||||
IncompatibleDestination = 17
|
||||
|
||||
class SwyxControlException(Exception):
|
||||
|
||||
def __init__(self, msg, *args: object) -> None:
|
||||
self.msg = msg
|
||||
super().__init__(*args)
|
||||
|
||||
class SwyxControl(Thread):
|
||||
|
||||
__running = True
|
||||
phone_mgr = None
|
||||
__line_state_changed_hander = []
|
||||
__phone_mgr_connected_hander = []
|
||||
all_lines_inactive = False
|
||||
|
||||
class __PhoneLineEventHandler():
|
||||
outer: 'SwyxControl' = None
|
||||
|
||||
def OnDispOnLineMgrNotification(self, msg, param, returns=""):
|
||||
if not self.outer:
|
||||
logging.debug("self.outer not set")
|
||||
return True
|
||||
logging.debug("msg: {}\tparam: {}\treturns: {}".format(msg, param,returns))
|
||||
if msg == CLMgrMessage.CLMgrLineStateChangedMessage:
|
||||
self.outer._handle_line_state_changed(msg, param)
|
||||
return True
|
||||
|
||||
def setOuter(self, outer: 'SwyxControl'):
|
||||
logging.debug("set outer class")
|
||||
self.outer = outer
|
||||
|
||||
def _handle_line_state_changed(self, msg, param):
|
||||
line = self.phone_mgr.DispGetLine(param)
|
||||
logging.debug("Line: {} {} / {}".format(
|
||||
param,
|
||||
LineState.s[line.DispState],
|
||||
LineState.s[msg]
|
||||
)
|
||||
)
|
||||
self.all_lines_inactive = self.__all_lines_inactive()
|
||||
for handler in self.__line_state_changed_hander:
|
||||
handler(line)
|
||||
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
pass
|
||||
|
||||
def __all_lines_inactive(self) -> bool:
|
||||
'''returns true if all lines are inactive'''
|
||||
for linenum in range(self.phone_mgr.DispNumberOfLines):
|
||||
line = self.phone_mgr.DispGetLine(linenum)
|
||||
if line.DispState != LineState.Inactive:
|
||||
return False
|
||||
return True
|
||||
|
||||
def add_line_state_changed_handler(self, handler):
|
||||
'''handler called when CLMgrMessage.CLMgrLineStateChangedMessage
|
||||
is fired
|
||||
|
||||
def handler(line):
|
||||
if line.DispState == LineState.Ringing:
|
||||
print("Ringing")
|
||||
if line.DispState == LineState.HookOffInternal:
|
||||
print("HookOffInternal")
|
||||
sc.add_line_state_changed_handler(handler)
|
||||
'''
|
||||
self.__line_state_changed_hander.append(handler)
|
||||
|
||||
def add_phone_mgr_connected_handler(self, handler):
|
||||
'''
|
||||
handler called when CLMgr.ClientLineMgr dispatched
|
||||
|
||||
def handler():
|
||||
print("connected")
|
||||
sc.add_phone_mgr_connected_handler(handler)
|
||||
'''
|
||||
self.__phone_mgr_connected_hander.append(handler)
|
||||
|
||||
def stop(self):
|
||||
'''stops the running thread'''
|
||||
self.__running = False
|
||||
|
||||
def run(self):
|
||||
# Initialize
|
||||
import win32com.client
|
||||
#pythoncom.CoInitialize(pythoncom.COINIT_MULTITHREADED)
|
||||
#try:
|
||||
self.phone_mgr = win32com.client.Dispatch("CLMgr.ClientLineMgr")
|
||||
self.all_lines_inactive = self.__all_lines_inactive()
|
||||
for handler in self.__phone_mgr_connected_hander:
|
||||
handler()
|
||||
# except Exception:
|
||||
# raise SwyxControlException("Swyx Client not installed")
|
||||
self.e = win32com.client.WithEvents("CLMgr.ClientLineMgr", self.__PhoneLineEventHandler)
|
||||
self.e.setOuter(self)
|
||||
while self.__running:
|
||||
pythoncom.PumpWaitingMessages()
|
||||
time.sleep(0.1)
|
||||
|
||||
if __name__ == "__main__":
|
||||
logging.getLogger().setLevel(logging.DEBUG)
|
||||
def line_change_handler(line):
|
||||
if line.DispState == LineState.Ringing:
|
||||
print("Ringing")
|
||||
if line.DispState == LineState.HookOffInternal:
|
||||
print("HookOffInternal")
|
||||
|
||||
def phone_mgr_connected_handler():
|
||||
print(sc.all_lines_inactive)
|
||||
|
||||
sc = SwyxControl()
|
||||
sc.add_line_state_changed_handler(line_change_handler)
|
||||
sc.add_phone_mgr_connected_handler(phone_mgr_connected_handler)
|
||||
sc.start()
|
||||
pass
|
@ -1,9 +1,12 @@
|
||||
from collections import defaultdict
|
||||
from enum import Enum
|
||||
from threading import Thread
|
||||
import win32api
|
||||
import win32con
|
||||
import win32gui
|
||||
import win32ts
|
||||
import time
|
||||
import ctypes
|
||||
|
||||
|
||||
class SessionEvent(Enum):
|
||||
@ -22,14 +25,32 @@ class SessionEvent(Enum):
|
||||
SESSION_REMOTE_CONTROL = 0x9 # WTS_SESSION_REMOTE_CONTROL
|
||||
|
||||
|
||||
class WorkstationMonitor:
|
||||
CLASS_NAME = "WorkstationMonitor"
|
||||
WINDOW_TITLE = "Workstation Event Monitor"
|
||||
class LockscreenMonitor(Thread):
|
||||
CLASS_NAME = "LockscreenMonitor"
|
||||
WINDOW_TITLE = "Lockscreen Event Monitor"
|
||||
__running = True
|
||||
|
||||
def __init__(self):
|
||||
self.window_handle = None
|
||||
self.event_handlers = defaultdict(list)
|
||||
self._register_listener()
|
||||
super().__init__()
|
||||
|
||||
def run(self) -> None:
|
||||
while self.__running:
|
||||
self.listen()
|
||||
time.sleep(0.1)
|
||||
|
||||
def stop(self):
|
||||
self.__running = False
|
||||
exit_code = 0
|
||||
win32gui.PostQuitMessage(exit_code)
|
||||
|
||||
def screen_locked(self) -> bool:
|
||||
if (ctypes.windll.User32.GetForegroundWindow() % 10 == 0):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def _register_listener(self):
|
||||
wc = win32gui.WNDCLASS()
|
||||
@ -51,11 +72,7 @@ class WorkstationMonitor:
|
||||
win32ts.WTSRegisterSessionNotification(self.window_handle, scope)
|
||||
|
||||
def listen(self):
|
||||
win32gui.PumpMessages()
|
||||
|
||||
def stop(self):
|
||||
exit_code = 0
|
||||
win32gui.PostQuitMessage(exit_code)
|
||||
win32gui.PumpWaitingMessages()
|
||||
|
||||
def _window_procedure(self, window_handle: int, message: int, event_id, session_id):
|
||||
"""
|
||||
@ -78,11 +95,11 @@ class WorkstationMonitor:
|
||||
for handler in self.event_handlers[SessionEvent.ANY]:
|
||||
handler(event)
|
||||
|
||||
def register_handler(self, event: SessionEvent, handler: callable):
|
||||
self.event_handlers[event].append(handler)
|
||||
def register_handler(self, handler: callable):
|
||||
self.event_handlers[SessionEvent.ANY].append(handler)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
m = WorkstationMonitor()
|
||||
m = LockscreenMonitor()
|
||||
m.register_handler(SessionEvent.ANY, handler=print)
|
||||
m.listen()
|
Loading…
x
Reference in New Issue
Block a user