11using System ;
22using System . Runtime . InteropServices ;
33using System . Windows . Forms ;
4+ using Windows . Media . Control ;
45
56namespace Taskplay
67{
78 static class Program
89 {
910 static bool _isMusicPlaying = false ; // Bool to keep in check if the user is playing music
10-
1111 static bool IsDarkModeOn => GetSettingState ( "DarkMode" ) ;
12- static bool AreChangeSongButtonsShown => GetSettingState ( "ShowChangeSongButtons" ) ;
12+ static bool showNextButton => GetSettingState ( "ShowNextButton" , true ) ;
13+ static bool showPrevButton => GetSettingState ( "ShowPrevButton" , true ) ;
14+ static bool IsSyncEnabled => GetSettingState ( "SyncEnabled" , true ) ;
15+ static int SyncInterval => int . Parse ( GetSettingStateString ( "SyncInterval" , "500" ) ) ;
16+ static int waitTimeAfterClickToRefresh => int . Parse ( GetSettingStateString ( "PauseSyncAfterClick" , "3000" ) ) ; //ms
17+ static int waitTimeRemaining = 0 ;
18+ static bool dontShowSkipWhilePaused => GetSettingState ( "DontShowSkipWhilePaused" ) ;
19+
20+ static NotifyIcon playIcon = new NotifyIcon ( ) ;
21+
22+ static NotifyIcon nextIcon = null ;
1323
24+ static NotifyIcon previousIcon = null ;
1425
26+ static ContextMenu contextMenu = new ContextMenu ( ) ;
1527
1628 static readonly Action < bool > restartAction = ( b ) => Application . Restart ( ) ;
1729
@@ -21,14 +33,19 @@ static class Program
2133 [ STAThread ]
2234 static void Main ( )
2335 {
36+ //check for already running
37+ if ( System . Diagnostics . Process . GetProcessesByName ( System . IO . Path . GetFileNameWithoutExtension ( System . Reflection . Assembly . GetEntryAssembly ( ) . Location ) ) . Length > 1 )
38+ {
39+ //sleep for 500 ms and then check again
40+ System . Threading . Thread . Sleep ( 500 ) ;
41+ if ( System . Diagnostics . Process . GetProcessesByName ( System . IO . Path . GetFileNameWithoutExtension ( System . Reflection . Assembly . GetEntryAssembly ( ) . Location ) ) . Length > 1 )
42+ { MessageBox . Show ( "Taskplay is already running" , "Taskplay" , MessageBoxButtons . OK , MessageBoxIcon . Information ) ;
43+ return ;
44+ }
45+ }
2446 Application . EnableVisualStyles ( ) ;
2547 Application . SetCompatibleTextRenderingDefault ( false ) ;
26- //Create system tray icons
27- NotifyIcon previousIcon = new NotifyIcon ( ) ;
28- NotifyIcon playIcon = new NotifyIcon ( ) ;
29- NotifyIcon nextIcon = new NotifyIcon ( ) ;
3048 //Create the context menu and its items
31- ContextMenu contextMenu = new ContextMenu ( ) ;
3249 MenuItem contextItemSettings = new MenuItem ( ) ;
3350 MenuItem contextItemExit = new MenuItem ( ) ;
3451 //Setup the context menu items
@@ -39,25 +56,28 @@ static void Main()
3956 //Add the context menu items to the context menu
4057 contextMenu . MenuItems . Add ( contextItemSettings ) ;
4158 contextMenu . MenuItems . Add ( contextItemExit ) ;
42- //Setup nextIcon
43- nextIcon . Icon = IsDarkModeOn ? Properties . Resources . ForwardDark : Properties . Resources . Forward ;
44- nextIcon . Text = "Next" ;
45- nextIcon . Visible = AreChangeSongButtonsShown ;
46- nextIcon . MouseClick += new MouseEventHandler ( nextIcon_MouseClick ) ;
47- nextIcon . ContextMenu = contextMenu ;
59+
60+ //Setup next and prev icons
61+
62+
63+
4864 //Setup playIcon
49- playIcon . Icon = IsDarkModeOn ? Properties . Resources . PlayDark : Properties . Resources . Play ;
65+ updatePlayingIcon ( _isMusicPlaying ) ;
5066 playIcon . Text = "Play / Pause" ;
5167 playIcon . Visible = true ;
5268 playIcon . MouseClick += new MouseEventHandler ( playIcon_MouseClick ) ;
5369 playIcon . ContextMenu = contextMenu ;
54- //Setup previousIcon
55- previousIcon . Icon = IsDarkModeOn ? Properties . Resources . BackwardDark : Properties . Resources . Backward ;
56- previousIcon . Text = "Previous" ;
57- previousIcon . Visible = AreChangeSongButtonsShown ;
58- previousIcon . MouseClick += new MouseEventHandler ( previousIcon_MouseClick ) ;
59- previousIcon . ContextMenu = contextMenu ;
70+
71+
72+
73+ var sessionManager = GlobalSystemMediaTransportControlsSessionManager . RequestAsync ( ) . AsTask ( ) . Result ;
6074
75+ if ( IsSyncEnabled ) {
76+ var timer = new System . Threading . Timer ( ( e ) =>
77+ {
78+ mediaStateChange ( sessionManager , playIcon , SyncInterval ) ;
79+ } , null , TimeSpan . Zero , TimeSpan . FromMilliseconds ( SyncInterval ) ) ;
80+ }
6181 //Launch
6282 Application . Run ( ) ;
6383 }
@@ -79,27 +99,11 @@ private static void playIcon_MouseClick(object sender, MouseEventArgs e)
7999 {
80100 keybd_event ( 0xB3 , 0 , 0x0001 , IntPtr . Zero ) ;
81101 keybd_event ( 0xB3 , 0 , 0x0002 , IntPtr . Zero ) ;
82-
83- // Get the Play-button
84- var playIcon = ( NotifyIcon ) sender ;
85-
86- if ( _isMusicPlaying == false )
87- {
88- // Start playing music and show the pause-icon
89- playIcon . Icon = IsDarkModeOn ? Properties . Resources . PauseDark : Properties . Resources . Pause ;
90- _isMusicPlaying = true ;
91- }
92- else
93- {
94- // Pause the music and display the Play-icon
95- playIcon . Icon = IsDarkModeOn ? Properties . Resources . PlayDark : Properties . Resources . Play ;
96- _isMusicPlaying = false ;
97- }
102+ waitTimeRemaining = waitTimeAfterClickToRefresh ;
103+ updatePlayingIcon ( ! _isMusicPlaying ) ;
98104 }
99105
100- // PLEASE NOTE; this method does NOT check whether the music has been paused by an external source.
101- // This could be added by building in an check that listens to the state of the systems MusicPlayer
102- // I hope this gives a nice base to start with. :)
106+
103107 }
104108
105109 private static void nextIcon_MouseClick ( object sender , MouseEventArgs e )
@@ -112,34 +116,164 @@ private static void nextIcon_MouseClick(object sender, MouseEventArgs e)
112116 }
113117 }
114118
119+ private static NotifyIcon spawnNextIcon ( bool doit )
120+ {
121+ if ( ! doit ) return null ;
122+ NotifyIcon newNextIcon = new NotifyIcon ( ) ;
123+ //Setup nextIcon
124+ newNextIcon . Icon = IsDarkModeOn ? Properties . Resources . ForwardDark : Properties . Resources . Forward ;
125+ newNextIcon . Text = "Next" ;
126+ newNextIcon . Visible = showNextButton ;
127+ newNextIcon . MouseClick += new MouseEventHandler ( nextIcon_MouseClick ) ;
128+ newNextIcon . ContextMenu = contextMenu ;
129+ return newNextIcon ;
130+ }
131+
132+ private static NotifyIcon spawnPreviousIcon ( bool doIt )
133+ {
134+ if ( ! doIt ) return null ;
135+ NotifyIcon newPreviousIcon = new NotifyIcon ( ) ;
136+ //Setup previousIcon
137+ newPreviousIcon . Icon = IsDarkModeOn ? Properties . Resources . BackwardDark : Properties . Resources . Backward ;
138+ newPreviousIcon . Text = "Previous" ;
139+ newPreviousIcon . Visible = true ;
140+ newPreviousIcon . MouseClick += new MouseEventHandler ( previousIcon_MouseClick ) ;
141+ newPreviousIcon . ContextMenu = contextMenu ;
142+ return newPreviousIcon ;
143+ }
144+
145+
146+ public static void updatePlayingIcon ( bool playing )
147+ {
148+ if ( playing == true )
149+ {
150+ // Start playing music and show the pause-icon
151+ playIcon . Icon = IsDarkModeOn ? Properties . Resources . PauseDark : Properties . Resources . Pause ;
152+ _isMusicPlaying = true ;
153+ playIcon . Text = "Pause" ;
154+ //Spawn the next and previous icons if they are not already spawned
155+
156+ if ( nextIcon == null ) nextIcon = spawnNextIcon ( showNextButton ) ;
157+ if ( previousIcon == null ) previousIcon = spawnPreviousIcon ( showPrevButton ) ;
158+
159+ }
160+ else
161+ {
162+ // Pause the music and display the Play-icon
163+ playIcon . Icon = IsDarkModeOn ? Properties . Resources . PlayDark : Properties . Resources . Play ;
164+ _isMusicPlaying = false ;
165+ playIcon . Text = "Play" ;
166+ //Dispose the next and previous icons if we are not showing them while paused
167+ if ( dontShowSkipWhilePaused )
168+ {
169+ if ( nextIcon != null ) nextIcon . Dispose ( ) ;
170+ nextIcon = null ;
171+ if ( previousIcon != null ) previousIcon . Dispose ( ) ;
172+ previousIcon = null ;
173+ }
174+ else
175+ {
176+ if ( nextIcon == null ) nextIcon = spawnNextIcon ( showNextButton ) ;
177+ if ( previousIcon == null ) previousIcon = spawnPreviousIcon ( showPrevButton ) ;
178+ }
179+ }
180+
181+
182+ }
183+
115184 private static void contextMenuSettings_Click ( object sender , System . EventArgs e )
116185 {
117186 //Show Settings form
118- var settingsForm = new SettingsForm ( IsDarkModeOn , AreChangeSongButtonsShown , restartAction ) ;
187+ var settingsForm = new SettingsForm ( IsDarkModeOn , showNextButton , showPrevButton , restartAction , IsSyncEnabled , SyncInterval , waitTimeAfterClickToRefresh , dontShowSkipWhilePaused ) ;
119188 settingsForm . ShowDialog ( ) ;
120189 }
121190
122191 private static void contextMenuExit_Click ( object sender , System . EventArgs e )
123192 {
193+ hideIcons ( ) ;
194+ //sleep for 500 ms
195+ System . Threading . Thread . Sleep ( 500 ) ;
196+
197+
124198 //Exit the app
125199 Application . Exit ( ) ;
126200 }
127201
128- private static bool GetSettingState ( string settingName )
202+
203+
204+ //listener for media events
205+ private static void mediaStateChange ( GlobalSystemMediaTransportControlsSessionManager sessionManager1 , NotifyIcon playIcon , int refreshIntervalForMediaState )
206+ {
207+ //wait for the interval to pass
208+ if ( waitTimeRemaining > 0 )
209+ {
210+ waitTimeRemaining -= refreshIntervalForMediaState ;
211+ return ;
212+ } else
213+ {
214+ waitTimeRemaining = 0 ;
215+ }
216+
217+
218+ // check through all sessions to see if anything is playing
219+ var sessionManager = GlobalSystemMediaTransportControlsSessionManager . RequestAsync ( ) . AsTask ( ) . Result ;
220+
221+ for ( int i = 0 ; i < sessionManager . GetSessions ( ) . Count ; i ++ )
222+ {
223+ if ( sessionManager . GetSessions ( ) [ i ] . GetPlaybackInfo ( ) . PlaybackStatus . ToString ( ) == "Playing" )
224+ {
225+ updatePlayingIcon ( true ) ;
226+ return ;
227+ }
228+ else
229+ {
230+ updatePlayingIcon ( false ) ;
231+ }
232+ }
233+ }
234+
235+
236+
237+ private static bool GetSettingState ( string settingName , bool defaultValueBool = false )
129238 {
239+ int defaultValue = defaultValueBool ? 1 : 0 ;
130240 var subKey = Microsoft . Win32 . Registry . CurrentUser . CreateSubKey ( @"SOFTWARE\Taskplay" ) ;
131241
132242 var keyValue = subKey . GetValue ( settingName ) ;
133243
134244 if ( keyValue == null )
135245 {
136- subKey . SetValue ( settingName , 0 ) ;
137- return false ;
246+ subKey . SetValue ( settingName , defaultValue ) ;
247+ return defaultValueBool ;
138248 }
139249
140250 return ( int ) keyValue == 1 ;
141251 }
142252
253+ private static String GetSettingStateString ( string settingName , string defaultValue )
254+ {
255+ var subKey = Microsoft . Win32 . Registry . CurrentUser . CreateSubKey ( @"SOFTWARE\Taskplay" ) ;
256+
257+ var keyValue = subKey . GetValue ( settingName ) ;
258+
259+ if ( keyValue == null )
260+ {
261+ subKey . SetValue ( settingName , defaultValue , Microsoft . Win32 . RegistryValueKind . String ) ;
262+ return defaultValue ;
263+ }
264+
265+
266+ return keyValue . ToString ( ) ;
267+ }
268+ public static void hideIcons ( )
269+ {
270+ playIcon ? . Dispose ( ) ;
271+ nextIcon ? . Dispose ( ) ;
272+ previousIcon ? . Dispose ( ) ;
273+
274+ }
275+
276+
143277 [ DllImport ( "user32.dll" , SetLastError = true ) ]
144278 public static extern void keybd_event ( byte virtualKey , byte scanCode , uint flags , IntPtr extraInfo ) ;
145279 }
0 commit comments