Compare commits
No commits in common. "65f3a5c1daa52ebeee5ca1e288793e0ce2b4817d" and "172a91c7408a56ab7253956e622720b442217cc5" have entirely different histories.
65f3a5c1da
...
172a91c740
110
__main__.py
110
__main__.py
@ -1,5 +1,109 @@
|
|||||||
from gui import Gui
|
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 resources import LineState, CLMgrMessage
|
||||||
|
|
||||||
if __name__ == "__main__":
|
import serial
|
||||||
gui = Gui()
|
from serial import SerialException
|
||||||
|
|
||||||
|
portName = 'COM3'
|
||||||
|
|
||||||
|
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=""):
|
||||||
|
|
||||||
|
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'shc131139131')
|
||||||
|
else:
|
||||||
|
sendSerial(b'shc255029000')
|
||||||
|
asyncio.run(try_pause())
|
||||||
|
for linenum in range(self.phone_mgr.DispNumberOfLines):
|
||||||
|
line = self.phone_mgr.DispGetLine(linenum)
|
||||||
|
if line.DispState != LineState.Inactive:
|
||||||
|
return True
|
||||||
|
asyncio.run(try_play())
|
||||||
|
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()
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
win32com.client.WithEvents("CLMgr.ClientLineMgr", PhoneLineEventHandler)
|
||||||
|
while True:
|
||||||
|
pythoncom.PumpWaitingMessages()
|
||||||
|
time.sleep(0.1) # Don't use up all our CPU checking constantly
|
@ -22,19 +22,23 @@ pyz = PYZ(a.pure, a.zipped_data,
|
|||||||
|
|
||||||
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
BIN
favicon.ico
Binary file not shown.
Before Width: | Height: | Size: 66 KiB |
147
gui.py
147
gui.py
@ -1,147 +0,0 @@
|
|||||||
# 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
607
ledcontroll.py
@ -1,607 +0,0 @@
|
|||||||
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
119
mediacontrol.py
@ -1,119 +0,0 @@
|
|||||||
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,4 +1,2 @@
|
|||||||
winrt
|
winrt
|
||||||
pywin32
|
pywin32
|
||||||
python3-tk
|
|
||||||
pystray
|
|
100
resources.py
Normal file
100
resources.py
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
|
||||||
|
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
|
@ -1,44 +0,0 @@
|
|||||||
# -*- 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
221
swyxcontrol.py
@ -1,221 +0,0 @@
|
|||||||
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,105 +0,0 @@
|
|||||||
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):
|
|
||||||
ANY = 0
|
|
||||||
# window messages
|
|
||||||
CHANGE = 0x2B1 # WM_WTSSESSION_CHANGE
|
|
||||||
# WM_WTSSESSION_CHANGE events (wparam)
|
|
||||||
CONSOLE_CONNECT = 0x1 # WTS_CONSOLE_CONNECT
|
|
||||||
CONSOLE_DISCONNECT = 0x2 # WTS_CONSOLE_DISCONNECT
|
|
||||||
REMOTE_CONNECT = 0x3 # WTS_REMOTE_CONNECT
|
|
||||||
REMOTE_DISCONNECT = 0x4 # WTS_REMOTE_DISCONNECT
|
|
||||||
SESSION_LOGON = 0x5 # WTS_SESSION_LOGON
|
|
||||||
SESSION_LOGOFF = 0x6 # WTS_SESSION_LOGOFF
|
|
||||||
SESSION_LOCK = 0x7 # WTS_SESSION_LOCK
|
|
||||||
SESSION_UNLOCK = 0x8 # WTS_SESSION_UNLOCK
|
|
||||||
SESSION_REMOTE_CONTROL = 0x9 # WTS_SESSION_REMOTE_CONTROL
|
|
||||||
|
|
||||||
|
|
||||||
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()
|
|
||||||
wc.hInstance = handle_instance = win32api.GetModuleHandle(None)
|
|
||||||
wc.lpszClassName = self.CLASS_NAME
|
|
||||||
wc.lpfnWndProc = self._window_procedure
|
|
||||||
window_class = win32gui.RegisterClass(wc)
|
|
||||||
|
|
||||||
style = 0
|
|
||||||
self.window_handle = win32gui.CreateWindow(window_class,
|
|
||||||
self.WINDOW_TITLE,
|
|
||||||
style,
|
|
||||||
0, 0, win32con.CW_USEDEFAULT, win32con.CW_USEDEFAULT,
|
|
||||||
0, 0, handle_instance, None)
|
|
||||||
win32gui.UpdateWindow(self.window_handle)
|
|
||||||
|
|
||||||
# scope = win32ts.NOTIFY_FOR_THIS_SESSION
|
|
||||||
scope = win32ts.NOTIFY_FOR_ALL_SESSIONS
|
|
||||||
win32ts.WTSRegisterSessionNotification(self.window_handle, scope)
|
|
||||||
|
|
||||||
def listen(self):
|
|
||||||
win32gui.PumpWaitingMessages()
|
|
||||||
|
|
||||||
def _window_procedure(self, window_handle: int, message: int, event_id, session_id):
|
|
||||||
"""
|
|
||||||
# WindowProc callback function
|
|
||||||
|
|
||||||
https://msdn.microsoft.com/en-us/library/ms633573(v=VS.85).aspx
|
|
||||||
"""
|
|
||||||
if message == SessionEvent.CHANGE.value:
|
|
||||||
self._handle_session_change(SessionEvent(event_id), session_id)
|
|
||||||
elif message == win32con.WM_CLOSE:
|
|
||||||
win32gui.DestroyWindow(window_handle)
|
|
||||||
elif message == win32con.WM_DESTROY:
|
|
||||||
win32gui.PostQuitMessage(0)
|
|
||||||
elif message == win32con.WM_QUERYENDSESSION:
|
|
||||||
return True
|
|
||||||
|
|
||||||
def _handle_session_change(self, event: SessionEvent, session_id: int):
|
|
||||||
for handler in self.event_handlers[event]:
|
|
||||||
handler(event)
|
|
||||||
for handler in self.event_handlers[SessionEvent.ANY]:
|
|
||||||
handler(event)
|
|
||||||
|
|
||||||
def register_handler(self, handler: callable):
|
|
||||||
self.event_handlers[SessionEvent.ANY].append(handler)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
m = LockscreenMonitor()
|
|
||||||
m.register_handler(SessionEvent.ANY, handler=print)
|
|
||||||
m.listen()
|
|
Loading…
x
Reference in New Issue
Block a user