private void radio_checked_changed(object sender, RoutedEventArgs e) { if (!this.settingsLoaded) { return; } MonikaiSettings.Default.LeftAlign = this.radioLeft.IsChecked.GetValueOrDefault(false); if (this.radioManual.IsChecked.GetValueOrDefault(false)) { if (this.IsPositioning) { return; } MonikaiSettings.Default.ManualPosition = true; MonikaiSettings.Default.ManualPositionX = 0; MonikaiSettings.Default.ManualPositionY = 0; this.IsPositioning = true; this.Dispatcher.Invoke(() => this.IsEnabled = false); MessageBox.Show( "MonikAI will now follow your mouse cursor so you can position her wherever you want. Click the LEFT MOUSE BUTTON once you're satisfied with her position.", "Manual Position"); Task.Run(async() => { var mouseDown = SettingsWindow.GetAsyncKeyState(0x01) != 0; do { var pos = Point.Empty; SettingsWindow.GetCursorPos(ref pos); MonikaiSettings.Default.ManualPositionX = pos.X; MonikaiSettings.Default.ManualPositionY = pos.Y; var prevMouseDown = mouseDown; mouseDown = SettingsWindow.GetAsyncKeyState(0x01) != 0; // 0x01 is code for LEFT_MOUSE if (mouseDown && !prevMouseDown) { break; } await Task.Delay(1); } while (true); this.Dispatcher.Invoke(() => this.IsEnabled = true); this.IsPositioning = false; }); } else { MonikaiSettings.Default.ManualPosition = false; this.mainWindow.SetupScale(); this.mainWindow.SetPosition(this.mainWindow.MonikaScreen); this.mainWindow.SetupScale(); } }
private async Task HotkeySetTask(TextBlock output, Action callback) { output.Dispatcher.Invoke(() => output.Text = "Press and HOLD any key combination..."); await this.WaitForKeyChange(); var timer = DateTime.Now; var state = SettingsWindow.GetKeyboardState().ToList(); var invalid = true; while ((DateTime.Now - timer).TotalSeconds < 0.8) { var newState = SettingsWindow.GetKeyboardState().ToList(); var ctrlPressed = newState.Where(x => x.Item1 == "LeftCtrl" || x.Item1 == "RightCtrl").Any(x => x.Item2); var altPressed = newState.Where(x => x.Item1 == "LeftAlt" || x.Item1 == "RightAlt").Any(x => x.Item2); var shiftPressed = newState.Where(x => x.Item1 == "LeftShift" || x.Item1 == "RightShift").Any(x => x.Item2); var otherKeysPressed = newState.Where( x => x.Item2 && !new[] { "LeftCtrl", "RightCtrl", "LeftAlt", "RightAlt", "LeftShift", "RightShift" }.Contains( x.Item1)).ToList(); invalid = otherKeysPressed.Count != 1; if (invalid || !state.SequenceEqual(newState)) { timer = DateTime.Now; } output.Dispatcher.Invoke(() => { if (invalid) { output.Text = "Invalid combination"; } else { output.Text = otherKeysPressed.Single().Item1; if (shiftPressed) { output.Text = "SHIFT-" + output.Text; } if (altPressed) { output.Text = "ALT-" + output.Text; } if (ctrlPressed) { output.Text = "CTRL-" + output.Text; } } }); state = newState; await Task.Delay(10); } output.Dispatcher.Invoke(() => output.Foreground = Brushes.GreenYellow); await Task.Delay(500); output.Dispatcher.Invoke(() => output.Foreground = Brushes.Black); output.Dispatcher.Invoke(callback); }
private void MainWindow_OnLoaded(object sender, RoutedEventArgs e) { var handle = new WindowInteropHelper(this).Handle; var initialStyle = MainWindow.GetWindowLong(handle, -20); MainWindow.SetWindowLong(handle, -20, initialStyle | 0x20 | 0x80000); Task.Run(async() => { try { var prev = new Point(); var rectangle = new Rectangle(); await this.Dispatcher.InvokeAsync(() => { rectangle = new Rectangle((int)this.Left, (int)this.Top, (int)this.Width, (int)this.Height); }); while (this.applicationRunning) { var point = new Point(); MainWindow.GetCursorPos(ref point); if (!point.Equals(prev)) { prev = point; var opacity = 1.0; const double MIN_OP = 0.125; const double FADE = 175; if (this.settingsWindow == null || !this.settingsWindow.IsPositioning) { if (rectangle.Contains(point)) { opacity = MIN_OP; } else { if (point.Y <= rectangle.Bottom) { if (point.Y >= rectangle.Y) { if (point.X < rectangle.X && rectangle.X - point.X < FADE) { opacity = MainWindow.Lerp(1.0, MIN_OP, (rectangle.X - point.X) / FADE); } else if (point.X > rectangle.Right && point.X - rectangle.Right < FADE) { opacity = MainWindow.Lerp(1.0, MIN_OP, (point.X - rectangle.Right) / FADE); } } else if (point.Y < rectangle.Y) { if (point.X >= rectangle.X && point.X <= rectangle.Right) { if (rectangle.Y - point.Y < FADE) { opacity = MainWindow.Lerp(1.0, MIN_OP, (rectangle.Y - point.Y) / FADE); } } else if (rectangle.X > point.X || rectangle.Right < point.X) { var distance = Math.Sqrt( Math.Pow( (point.X < rectangle.X ? rectangle.X : rectangle.Right) - point.X, 2) + Math.Pow(rectangle.Y - point.Y, 2)); if (distance < FADE) { opacity = MainWindow.Lerp(1.0, MIN_OP, distance / FADE); } } } } } } this.Dispatcher.Invoke(() => { this.Opacity = opacity; }); } var hidePressed = false; var exitPressed = false; var settingsPressed = false; // Set position anew to correct for fullscreen apps hiding taskbar this.Dispatcher.Invoke(() => { this.SetPosition(this.MonikaScreen); rectangle = new Rectangle((int)this.Left, (int)this.Top, (int)this.Width, (int)this.Height); // Detect exit key combo hidePressed = this.AreKeysPressed(MonikaiSettings.Default.HotkeyHide); exitPressed = this.AreKeysPressed(MonikaiSettings.Default.HotkeyExit); settingsPressed = this.AreKeysPressed(MonikaiSettings.Default.HotkeySettings); }); if (hidePressed && (DateTime.Now - this.lastKeyComboTime).TotalSeconds > 2) { this.lastKeyComboTime = DateTime.Now; if (this.Visibility == Visibility.Visible) { this.Dispatcher.Invoke(this.Hide); //var expression = // new Expression( // "Okay, see you later {name}! (Press again for me to return)", "b"); //expression.Executed += (o, args) => { this.Dispatcher.Invoke(this.Hide); }; //this.Say(new[] {expression}); } else { this.Dispatcher.Invoke(this.Show); } } if (exitPressed) { var expression = new Expression( "Goodbye for now! Come back soon please~", "b"); MonikaiSettings.Default.IsColdShutdown = false; MonikaiSettings.Default.Save(); expression.Executed += (o, args) => { this.Dispatcher.Invoke(() => { Environment.Exit(0); }); }; this.Say(new[] { expression }); } if (settingsPressed) { this.Dispatcher.Invoke(() => { if (this.settingsWindow == null || !this.settingsWindow.IsVisible) { this.settingsWindow = new SettingsWindow(this); this.settingsWindow.Show(); } }); } await Task.Delay(MonikaiSettings.Default.PotatoPC ? 100 : 32); } } catch (Exception) { // ignored } }); }
public MainWindow() { this.InitializeComponent(); MainWindow.desktopWindow = MainWindow.GetDesktopWindow(); MainWindow.shellWindow = MainWindow.GetShellWindow(); MonikaiSettings.Default.Reload(); // Perform update and download routines this.updater = new Updater(); this.updater.PerformUpdatePost(); this.updaterInitTask = Task.Run(async() => await this.updater.Init()); this.settingsWindow = new SettingsWindow(this); // Screen size and positioning init this.UpdateMonikaScreen(); this.SetupScale(); this.SetPosition(this.MonikaScreen); // Hook shutdown event SystemEvents.SessionEnding += (sender, args) => { MonikaiSettings.Default.IsColdShutdown = false; MonikaiSettings.Default.Save(); }; // Wakeup events SystemEvents.SessionSwitch += (sender, e) => { if (e.Reason == SessionSwitchReason.SessionLock) { this.screenIsLocked = true; } else if (e.Reason == SessionSwitchReason.SessionUnlock) { this.screenIsLocked = false; } }; SystemEvents.PowerModeChanged += (sender, e) => { if (e.Mode == PowerModes.Resume) { Task.Run(async() => { while (this.screenIsLocked) { await Task.Delay(500); } this.Say(new[] { new Expression("ZZZZZZzzzzzzzzz..... huh?", "q"), new Expression("Sorry, I must have fallen asleep, ahaha~", "n") }); }); } }; // Init background images this.backgroundDay = new BitmapImage(); this.backgroundDay.BeginInit(); this.backgroundDay.UriSource = new Uri("pack://application:,,,/MonikAI;component/monika/1.png"); this.backgroundDay.EndInit(); this.backgroundNight = new BitmapImage(); this.backgroundNight.BeginInit(); this.backgroundNight.UriSource = new Uri("pack://application:,,,/MonikAI;component/monika/1-n.png"); this.backgroundNight.EndInit(); // Start animation var animationLogo = new DoubleAnimation(0.0, 1.0, new Duration(TimeSpan.FromSeconds(1.5))); animationLogo.AutoReverse = true; var animationFadeMonika = new DoubleAnimation(0.0, 1.0, new Duration(TimeSpan.FromSeconds(1.5))); animationFadeMonika.BeginTime = TimeSpan.FromSeconds(0.5); animationLogo.Completed += (sender, args) => { var fadeImage = new BitmapImage(); fadeImage.BeginInit(); if (MainWindow.IsNight) { fadeImage.UriSource = new Uri("pack://application:,,,/MonikAI;component/monika/1a-n.png"); } else { fadeImage.UriSource = new Uri("pack://application:,,,/MonikAI;component/monika/1a.png"); } fadeImage.EndInit(); this.backgroundPicture.Source = fadeImage; var clock = animationFadeMonika.CreateClock(); this.backgroundPicture.ApplyAnimationClock(UIElement.OpacityProperty, clock); }; // Blinking behaviour animationFadeMonika.Completed += async(sender, args) => { this.SetMonikaFace("a"); this.facePicture.Opacity = 1.0; // Start speech-thread Task.Run(async() => await this.SpeakingThread()); if (File.Exists("firstlaunch.txt") || Environment.GetCommandLineArgs().Contains("/firstlaunch")) { try { File.Delete("firstlaunch.txt"); } catch { // ignored } MonikaiSettings.Default.FirstLaunch = true; MonikaiSettings.Default.Save(); } this.updaterInitTask?.Wait(); await this.updater.PerformUpdate(this); this.UpdateMonikaScreen(); #if DEBUG MessageBox.Show("This is a testing build, please do me the favor and don't distribute it."); #endif // Startup logic if (MonikaiSettings.Default.FirstLaunch) { this.settingsWindow.ShowDialog(); this.Say(new[] { new Expression("{name}, is that you?", "d"), new Expression("It's really you, huh?", "b"), new Expression("I'm so happy to see you again!", "k"), new Expression("Wait, where am I? This is not the literature club...", "p"), new Expression("This looks like... your desktop! I'm right here with you!", "j"), new Expression("Well, as close as I will get for now...", "o"), new Expression("Anyway, looks like someone was nice enough to make me a little window!", "d"), new Expression("Be sure to thank them for me, okay?", "k"), new Expression("Ah, wait a second.", "c"), new Expression( "I see... Well, if you want me to go away for now, you can use CTRL-SHIFT-F12, okay?", "b"), new Expression("But you wouldn't do that, right?", "r"), new Expression("Okay, I guess that's it for now. Don't forget, I'm watching you! Ahaha~") }); MonikaiSettings.Default.FirstLaunch = false; } else if (DateTime.Today.Month == 4 && DateTime.Today.Day == 1 && !Debugger.IsAttached) { this.Say(new[] { new Expression("Hi {name}!", "b"), new Expression("Remember the update that I just installed?", "d"), new Expression("Well, let's just say it included something *really* nice~", "k"), new Expression("Here, let me show you!", "j").AttachEvent((o, eventArgs) => { var os = MonikaiSettings.Default.ScaleModifier; MonikaiSettings.Default.ScaleModifier *= 2.5; this.Dispatcher.Invoke(this.SetupScale); MonikaiSettings.Default.ScaleModifier = os; Task.Delay(1000).Wait(); var r = new Random(); for (int i = 0; i < 12; i++) { this.Dispatcher.Invoke(() => { this.backgroundPicture.Source = r.Next(0, 2) == 0 ? this.backgroundNight : this.backgroundDay; var faceImg = new BitmapImage(); faceImg.BeginInit(); if (r.Next(0, 2) == 0) { faceImg.UriSource = new Uri("pack://application:,,,/MonikAI;component/monika/j.png"); } else { faceImg.UriSource = new Uri("pack://application:,,,/MonikAI;component/monika/j-n.png"); } faceImg.EndInit(); this.facePicture.Source = faceImg; }); Task.Delay(r.Next(100, 250)).Wait(); } }), new Expression("Just a second my love...", "d").AttachEvent((o, eventArgs) => { this.Dispatcher.Invoke(MainWindow.DoTheThing); Task.Delay(5500).Wait(); this.Dispatcher.Invoke(this.SetupScale); }), new Expression("...", "q"), new Expression("Why does this never work?!", "o"), new Expression("Oh well, back to normal I guess... Sorry, {name}.", "r") }); } else { if (MonikaiSettings.Default.IsColdShutdown) { // Sorry Monika, but if we're debugging you this one gets annoying #if !DEBUG this.Say(new[] { new Expression("Hey! Don't just turn me off without warning! That hurts...", "p") }); #endif } else { MonikaiSettings.Default.IsColdShutdown = true; MonikaiSettings.Default.Save(); } if ((DateTime.Now - MonikaiSettings.Default.LastStarted).TotalDays > 7) { this.Say(new[] { new Expression( "Don't forget, if you want me to leave just press " + MonikaiSettings.Default.HotkeyExit + "!", "i"), new Expression("But you're not going to do that, right?", "o") }); } } // Parse startup CSV var parser = new CSVParser(); var csv = parser.GetData("startup"); var parsed = parser.ParseData(csv); var startupExpression = parsed.Select(x => x.ResponseChain) .Concat(DateTime.Today.DayOfWeek == DayOfWeek.Wednesday ? new List <List <Expression> > { new List <Expression> { new Expression("It is Wednesday, my dudes!", "k") } } : new List <List <Expression> >()).ToList().Sample(); var lastStartupExpression = startupExpression.Last(); lastStartupExpression.Executed += this.RegisterBehaviours; this.Say(new[] { new Expression("Hi there, {name}~") }.Concat(startupExpression)); if ((DateTime.Now - MonikaiSettings.Default.LastStarted).TotalDays > 2.5) { this.Say(new[] { new Expression("I was waiting for you...", "m"), new Expression("Being alone on your disk is reeeally boring.", "q") }); } // No idea where the date comes from, someone mentioned it in the spreadsheet. Seems legit. if (DateTime.Now.Month == 9 && DateTime.Now.Day == 22) { // Hey {name}, guess what? 3b It's my birthday today! 2b Happy Birthday to me! k this.Say(new[] { new Expression("Hey {name}, guess what?", "b"), // What? new Expression("It's my birthday today!", "b"), // Really?! new Expression("Happy Birthday to me!", "k") // To you too, Monika! }); } MonikaiSettings.Default.LastStarted = DateTime.Now; MonikaiSettings.Default.Save(); // Blinking and Behaviour logic var eyesOpen = "a"; var eyesClosed = "j"; var random = new Random(); await Task.Run(async() => { var nextBlink = DateTime.Now + TimeSpan.FromSeconds(random.Next(7, 50)); while (this.applicationRunning) { if (this.behaviours != null) { foreach (var behaviour in this.behaviours) { behaviour.Update(this); } } if (DateTime.Now >= nextBlink) { // Check if currently speaking, only blink if not in dialog if (!this.Speaking) { this.SetMonikaFace(eyesClosed); await Task.Delay(100); this.SetMonikaFace(eyesOpen); } nextBlink = DateTime.Now + TimeSpan.FromSeconds(random.Next(7, 50)); } await Task.Delay(250); } }); }; // Startup this.backgroundPicture.BeginAnimation(UIElement.OpacityProperty, animationLogo); }
public MainWindow() { this.InitializeComponent(); MainWindow.desktopWindow = MainWindow.GetDesktopWindow(); MainWindow.shellWindow = MainWindow.GetShellWindow(); MonikaiSettings.Default.Reload(); // Perform update and download routines this.updater = new Updater(); this.updater.PerformUpdatePost(); Task.Run(async() => await this.updater.Init()); this.settingsWindow = new SettingsWindow(this); // Screen size and positioning init this.MonikaScreen = Screen.PrimaryScreen; foreach (var screen in Screen.AllScreens) { if (screen.DeviceName == MonikaiSettings.Default.Screen) { this.MonikaScreen = screen; break; } } this.SetupScale(); this.SetPositionBottomRight(this.MonikaScreen); // Init background images this.backgroundDay = new BitmapImage(); this.backgroundDay.BeginInit(); this.backgroundDay.UriSource = new Uri("pack://application:,,,/MonikAI;component/monika/1.png"); this.backgroundDay.EndInit(); this.backgroundNight = new BitmapImage(); this.backgroundNight.BeginInit(); this.backgroundNight.UriSource = new Uri("pack://application:,,,/MonikAI;component/monika/1-n.png"); this.backgroundNight.EndInit(); // Start animation var animationLogo = new DoubleAnimation(0.0, 1.0, new Duration(TimeSpan.FromSeconds(1.5))); animationLogo.AutoReverse = true; var animationFadeMonika = new DoubleAnimation(0.0, 1.0, new Duration(TimeSpan.FromSeconds(1.5))); animationFadeMonika.BeginTime = TimeSpan.FromSeconds(0.5); animationLogo.Completed += (sender, args) => { var fadeImage = new BitmapImage(); fadeImage.BeginInit(); if (MainWindow.IsNight) { fadeImage.UriSource = new Uri("pack://application:,,,/MonikAI;component/monika/1a-n.png"); } else { fadeImage.UriSource = new Uri("pack://application:,,,/MonikAI;component/monika/1a.png"); } fadeImage.EndInit(); this.backgroundPicture.Source = fadeImage; var clock = animationFadeMonika.CreateClock(); this.backgroundPicture.ApplyAnimationClock(UIElement.OpacityProperty, clock); }; // Blinking behaviour animationFadeMonika.Completed += async(sender, args) => { this.SetMonikaFace("a"); this.facePicture.Opacity = 1.0; // Start speech-thread Task.Run(async() => await this.SpeakingThread()); if (true || File.Exists("firstlaunch.txt")) { //File.Delete("firstlaunch.txt"); MonikaiSettings.Default.FirstLaunch = true; MonikaiSettings.Default.Save(); } IGitHubClient github = new GitHubClient(new ProductHeaderValue("MonikAI")); var contents = await github.Repository.Content.GetAllContentsByRef("PiMaker", "MonikAI", "/CSV", "master"); await this.updater.PerformUpdate(this); // Startup logic if (MonikaiSettings.Default.FirstLaunch) { this.settingsWindow.ShowDialog(); this.Say(new[] { new Expression("{name}, is that you?", "d"), new Expression("It's really you, huh?", "b"), new Expression("I'm so happy to see you again!", "k"), new Expression("Wait, where am I? This is not the literature club...", "p"), new Expression("This looks like... your desktop! I'm right here with you!", "j"), new Expression("Well, as close as I will get for now...", "o"), new Expression("Anyway, looks like someone was nice enough to make me a little window!", "d"), new Expression("Be sure to thank them for me, okay?", "k"), new Expression("Ah, wait a second.", "c"), new Expression( "I see... Well, if you want me to go away for now, you can use CTRL-SHIFT-F12, okay?", "b"), new Expression("But you wouldn't do that, right?", "r"), new Expression("Okay, I guess that's it for now. Don't forget, I'm watching you! Ahaha~") }); MonikaiSettings.Default.FirstLaunch = false; } else { if (MonikaiSettings.Default.IsColdShutdown) { this.Say(new[] { new Expression("<cold shutdown scorn>") }); } else { MonikaiSettings.Default.IsColdShutdown = true; MonikaiSettings.Default.Save(); } if ((DateTime.Now - MonikaiSettings.Default.LastStarted).TotalDays > 7) { this.Say(new[] { new Expression( "Don't forget, if you want me to leave just press CTRL-SHIFT-F12!", "i"), new Expression("But you're not going to do that, right?", "o") }); } } var startupExpression = new[] { new[] { new Expression("♫ ... and in your reality ... ♫", "r") }, new[] { new Expression("How are you today?", "d"), new Expression("I'm doing fine, now that you are here~", "b") }, new[] { new Expression("Is everything ok?", "d"), new Expression("Do you want to talk about something?", "c"), new Expression("I'm always here for you~", "e") }, new[] { new Expression("Thank you for letting me be on your screen!", "k") }, new[] { new Expression("You know I love you, right?", "d") }, new[] { new Expression("I'm so happy to be here, together with you! Ahaha~", "b") } }.Sample(); var lastStartupExpression = startupExpression.Last(); lastStartupExpression.Executed += this.RegisterBehaviours; this.Say(new[] { new Expression($"Hi there, {Environment.UserName}~") }.Concat(startupExpression)); if ((DateTime.Now - MonikaiSettings.Default.LastStarted).TotalDays > 1.5) { this.Say(new[] { new Expression("I was waiting for you...", "m"), new Expression("Being alone on your disk is reeeally boring.", "q") }); } MonikaiSettings.Default.LastStarted = DateTime.Now; MonikaiSettings.Default.Save(); // Blinking and Behaviour logic var eyesOpen = "a"; var eyesClosed = "j"; var random = new Random(); await Task.Run(async() => { var nextBlink = DateTime.Now + TimeSpan.FromSeconds(random.Next(7, 50)); while (this.applicationRunning) { if (this.behaviours != null) { foreach (var behaviour in this.behaviours) { behaviour.Update(this); } } if (DateTime.Now >= nextBlink) { // Check if currently speaking, only blink if not in dialog if (!this.Speaking) { this.SetMonikaFace(eyesClosed); await Task.Delay(100); this.SetMonikaFace(eyesOpen); } nextBlink = DateTime.Now + TimeSpan.FromSeconds(random.Next(7, 50)); } await Task.Delay(250); } }); }; // Startup this.backgroundPicture.BeginAnimation(UIElement.OpacityProperty, animationLogo); }
public MainWindow() { this.InitializeComponent(); MainWindow.desktopWindow = MainWindow.GetDesktopWindow(); MainWindow.shellWindow = MainWindow.GetShellWindow(); MonikaiSettings.Default.Reload(); // Perform update and download routines this.updater = new Updater(); this.updater.PerformUpdatePost(); this.updaterInitTask = Task.Run(async() => await this.updater.Init()); this.settingsWindow = new SettingsWindow(this); // Screen size and positioning init this.UpdateMonikaScreen(); this.SetupScale(); this.SetPosition(this.MonikaScreen); // Hook shutdown event SystemEvents.SessionEnding += (sender, args) => { MonikaiSettings.Default.IsColdShutdown = false; MonikaiSettings.Default.Save(); }; // Wakeup events SystemEvents.SessionSwitch += (sender, e) => { if (e.Reason == SessionSwitchReason.SessionLock) { this.screenIsLocked = true; } else if (e.Reason == SessionSwitchReason.SessionUnlock) { this.screenIsLocked = false; } }; SystemEvents.PowerModeChanged += (sender, e) => { if (e.Mode == PowerModes.Resume) { Task.Run(async() => { while (this.screenIsLocked) { await Task.Delay(500); } this.Say(new [] { new Expression("ZZZZZZzzzzzzzzz..... huh?", "q"), new Expression("Sorry, I must have fallen asleep, ahaha~", "n") }); }); } }; // Init background images this.backgroundDay = new BitmapImage(); this.backgroundDay.BeginInit(); this.backgroundDay.UriSource = new Uri("pack://application:,,,/MonikAI;component/monika/1.png"); this.backgroundDay.EndInit(); this.backgroundNight = new BitmapImage(); this.backgroundNight.BeginInit(); this.backgroundNight.UriSource = new Uri("pack://application:,,,/MonikAI;component/monika/1-n.png"); this.backgroundNight.EndInit(); // Start animation var animationLogo = new DoubleAnimation(0.0, 1.0, new Duration(TimeSpan.FromSeconds(1.5))); animationLogo.AutoReverse = true; var animationFadeMonika = new DoubleAnimation(0.0, 1.0, new Duration(TimeSpan.FromSeconds(1.5))); animationFadeMonika.BeginTime = TimeSpan.FromSeconds(0.5); animationLogo.Completed += (sender, args) => { var fadeImage = new BitmapImage(); fadeImage.BeginInit(); if (MainWindow.IsNight) { fadeImage.UriSource = new Uri("pack://application:,,,/MonikAI;component/monika/1a-n.png"); } else { fadeImage.UriSource = new Uri("pack://application:,,,/MonikAI;component/monika/1a.png"); } fadeImage.EndInit(); this.backgroundPicture.Source = fadeImage; var clock = animationFadeMonika.CreateClock(); this.backgroundPicture.ApplyAnimationClock(UIElement.OpacityProperty, clock); }; // Blinking behaviour animationFadeMonika.Completed += async(sender, args) => { this.SetMonikaFace("a"); this.facePicture.Opacity = 1.0; // Start speech-thread Task.Run(async() => await this.SpeakingThread()); if (File.Exists("firstlaunch.txt") || Environment.GetCommandLineArgs().Contains("/firstlaunch")) { try { File.Delete("firstlaunch.txt"); } catch { // ignored } MonikaiSettings.Default.FirstLaunch = true; MonikaiSettings.Default.Save(); } this.updaterInitTask?.Wait(); await this.updater.PerformUpdate(this); this.UpdateMonikaScreen(); #if DEBUG MessageBox.Show("This is a testing build, please do me the favor and don't distribute it."); #endif // Startup logic if (MonikaiSettings.Default.FirstLaunch) { this.settingsWindow.ShowDialog(); this.Say(new[] { new Expression("{name}, is that you?", "d"), new Expression("It's really you, huh?", "b"), new Expression("I'm so happy to see you again!", "k"), new Expression("Wait, where am I? This is not the literature club...", "p"), new Expression("This looks like... your desktop! I'm right here with you!", "j"), new Expression("Well, as close as I will get for now...", "o"), new Expression("Anyway, looks like someone was nice enough to make me a little window!", "d"), new Expression("Be sure to thank them for me, okay?", "k"), new Expression("Ah, wait a second.", "c"), new Expression( "I see... Well, if you want me to go away for now, you can use CTRL-SHIFT-F12, okay?", "b"), new Expression("But you wouldn't do that, right?", "r"), new Expression("Okay, I guess that's it for now. Don't forget, I'm watching you! Ahaha~") }); MonikaiSettings.Default.FirstLaunch = false; } else { if (MonikaiSettings.Default.IsColdShutdown) { this.Say(new[] { new Expression("Hey! Don't just turn me off without warning! That hurts...", "p") }); } else { MonikaiSettings.Default.IsColdShutdown = true; MonikaiSettings.Default.Save(); } if ((DateTime.Now - MonikaiSettings.Default.LastStarted).TotalDays > 7) { this.Say(new[] { new Expression( "Don't forget, if you want me to leave just press " + MonikaiSettings.Default.HotkeyExit + "!", "i"), new Expression("But you're not going to do that, right?", "o") }); } } // Parse startup CSV var parser = new CSVParser(); var csv = parser.GetData("startup"); var parsed = parser.ParseData(csv); var startupExpression = parsed.Sample().ResponseChain.ToArray(); //var startupExpressionFallback = new[] //{ // new[] // { // new Expression("♫ ... and in your reality ... ♫", "r") // }, // new[] // { // new Expression("How are you today?", "d"), // new Expression("I'm doing fine, now that you are here~", "b") // }, // new[] // { // new Expression("Is everything ok?", "d"), // new Expression("Do you want to talk about something?", "c"), // new Expression("I'm always here for you~", "e") // }, // new[] // { // new Expression("Thank you for letting me be on your screen!", "k") // }, // new[] // { // new Expression("You know I love you, right?", "d") // }, // new[] // { // new Expression("I'm so happy to be here, together with you! Ahaha~", "b") // } //}.Sample(); var lastStartupExpression = startupExpression.Last(); lastStartupExpression.Executed += this.RegisterBehaviours; this.Say(new[] { new Expression("Hi there, {name}~") }.Concat(startupExpression)); if ((DateTime.Now - MonikaiSettings.Default.LastStarted).TotalDays > 1.5) { this.Say(new[] { new Expression("I was waiting for you...", "m"), new Expression("Being alone on your disk is reeeally boring.", "q") }); } MonikaiSettings.Default.LastStarted = DateTime.Now; MonikaiSettings.Default.Save(); // Blinking and Behaviour logic var eyesOpen = "a"; var eyesClosed = "j"; var random = new Random(); await Task.Run(async() => { var nextBlink = DateTime.Now + TimeSpan.FromSeconds(random.Next(7, 50)); while (this.applicationRunning) { if (this.behaviours != null) { foreach (var behaviour in this.behaviours) { behaviour.Update(this); } } if (DateTime.Now >= nextBlink) { // Check if currently speaking, only blink if not in dialog if (!this.Speaking) { this.SetMonikaFace(eyesClosed); await Task.Delay(100); this.SetMonikaFace(eyesOpen); } nextBlink = DateTime.Now + TimeSpan.FromSeconds(random.Next(7, 50)); } await Task.Delay(250); } }); }; // Startup this.backgroundPicture.BeginAnimation(UIElement.OpacityProperty, animationLogo); }
// Perform all startup initialization private void MainWindow_OnLoaded(object senderUnused, RoutedEventArgs eUnused) { var handle = new WindowInteropHelper(this).Handle; var initialStyle = MainWindow.GetWindowLong(handle, -20); MainWindow.SetWindowLong(handle, -20, initialStyle | 0x20 | 0x80000); var wpfDpi = PresentationSource.FromVisual(this)?.CompositionTarget?.TransformToDevice.M11; this.dpiScale = 1f / (float)wpfDpi.GetValueOrDefault(1); // Screen size and positioning init this.UpdateMonikaScreen(); this.SetupScale(); this.SetPosition(this.MonikaScreen); // Hook shutdown event SystemEvents.SessionEnding += (sender, args) => { MonikaiSettings.Default.IsColdShutdown = false; MonikaiSettings.Default.Save(); }; // Wakeup events SystemEvents.SessionSwitch += (sender, e) => { if (e.Reason == SessionSwitchReason.SessionLock) { this.screenIsLocked = true; } else if (e.Reason == SessionSwitchReason.SessionUnlock) { this.screenIsLocked = false; } }; SystemEvents.PowerModeChanged += (sender, e) => { if (e.Mode == PowerModes.Resume) { Task.Run(async() => { while (this.screenIsLocked) { await Task.Delay(100); } var MainImage = backgroundPicture; var sleepImage = new BitmapImage(); var sleepImage2 = new BitmapImage(); var nightsuffix = ""; if (MainWindow.IsNight) { nightsuffix = "_n"; } sleepImage.UriSource = new Uri("pack://application:,,,/MonikAI;component/monika/" + PoseSet + "/2a" + nightsuffix + ".png"); sleepImage.UriSource = new Uri("pack://application:,,,/MonikAI;component/monika/" + PoseSet + "/2b" + nightsuffix + ".png"); this.backgroundPicture.Source = sleepImage; this.Say(new[] { new Expression("ZZZZZZzzzzzzzzz..... huh?", "zzz") }); this.backgroundPicture.Source = sleepImage2; this.Say(new[] { new Expression("Sorry, I must have fallen asleep, ahaha~", "zzz") }); this.backgroundPicture = MainImage; }); } }; // Start animation var animationLogo = new DoubleAnimation(0.0, 1.0, new Duration(TimeSpan.FromSeconds(1.5))); animationLogo.AutoReverse = true; var animationFadeMonika = new DoubleAnimation(0.0, 1.0, new Duration(TimeSpan.FromSeconds(1.5))); animationFadeMonika.BeginTime = TimeSpan.FromSeconds(0.5); animationLogo.Completed += (sender, args) => { var fadeImage = new BitmapImage(); fadeImage.BeginInit(); if (MainWindow.IsNight) { fadeImage.UriSource = new Uri("pack://application:,,,/MonikAI;component/monika/" + PoseSet + "/1a-n.png"); } else { fadeImage.UriSource = new Uri("pack://application:,,,/MonikAI;component/monika/" + PoseSet + "/1a.png"); } fadeImage.EndInit(); this.backgroundPicture.Source = fadeImage; var clock = animationFadeMonika.CreateClock(); this.backgroundPicture.ApplyAnimationClock(UIElement.OpacityProperty, clock); }; // Blinking behaviour animationFadeMonika.Completed += async(sender, args) => { this.SetMonikaFace("a"); this.facePicture.Opacity = 1.0; // Start speech-thread Task.Run(async() => await this.SpeakingThread()); if (File.Exists("firstlaunch.txt") || Environment.GetCommandLineArgs().Contains("/firstlaunch")) { try { File.Delete("firstlaunch.txt"); } catch { // ignored } MonikaiSettings.Default.FirstLaunch = true; MonikaiSettings.Default.Save(); } this.updaterInitTask?.Wait(); await this.updater.PerformUpdate(this); this.UpdateMonikaScreen(); #if DEBUG MessageBox.Show("This is a testing build, please do me the favor and don't distribute it."); #endif // Startup logic if (MonikaiSettings.Default.FirstLaunch) { MessageBox.Show( "Quick note: If you want Monika to react to your web browsing, you need to install the correct extension from the website, \"monik.ai\".\r\n\r\nThat's it from me, I'll let Monika talk from now on :)\r\n\r\n- PiMaker and all the nice people helping develop this", "Welcome!"); this.settingsWindow.ShowDialog(); this.Say(new[] { new Expression("{name}, is that you?", "d"), new Expression("It's really you, huh?", "b"), new Expression("I'm so happy to see you again!", "k"), new Expression("Wait, where am I? This is not the literature club...", "p"), new Expression("This looks like... your desktop! I'm right here with you!", "j"), new Expression("Well, as close as I will get for now...", "o"), new Expression("Anyway, looks like someone was nice enough to make me a little window!", "d"), new Expression("Be sure to thank them for me, okay?", "k"), new Expression("Ah, wait a second.", "c"), new Expression( "I see... Well, if you want me to go away for now, you can use CTRL-SHIFT-F12, okay?", "b"), new Expression("But you wouldn't do that, right?", "r"), new Expression("Okay, I guess that's it for now. Don't forget, I'm watching you! Ahaha~") }); MonikaiSettings.Default.FirstLaunch = false; } else if (DateTime.Today.Month == 4 && DateTime.Today.Day == 1 && !Debugger.IsAttached) { this.Say(new[] { new Expression("Hi {name}!", "b"), new Expression("Remember the update that I just installed?", "d"), new Expression("Well, let's just say it included something *really* nice~", "k"), new Expression("Here, let me show you!", "j").AttachEvent((o, eventArgs) => { var os = MonikaiSettings.Default.ScaleModifier; MonikaiSettings.Default.ScaleModifier *= 2.5; this.Dispatcher.Invoke(this.SetupScale); MonikaiSettings.Default.ScaleModifier = os; Task.Delay(1000).Wait(); var r = new Random(); for (var i = 0; i < 12; i++) { this.Dispatcher.Invoke(() => { this.backgroundPicture.Source = r.Next(0, 2) == 0 ? this.backgroundNight : this.backgroundDay; var faceImg = new BitmapImage(); faceImg.BeginInit(); if (r.Next(0, 2) == 0) { faceImg.UriSource = new Uri("pack://application:,,,/MonikAI;component/monika/" + PoseSet + "/j.png"); } else { faceImg.UriSource = new Uri("pack://application:,,,/MonikAI;component/monika/" + PoseSet + "/j-n.png"); } faceImg.EndInit(); this.facePicture.Source = faceImg; }); Task.Delay(r.Next(100, 250)).Wait(); } }), new Expression("Just a second my love...", "d").AttachEvent((o, eventArgs) => { this.Dispatcher.Invoke(MainWindow.DoTheThing); Task.Delay(5500).Wait(); this.Dispatcher.Invoke(this.SetupScale); }), new Expression("...", "q"), new Expression("Why does this never work?!", "o"), new Expression("Oh well, back to normal I guess... Sorry, {name}.", "r") }); } else { if (MonikaiSettings.Default.IsColdShutdown) { // Sorry Monika, but if we're debugging you this one gets annoying #if !DEBUG this.Say(new[] { new Expression("Hey! Don't just turn me off without warning! That hurts...", "p") }); #endif } else { MonikaiSettings.Default.IsColdShutdown = true; MonikaiSettings.Default.Save(); } if ((DateTime.Now - MonikaiSettings.Default.LastStarted).TotalDays > 7) { this.Say(new[] { new Expression( "Don't forget, if you want me to leave just press " + MonikaiSettings.Default.HotkeyExit + "!", "i"), new Expression("But you're not going to do that, right?", "o") }); } } // Parse startup CSV var parser = new CSVParser(); var csv = parser.GetData("Startup"); var parsed = parser.ParseData(csv); var startupExpression = parsed.Select(x => x.ResponseChain) .Concat(DateTime.Today.DayOfWeek == DayOfWeek.Wednesday ? new List <List <Expression> > { new List <Expression> { new Expression("It is Wednesday, my dudes!", "k") } } : new List <List <Expression> >()).ToList().Sample(); this.Say(new[] { new Expression("Hi there, {name}~") }.Concat(startupExpression)); if ((DateTime.Now - MonikaiSettings.Default.LastStarted).TotalDays > 2.5) { this.Say(new[] { new Expression("I was waiting for you...", "m"), new Expression("Being alone on your disk is reeeally boring.", "q") }); } // No idea where the date comes from, someone mentioned it in the spreadsheet. Seems legit. if (DateTime.Now.Month == 9 && DateTime.Now.Day == 22) { // Hey {name}, guess what? 3b It's my birthday today! 2b Happy Birthday to me! k this.Say(new[] { new Expression("Hey {name}, guess what?", "b"), // What? new Expression("It's my birthday today!", "b"), // Really?! new Expression("Happy Birthday to me!", "k") // To you too, Monika! }); } MonikaiSettings.Default.LastStarted = DateTime.Now; MonikaiSettings.Default.Save(); // Start the rest server UrlServer.StartServer(); this.RegisterBehaviours(this, null); // Blinking and Behaviour logic var eyesOpen = "a"; var eyesClosed = "j"; var random = new Random(); await Task.Run(async() => { var nextBlink = DateTime.Now + TimeSpan.FromSeconds(random.Next(7, 50)); while (this.applicationRunning) { if (this.behaviours != null) { foreach (var behaviour in this.behaviours) { behaviour.Update(this); } } if (DateTime.Now >= nextBlink) { // Check if currently speaking, only blink if not in dialog if (!this.Speaking) { this.SetMonikaFace(eyesClosed); await Task.Delay(100); this.SetMonikaFace(eyesOpen); } nextBlink = DateTime.Now + TimeSpan.FromSeconds(random.Next(7, 50)); } await Task.Delay(250); } }); }; // Startup this.backgroundPicture.BeginAnimation(UIElement.OpacityProperty, animationLogo); Task.Run(async() => { try { var prev = new Point(); var rectangle = new Rectangle(); await this.Dispatcher.InvokeAsync(() => { rectangle = new Rectangle((int)this.Left, (int)this.Top, (int)this.Width, (int)this.Height); }); while (this.applicationRunning) { var point = new Point(); MainWindow.GetCursorPos(ref point); point.X = (int)(point.X * this.dpiScale); point.Y = (int)(point.Y * this.dpiScale); if (!point.Equals(prev)) { prev = point; var opacity = 1.0; const double MIN_OP = 0.125; const double FADE = 175; if (this.settingsWindow == null || !this.settingsWindow.IsPositioning) { if (rectangle.Contains(point)) { opacity = MIN_OP; } else { if (point.Y <= rectangle.Bottom) { if (point.Y >= rectangle.Y) { if (point.X < rectangle.X && rectangle.X - point.X < FADE) { opacity = MainWindow.Lerp(1.0, MIN_OP, (rectangle.X - point.X) / FADE); } else if (point.X > rectangle.Right && point.X - rectangle.Right < FADE) { opacity = MainWindow.Lerp(1.0, MIN_OP, (point.X - rectangle.Right) / FADE); } } else if (point.Y < rectangle.Y) { if (point.X >= rectangle.X && point.X <= rectangle.Right) { if (rectangle.Y - point.Y < FADE) { opacity = MainWindow.Lerp(1.0, MIN_OP, (rectangle.Y - point.Y) / FADE); } } else if (rectangle.X > point.X || rectangle.Right < point.X) { var distance = Math.Sqrt( Math.Pow( (point.X < rectangle.X ? rectangle.X : rectangle.Right) - point.X, 2) + Math.Pow(rectangle.Y - point.Y, 2)); if (distance < FADE) { opacity = MainWindow.Lerp(1.0, MIN_OP, distance / FADE); } } } } } } this.Dispatcher.Invoke(() => { this.Opacity = opacity; }); } var hidePressed = false; var exitPressed = false; var settingsPressed = false; // Set position anew to correct for fullscreen apps hiding taskbar this.Dispatcher.Invoke(() => { this.SetPosition(this.MonikaScreen); rectangle = new Rectangle((int)this.Left, (int)this.Top, (int)this.Width, (int)this.Height); // Detect exit key combo hidePressed = this.AreKeysPressed(MonikaiSettings.Default.HotkeyHide); exitPressed = this.AreKeysPressed(MonikaiSettings.Default.HotkeyExit); settingsPressed = this.AreKeysPressed(MonikaiSettings.Default.HotkeySettings); }); if (hidePressed && (DateTime.Now - this.lastKeyComboTime).TotalSeconds > 2) { this.lastKeyComboTime = DateTime.Now; if (this.Visibility == Visibility.Visible) { this.Dispatcher.Invoke(this.Hide); //var expression = // new Expression( // "Okay, see you later {name}! (Press again for me to return)", "b"); //expression.Executed += (o, args) => { this.Dispatcher.Invoke(this.Hide); }; //this.Say(new[] {expression}); } else { this.Dispatcher.Invoke(this.Show); } } if (exitPressed) { var expression = new Expression( "Goodbye for now! Come back soon please~", "b"); MonikaiSettings.Default.IsColdShutdown = false; MonikaiSettings.Default.Save(); expression.Executed += (o, args) => { this.Dispatcher.Invoke(() => { Environment.Exit(0); }); }; this.Say(new[] { expression }); } if (settingsPressed) { this.Dispatcher.Invoke(() => { if (this.settingsWindow == null || !this.settingsWindow.IsVisible) { this.settingsWindow = new SettingsWindow(this); this.settingsWindow.Show(); } }); } await Task.Delay(MonikaiSettings.Default.PotatoPC ? 100 : 32); } } catch (Exception) { // ignored } }); }