Skip to content

Commit 7e89a37

Browse files
authored
Merge pull request #1 from mcallbosco/PlayPauseExternalUpdate
Update to enable automatic Play/Pause sync, along with some new settings.
2 parents 11da72c + 4e06332 commit 7e89a37

11 files changed

Lines changed: 12381 additions & 139 deletions

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
# Taskplay
1+
# TaskplayUpdated
22
![Screenshot](https://raw.githubusercontent.com/evilpro/Taskplay/master/Taskplay.png)
33

4-
Taskplay is a small utility which adds media playback controls to the Windows System Tray
4+
Taskplay is a small utility which adds media playback controls to the Windows System Tray. This fork adds many essential features such as automatically updating the playing icon if you play or pause something, the ability to hide specific buttons, and the ability to have the song seek icons hidden while nothing is playing.
55

66
## Info
77
Taskplay is written in C#
88

9-
It is currently targeting .NET Framework 2.0 so it should be compatible with most Windows versions.
9+
This version of taskplay has been updated to use the Contracks SDK to grab if anything is playing, so it requires a minimum of Windows 10 version 1903 and .Net framework 4.7.2
1010

1111
## Download
1212
To download Taskplay, please go to the Releases tab of this repository.

Taskplay/App.config

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@
22
<configuration>
33
<startup>
44

5-
<supportedRuntime version="v2.0.50727"/></startup>
5+
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2"/></startup>
66
</configuration>

Taskplay/Program.cs

Lines changed: 177 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,29 @@
11
using System;
22
using System.Runtime.InteropServices;
33
using System.Windows.Forms;
4+
using Windows.Media.Control;
45

56
namespace 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
}

Taskplay/Properties/AssemblyInfo.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@
55
// General Information about an assembly is controlled through the following
66
// set of attributes. Change these attribute values to modify the information
77
// associated with an assembly.
8-
[assembly: AssemblyTitle("Taskplay")]
8+
[assembly: AssemblyTitle("TaskplayUpdated")]
99
[assembly: AssemblyDescription("Taskplay is a small utility which adds media playback controls to the Windows System Tray")]
1010
[assembly: AssemblyConfiguration("")]
11-
[assembly: AssemblyCompany("evil_pro")]
11+
[assembly: AssemblyCompany("mcallbosco, forked from evil_pro")]
1212
[assembly: AssemblyProduct("Taskplay")]
1313
[assembly: AssemblyCopyright("")]
1414
[assembly: AssemblyTrademark("")]
@@ -32,5 +32,5 @@
3232
// You can specify all the values or you can default the Build and Revision Numbers
3333
// by using the '*' as shown below:
3434
// [assembly: AssemblyVersion("1.0.*")]
35-
[assembly: AssemblyVersion("1.0.1.0")]
36-
[assembly: AssemblyFileVersion("1.0.1.0")]
35+
[assembly: AssemblyVersion("2.0.0.0")]
36+
[assembly: AssemblyFileVersion("2.0.0.0")]

Taskplay/Properties/Resources.Designer.cs

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Taskplay/Properties/Settings.Designer.cs

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)