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
|
from gui import Gui
|
||||||
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 resources import LineState, CLMgrMessage
|
|
||||||
|
|
||||||
import serial
|
if __name__ == "__main__":
|
||||||
from serial import SerialException
|
gui = Gui()
|
||||||
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")
|
|
@ -21,24 +21,20 @@ pyz = PYZ(a.pure, a.zipped_data,
|
|||||||
cipher=block_cipher)
|
cipher=block_cipher)
|
||||||
|
|
||||||
exe = EXE(pyz,
|
exe = EXE(pyz,
|
||||||
a.scripts,
|
a.scripts,
|
||||||
|
a.binaries,
|
||||||
|
a.zipfiles,
|
||||||
|
a.datas,
|
||||||
[],
|
[],
|
||||||
exclude_binaries=True,
|
|
||||||
name='__main__',
|
name='__main__',
|
||||||
debug=False,
|
debug=False,
|
||||||
bootloader_ignore_signals=False,
|
bootloader_ignore_signals=False,
|
||||||
strip=False,
|
strip=False,
|
||||||
upx=True,
|
upx=True,
|
||||||
|
upx_exclude=[],
|
||||||
|
runtime_tmpdir=None,
|
||||||
console=True,
|
console=True,
|
||||||
disable_windowed_traceback=False,
|
disable_windowed_traceback=False,
|
||||||
target_arch=None,
|
target_arch=None,
|
||||||
codesign_identity=None,
|
codesign_identity=None,
|
||||||
entitlements_file=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
|
winrt
|
||||||
pywin32
|
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 collections import defaultdict
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
from threading import Thread
|
||||||
import win32api
|
import win32api
|
||||||
import win32con
|
import win32con
|
||||||
import win32gui
|
import win32gui
|
||||||
import win32ts
|
import win32ts
|
||||||
|
import time
|
||||||
|
import ctypes
|
||||||
|
|
||||||
|
|
||||||
class SessionEvent(Enum):
|
class SessionEvent(Enum):
|
||||||
@ -22,14 +25,32 @@ class SessionEvent(Enum):
|
|||||||
SESSION_REMOTE_CONTROL = 0x9 # WTS_SESSION_REMOTE_CONTROL
|
SESSION_REMOTE_CONTROL = 0x9 # WTS_SESSION_REMOTE_CONTROL
|
||||||
|
|
||||||
|
|
||||||
class WorkstationMonitor:
|
class LockscreenMonitor(Thread):
|
||||||
CLASS_NAME = "WorkstationMonitor"
|
CLASS_NAME = "LockscreenMonitor"
|
||||||
WINDOW_TITLE = "Workstation Event Monitor"
|
WINDOW_TITLE = "Lockscreen Event Monitor"
|
||||||
|
__running = True
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.window_handle = None
|
self.window_handle = None
|
||||||
self.event_handlers = defaultdict(list)
|
self.event_handlers = defaultdict(list)
|
||||||
self._register_listener()
|
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):
|
def _register_listener(self):
|
||||||
wc = win32gui.WNDCLASS()
|
wc = win32gui.WNDCLASS()
|
||||||
@ -51,11 +72,7 @@ class WorkstationMonitor:
|
|||||||
win32ts.WTSRegisterSessionNotification(self.window_handle, scope)
|
win32ts.WTSRegisterSessionNotification(self.window_handle, scope)
|
||||||
|
|
||||||
def listen(self):
|
def listen(self):
|
||||||
win32gui.PumpMessages()
|
win32gui.PumpWaitingMessages()
|
||||||
|
|
||||||
def stop(self):
|
|
||||||
exit_code = 0
|
|
||||||
win32gui.PostQuitMessage(exit_code)
|
|
||||||
|
|
||||||
def _window_procedure(self, window_handle: int, message: int, event_id, session_id):
|
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]:
|
for handler in self.event_handlers[SessionEvent.ANY]:
|
||||||
handler(event)
|
handler(event)
|
||||||
|
|
||||||
def register_handler(self, event: SessionEvent, handler: callable):
|
def register_handler(self, handler: callable):
|
||||||
self.event_handlers[event].append(handler)
|
self.event_handlers[SessionEvent.ANY].append(handler)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
m = WorkstationMonitor()
|
m = LockscreenMonitor()
|
||||||
m.register_handler(SessionEvent.ANY, handler=print)
|
m.register_handler(SessionEvent.ANY, handler=print)
|
||||||
m.listen()
|
m.listen()
|
Loading…
x
Reference in New Issue
Block a user