using System; using System.Collections.Generic; using System.Drawing; using System.IO; using System.Threading; using System.Windows.Forms; // The 'windowHandle' parameter will contain the window handle for the: // - Active window when run by hotkey // - Trigger target when run by a Trigger rule // - TitleBar Button owner when run by a TitleBar Button // - Jump List owner when run from a Taskbar Jump List // - Currently focused window if none of these match public static class DisplayFusionFunction { ///////////////////////////////////////////////////////////////////////////////////// //Note: Replace the "Path" variable with the file you want to watch, // // and replace the "SearchText" varaible with the text you want to watch for // ///////////////////////////////////////////////////////////////////////////////////// private static readonly string Path = @"C:\Users\UserName\AppData\Roaming\Slack\logs\browser.log"; private static readonly string SearchText = "NEW_NOTIFICATION"; public static void Run(IntPtr windowHandle) { // Create a new FileTailWatcher with the parameters of our choosing using(FileTailWatcher watcher = new FileTailWatcher(Path, SearchText)) { // Assign the event that will get fired when the text is found in the file watcher.OnSearchTextFound += SlackWatcher_OnSearchTextFound; // Run the FileTailWatcher App Application.Run(watcher); } } // This event gets fired when the search text gets found private static void SlackWatcher_OnSearchTextFound() { // Put any code you want here BFS.Dialog.ShowTrayMessage("Hey You! You have a new slack message!!!"); } // This custom class uses a FileSystemWatcher to watch for changes in private class FileTailWatcher : ApplicationContext { // Variables private long LastFileSize = 0; private FileSystemWatcher Watcher; private readonly string Path; private readonly string SearchText; // Delegates and Events public delegate void DelegateVoid(); public event DelegateVoid OnSearchTextFound; // This function sets up the class, and starts watching the end of the file public FileTailWatcher(string path, string searchText) { this.Path = path; this.SearchText = searchText; FileInfo info = new FileInfo(this.Path); this.LastFileSize = info.Length; this.Watcher = new FileSystemWatcher(info.DirectoryName, info.Name); this.Watcher.Changed += this.Watcher_Changed; this.Watcher.EnableRaisingEvents = true; } // Do some cleanup protected override void Dispose(bool disposing) { if(this.Watcher != null) this.Watcher.Dispose(); base.Dispose(disposing); } // This method gets run when the file we're watching changes private void Watcher_Changed(object sender, FileSystemEventArgs e) { // Get the new file size long length = new FileInfo(this.Path).Length; // No point of looking through an empty file // When other apps write to the file, they might also clear it, so don't set LastFileSize if(length == 0) return; // If the file is the same size, ignore the change if (length == this.LastFileSize) return; // Open the file for reading, but allow other programs to read and write from the file using (FileStream file = File.Open(this.Path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) using (StreamReader reader = new StreamReader(file)) { //set the position of the stream to the last file size reader.BaseStream.Position = this.LastFileSize; //read each line until we find the EOF, or what we're looking for while (true) { string line = reader.ReadLine(); if (line == null) break; // The text we're looking for isn't going to be on an empty line if(string.IsNullOrEmpty(line)) continue; //if we havn't found our text on this line, continue to the next one if (line.IndexOf(this.SearchText, StringComparison.OrdinalIgnoreCase) == -1) continue; // If we got this far, we found what we wanted. no need to keep looking through the file. // Fire the event if(this.OnSearchTextFound != null) this.OnSearchTextFound(); break; } } // Set our last position searched this.LastFileSize = length; } } }