public static async Task SetDeckName(Deck deck, ExportingInfo info)
		{
			if(Config.Instance.ExportSetDeckName && !deck.TagList.ToLower().Contains("brawl"))
			{
				var name = deck.Name;
				if(Config.Instance.ExportAddDeckVersionToName)
					name += " " + deck.SelectedVersion.ShortVersionString;

				Logger.WriteLine("Setting deck name...", "DeckExporter");
				var nameDeckPos = new Point((int)Helper.GetScaledXPos(Config.Instance.ExportNameDeckX, info.HsRect.Width, info.Ratio),
				                            (int)(Config.Instance.ExportNameDeckY * info.HsRect.Height));
				await MouseActions.ClickOnPoint(info.HsHandle, nameDeckPos);
				//send enter and second click to make sure the current name gets selected
				SendKeys.SendWait("{ENTER}");
				await MouseActions.ClickOnPoint(info.HsHandle, nameDeckPos);
				if(Config.Instance.ExportPasteClipboard)
				{
					Clipboard.SetText(name);
					SendKeys.SendWait("^v");
				}
				else
					SendKeys.SendWait(name);
				SendKeys.SendWait("{ENTER}");
			}
		}
		{
			_info = info;
			_onUnexpectedMousePos = onUnexpectedMousePos;
		}

		private Point _previousCursorPos = Point.Empty;
		public async Task ClickOnPoint(Point clientPoint)
		{
			if(!User32.IsHearthstoneInForeground() || (_onUnexpectedMousePos != null && _previousCursorPos != Point.Empty &&
				(Math.Abs(_previousCursorPos.X - Cursor.Position.X) > 10 || Math.Abs(_previousCursorPos.Y - Cursor.Position.Y) > 10)))
			{
				if(!(_onUnexpectedMousePos == null || await _onUnexpectedMousePos()))
					throw new ExportingInterruptedException("Export interrupted, not continuing");
				if((_info = await ExportingHelper.EnsureHearthstoneInForeground(_info)) == null)
					throw new ExportingInterruptedException("Export interrupted - could not re-focus hearthstone");
				await Task.Delay(500);
			}

			User32.ClientToScreen(_info.HsHandle, ref clientPoint);
			Cursor.Position = _previousCursorPos = new Point(clientPoint.X, clientPoint.Y);
			Log.Debug("Clicking " + Cursor.Position);

			//mouse down
			if(SystemInformation.MouseButtonsSwapped)
				User32.mouse_event((uint)User32.MouseEventFlags.RightDown, 0, 0, 0, UIntPtr.Zero);
			else
				User32.mouse_event((uint)User32.MouseEventFlags.LeftDown, 0, 0, 0, UIntPtr.Zero);

			await Task.Delay(Config.Instance.DeckExportDelay);

			//mouse up
			if(SystemInformation.MouseButtonsSwapped)
        public static async Task SetDeckName(Deck deck, ExportingInfo info)
        {
            if (Config.Instance.ExportSetDeckName && !deck.TagList.ToLower().Contains("brawl"))
            {
                var name = deck.Name;
                if (Config.Instance.ExportAddDeckVersionToName)
                {
                    name += " " + deck.SelectedVersion.ShortVersionString;
                }

                Logger.WriteLine("Setting deck name...", "DeckExporter");
                var nameDeckPos = new Point((int)Helper.GetScaledXPos(Config.Instance.ExportNameDeckX, info.HsRect.Width, info.Ratio),
                                            (int)(Config.Instance.ExportNameDeckY * info.HsRect.Height));
                await MouseActions.ClickOnPoint(info.HsHandle, nameDeckPos);

                //send enter and second click to make sure the current name gets selected
                SendKeys.SendWait("{ENTER}");
                await MouseActions.ClickOnPoint(info.HsHandle, nameDeckPos);

                if (Config.Instance.ExportPasteClipboard)
                {
                    Clipboard.SetText(name);
                    SendKeys.SendWait("^v");
                }
                else
                {
                    SendKeys.SendWait(name);
                }
                SendKeys.SendWait("{ENTER}");
            }
        }
		public static async Task SetDeckName(Deck deck, ExportingInfo info)
		{
			if(Config.Instance.ExportSetDeckName && !deck.TagList.ToLower().Contains("brawl"))
			{
				var name = Regex.Replace(deck.Name, @"[\(\)\{\}]", "");
				if(name != deck.Name)
					Logger.WriteLine("Removed parenthesis/braces from deck name. New name: " + name, "DeckExporter");
				if(Config.Instance.ExportAddDeckVersionToName)
				{
					var version = " " + deck.SelectedVersion.ShortVersionString;
					if(name.Length + version.Length > MaxLengthDeckName)
						name = name.Substring(0, MaxLengthDeckName - version.Length);
					name += version;
				}

				Logger.WriteLine("Setting deck name...", "DeckExporter");
				var nameDeckPos = new Point((int)Helper.GetScaledXPos(Config.Instance.ExportNameDeckX, info.HsRect.Width, info.Ratio),
				                            (int)(Config.Instance.ExportNameDeckY * info.HsRect.Height));
				await ClickOnPoint(info.HsHandle, nameDeckPos);
				//send enter and second click to make sure the current name gets selected
				SendKeys.SendWait("{ENTER}");
				await ClickOnPoint(info.HsHandle, nameDeckPos);
				if(Config.Instance.ExportPasteClipboard)
				{
					Clipboard.SetText(name);
					SendKeys.SendWait("^v");
				}
				else
					SendKeys.SendWait(name);
				SendKeys.SendWait("{ENTER}");
			}
		}
        /// <summary>
        /// Returns true if Hearthstone lost focus in the process
        /// </summary>
        public static async Task <bool> CreateDeck(Deck deck, ExportingInfo info)
        {
            Log.Info("Creating deck...");
            deck.MissingCards.Clear();
            foreach (var card in deck.Cards.ToSortedCardList())
            {
                var missingCardsCount = await AddCardToDeck(card, info);

                if (missingCardsCount < 0)
                {
                    return(true);
                }
                if (missingCardsCount > 0)
                {
                    var missingCard = (Card)card.Clone();
                    missingCard.Count = missingCardsCount;
                    deck.MissingCards.Add(missingCard);
                }
            }
            Log.Info(deck.MissingCards.Count + " missing cards");
            if (deck.MissingCards.Any())
            {
                DeckList.Save();
            }
            return(false);
        }
 public static async Task ClearFilters(ExportingInfo info)
 {
     if (!Config.Instance.EnableExportAutoFilter)
     {
         return;
     }
     await ClearManaFilter(info);
     await ClearSetsFilter(info);
 }
		public static async Task<bool> Export(Deck deck)
		{
			if(deck == null)
				return false;
			var currentClipboard = "";
			var altScreenCapture = Config.Instance.AlternativeScreenCapture;
			try
			{
				Log.Info("Exporting " + deck.GetDeckInfo());
				if(Config.Instance.ExportPasteClipboard && Clipboard.ContainsText())
					currentClipboard = Clipboard.GetText();

				var info = new ExportingInfo();
				LogDebugInfo(info);

				var inForeground = await ExportingHelper.EnsureHearthstoneInForeground(info.HsHandle);
				if(!inForeground)
					return false;
				Log.Info($"Waiting for {Config.Instance.ExportStartDelay} seconds before starting the export process");
				await Task.Delay(Config.Instance.ExportStartDelay * 1000);
				if(!altScreenCapture)
					Core.Overlay.ForceHide(true);

				await ClearDeck(info);
				await SetDeckName(deck, info);
				await ClearFilters(info);
				var lostFocus = await CreateDeck(deck, info);
				if(lostFocus)
					return false;
				await ClearSearchBox(info.HsHandle, info.SearchBoxPos);

				if(Config.Instance.ExportPasteClipboard)
					Clipboard.Clear();
				Log.Info("Success exporting deck.");
				return true;
			}
			catch(Exception e)
			{
				Log.Error("Error exporting deck: " + e);
				return false;
			}
			finally
			{
				if(!altScreenCapture)
					Core.Overlay.ForceHide(false);
				try
				{
					if(Config.Instance.ExportPasteClipboard && currentClipboard != "")
						Clipboard.SetText(currentClipboard);
				}
				catch(Exception ex)
				{
					Log.Error("Could not restore clipboard content after export: " + ex);
				}
			}
		}
Exemple #8
0
 private static void LogDebugInfo(ExportingInfo info)
 {
     Logger.WriteLine(
         string.Format(
             "HsHandle={0} HsRect={1} Ratio={2} SearchBoxPosX={3} SearchBoxPosY={4} CardPosX={5} Card2PosX={6} CardPosY={7} ExportPasteClipboard={8} ExportNameDeckX={9} ExportNameDeckY={10} PrioritizeGolden={11} DeckExportDelay={12} EnableExportAutoFilter={13} ExportZeroButtonX={14} ExportZeroButtonY={15}",
             info.HsHandle, info.HsRect, info.Ratio, Config.Instance.ExportSearchBoxX,
             Config.Instance.ExportSearchBoxY, Config.Instance.ExportCard1X, Config.Instance.ExportCard2X,
             Config.Instance.ExportCardsY, Config.Instance.ExportPasteClipboard, Config.Instance.ExportNameDeckX,
             Config.Instance.ExportNameDeckY, Config.Instance.PrioritizeGolden, Config.Instance.DeckExportDelay,
             Config.Instance.EnableExportAutoFilter, Config.Instance.ExportZeroButtonX,
             Config.Instance.ExportZeroButtonY), "DeckExporter");
 }
		private static void LogDebugInfo(ExportingInfo info)
		{
			Logger.WriteLine(
			                 string.Format(
			                               "HsHandle={0} HsRect={1} Ratio={2} SearchBoxPosX={3} SearchBoxPosY={4} CardPosX={5} Card2PosX={6} CardPosY={7} ExportPasteClipboard={8} ExportNameDeckX={9} ExportNameDeckY={10} PrioritizeGolden={11} DeckExportDelay={12} EnableExportAutoFilter={13} ExportZeroButtonX={14} ExportZeroButtonY={15}",
			                               info.HsHandle, info.HsRect, info.Ratio, Config.Instance.ExportSearchBoxX,
			                               Config.Instance.ExportSearchBoxY, Config.Instance.ExportCard1X, Config.Instance.ExportCard2X,
			                               Config.Instance.ExportCardsY, Config.Instance.ExportPasteClipboard, Config.Instance.ExportNameDeckX,
			                               Config.Instance.ExportNameDeckY, Config.Instance.PrioritizeGolden, Config.Instance.DeckExportDelay,
			                               Config.Instance.EnableExportAutoFilter, Config.Instance.ExportZeroButtonX,
			                               Config.Instance.ExportZeroButtonY), "DeckExporter");
		}
		public static async Task<bool> Export(Deck deck, Func<Task<bool>> onInterrupt)
		{
			if(deck == null)
				return false;
			var currentClipboard = "";
			try
			{
				Log.Info("Exporting " + deck.GetDeckInfo());
				if(Config.Instance.ExportPasteClipboard && Clipboard.ContainsText())
					currentClipboard = Clipboard.GetText();
				var info = new ExportingInfo();
				LogDebugInfo(info);
				info = await ExportingHelper.EnsureHearthstoneInForeground(info);
				if(info == null)
					return false;
				LogDebugInfo(info);
				Log.Info($"Waiting for {Config.Instance.ExportStartDelay} seconds before starting the export process");
				await Task.Delay(Config.Instance.ExportStartDelay*1000);
				var exporter = new ExportingActions(info, deck, onInterrupt);
				await exporter.ClearDeck();
				await exporter.SetDeckName();
				await exporter.ClearFilters();
				await exporter.CreateDeck();
				await exporter.ClearSearchBox();
				if(Config.Instance.ExportPasteClipboard)
					Clipboard.Clear();
				Log.Info("Success exporting deck.");
				return true;
			}
			catch(ExportingInterruptedException e)
			{
				Log.Warn(e.Message);
				return false;
			}
			catch(Exception e)
			{
				Log.Error("Error exporting deck: " + e);
				return false;
			}
			finally
			{
				try
				{
					if(Config.Instance.ExportPasteClipboard && currentClipboard != "")
						Clipboard.SetText(currentClipboard);
				}
				catch(Exception ex)
				{
					Log.Error("Could not restore clipboard content after export: " + ex);
				}
			}
		}
Exemple #11
0
 public ExportingActions(ExportingInfo info, Deck deck, Func <Task <bool> > onInterrupt)
 {
     _info                 = info;
     _deck                 = deck;
     _mouse                = new MouseActions(info, onInterrupt);
     _clearCardPoint       = new Point(GetScaledXPos(Config.Instance.ExportClearX), GetYPos(Config.Instance.ExportClearY));
     _deckNamePoint        = new Point(GetScaledXPos(Config.Instance.ExportNameDeckX), GetYPos(Config.Instance.ExportNameDeckY));
     _card1Point           = new Point((int)_info.CardPosX + CardPosOffset, (int)_info.CardPosY + CardPosOffset);
     _card2Point           = new Point((int)_info.Card2PosX + CardPosOffset, (int)_info.CardPosY + CardPosOffset);
     _zeroManaCrystalPoint = new Point(GetScaledXPos(Config.Instance.ExportZeroButtonX), GetYPos(Config.Instance.ExportZeroButtonY));
     _setFilterMenuPoint   = new Point(GetScaledXPos(Config.Instance.ExportSetsButtonX), GetYPos(Config.Instance.ExportSetsButtonY));
     _setFilterAllPoint    = new Point(GetScaledXPos(Config.Instance.ExportAllSetsButtonX), GetYPos(Config.Instance.ExportStandardSetButtonY));
 }
		public static async Task ClearDeck(ExportingInfo info)
		{
			if(!Config.Instance.AutoClearDeck)
				return;
			var count = 0;
			Logger.WriteLine("Clearing deck...", "DeckExporter");
			while(!IsDeckEmpty(info.HsHandle, info.HsRect.Width, info.HsRect.Height, info.Ratio))
			{
				await
					ClickOnPoint(info.HsHandle,
					                          new Point((int)Helper.GetScaledXPos(Config.Instance.ExportClearX, info.HsRect.Width, info.Ratio),
					                                    (int)(Config.Instance.ExportClearY * info.HsRect.Height)));
				if(count++ > 35)
					break;
			}
		}
        public static async Task <ExportingInfo> EnsureHearthstoneInForeground(ExportingInfo info)
        {
            if (User32.IsHearthstoneInForeground())
            {
                return(info);
            }
            User32.ShowWindow(info.HsHandle, User32.GetHearthstoneWindowState() == WindowState.Minimized ? User32.SwRestore : User32.SwShow);
            User32.SetForegroundWindow(info.HsHandle);
            await Task.Delay(500);

            if (User32.IsHearthstoneInForeground())
            {
                return(new ExportingInfo());
            }
            Core.MainWindow.ShowMessage("Exporting error", "Can't find Hearthstone window.").Forget();
            Log.Error("Can't find Hearthstone window.");
            return(null);
        }
		public static async Task Export(Deck deck)
		{
			if(deck == null)
				return;
			var currentClipboard = "";
			try
			{
				Logger.WriteLine("Exporting " + deck.GetDeckInfo(), "DeckExporter");
				if(Config.Instance.ExportPasteClipboard && Clipboard.ContainsText())
					currentClipboard = Clipboard.GetText();

				var info = new ExportingInfo();
				LogDebugInfo(info);

				var inForeground = await ExportingHelper.EnsureHearthstoneInForeground(info.HsHandle);
				if(!inForeground)
					return;
				Logger.WriteLine($"Waiting for {Config.Instance.ExportStartDelay} seconds before starting the export process", "DeckExporter");
				await Task.Delay(Config.Instance.ExportStartDelay * 1000);
				Core.Overlay.ForceHide(true);

				await ClearDeck(info);
				await SetDeckName(deck, info);
				await ClearFilters(info);
				var lostFocus = await CreateDeck(deck, info);
				if(lostFocus)
					return;
				await ClearSearchBox(info.HsHandle, info.SearchBoxPos);

				if(Config.Instance.ExportPasteClipboard)
					Clipboard.Clear();
				Logger.WriteLine("Success exporting deck.", "DeckExporter");
			}
			catch(Exception e)
			{
				Logger.WriteLine("Error exporting deck: " + e, "DeckExporter");
			}
			finally
			{
				Core.Overlay.ForceHide(false);
				if(Config.Instance.ExportPasteClipboard && currentClipboard != "")
					Clipboard.SetText(currentClipboard);
			}
		}
        public static async Task ClearSetsFilter(ExportingInfo info)
        {
            Logger.WriteLine("Clearing set filter...", "DeckExporter");
            // Then ensure "All Sets" is selected
            var setsPoint = new Point((int)Helper.GetScaledXPos(Config.Instance.ExportSetsButtonX, info.HsRect.Width, info.Ratio),
                                      (int)(Config.Instance.ExportSetsButtonY * info.HsRect.Height));

            // open sets menu
            await MouseActions.ClickOnPoint(info.HsHandle, setsPoint);

            // select "All Sets"
            await
            MouseActions.ClickOnPoint(info.HsHandle,
                                      new Point((int)Helper.GetScaledXPos(Config.Instance.ExportAllSetsButtonX, info.HsRect.Width, info.Ratio),
                                                (int)(Config.Instance.ExportAllSetsButtonY *info.HsRect.Height)));

            // close sets menu
            await MouseActions.ClickOnPoint(info.HsHandle, setsPoint);
        }
        public static async Task ClearManaFilter(ExportingInfo info)
        {
            Log.Info("Clearing \"Zero\" crystal...");

            // First, ensure mana filters are cleared
            var crystalPoint = new Point((int)Helper.GetScaledXPos(Config.Instance.ExportZeroButtonX, info.HsRect.Width, info.Ratio),
                                         (int)(Config.Instance.ExportZeroButtonY * info.HsRect.Height));

            if (await IsZeroCrystalSelected(info.HsHandle, info.Ratio, info.HsRect.Width, info.HsRect.Height))
            {
                // deselect it
                await ClickOnPoint(info.HsHandle, crystalPoint);
            }
            else
            {
                // select it and then unselect it (in case other crystals are on)
                await ClickOnPoint(info.HsHandle, crystalPoint);
                await ClickOnPoint(info.HsHandle, crystalPoint);
            }
        }
        public static async Task SetDeckName(Deck deck, ExportingInfo info)
        {
            if (Config.Instance.ExportSetDeckName && !deck.TagList.ToLower().Contains("brawl"))
            {
                var name = Regex.Replace(deck.Name, @"[\(\)\{\}]", "");
                if (name != deck.Name)
                {
                    Log.Info("Removed parenthesis/braces from deck name. New name: " + name);
                }
                if (Config.Instance.ExportAddDeckVersionToName)
                {
                    var version = " " + deck.SelectedVersion.ShortVersionString;
                    if (name.Length + version.Length > MaxLengthDeckName)
                    {
                        name = name.Substring(0, MaxLengthDeckName - version.Length);
                    }
                    name += version;
                }

                Log.Info("Setting deck name...");
                var nameDeckPos = new Point((int)Helper.GetScaledXPos(Config.Instance.ExportNameDeckX, info.HsRect.Width, info.Ratio),
                                            (int)(Config.Instance.ExportNameDeckY * info.HsRect.Height));
                await ClickOnPoint(info.HsHandle, nameDeckPos);

                //send enter and second click to make sure the current name gets selected
                SendKeys.SendWait("{ENTER}");
                await ClickOnPoint(info.HsHandle, nameDeckPos);

                if (Config.Instance.ExportPasteClipboard)
                {
                    Clipboard.SetText(name);
                    SendKeys.SendWait("^v");
                }
                else
                {
                    SendKeys.SendWait(name);
                }
                SendKeys.SendWait("{ENTER}");
            }
        }
        public static async Task ClearDeck(ExportingInfo info)
        {
            if (!Config.Instance.AutoClearDeck)
            {
                return;
            }
            var count = 0;

            Log.Info("Clearing deck...");
            while (!await IsDeckEmpty(info.HsHandle, info.HsRect.Width, info.HsRect.Height, info.Ratio))
            {
                await
                ClickOnPoint(info.HsHandle,
                             new Point((int)Helper.GetScaledXPos(Config.Instance.ExportClearX, info.HsRect.Width, info.Ratio),
                                       (int)(Config.Instance.ExportClearY *info.HsRect.Height)));

                if (count++ > 35)
                {
                    break;
                }
            }
        }
Exemple #19
0
        public static async Task ClearSetsFilter(ExportingInfo info)
        {
            Log.Info("Clearing set filter...");
            // Then ensure "All Sets" is selected
            var setsPoint = new Point((int)Helper.GetScaledXPos(Config.Instance.ExportSetsButtonX, info.HsRect.Width, info.Ratio),
                                      (int)(Config.Instance.ExportSetsButtonY * info.HsRect.Height));

            // open sets menu
            await ClickOnPoint(info.HsHandle, setsPoint);

            await Task.Delay(100);

            // select "All Sets"
            await
            ClickOnPoint(info.HsHandle,
                         new Point(
                             (int)Helper.GetScaledXPos(Config.Instance.ExportAllSetsButtonX, info.HsRect.Width, info.Ratio),
                             (int)(Config.Instance.ExportStandardSetButtonY *info.HsRect.Height)));

            await Task.Delay(100);

            // close sets menu
            await ClickOnPoint(info.HsHandle, setsPoint);
        }
        public static async Task <bool> Export(Deck deck, Func <Task <bool> > onInterrupt)
        {
            if (deck == null)
            {
                return(false);
            }
            var currentClipboard = "";

            try
            {
                Log.Info("Exporting " + deck.GetDeckInfo());
                if (Config.Instance.ExportPasteClipboard && Clipboard.ContainsText())
                {
                    currentClipboard = Clipboard.GetText();
                }
                var info = new ExportingInfo();
                LogDebugInfo(info);
                info = await ExportingHelper.EnsureHearthstoneInForeground(info);

                if (info == null)
                {
                    return(false);
                }
                LogDebugInfo(info);
                Log.Info($"Waiting for {Config.Instance.ExportStartDelay} seconds before starting the export process");
                await Task.Delay(Config.Instance.ExportStartDelay *1000);

                var exporter = new ExportingActions(info, deck, onInterrupt);
                await exporter.ClearDeck();

                await exporter.SetDeckName();

                await exporter.ClearFilters();

                await exporter.CreateDeck();

                await exporter.ClearSearchBox();

                if (Config.Instance.ExportPasteClipboard)
                {
                    Clipboard.Clear();
                }
                Log.Info("Success exporting deck.");
                return(true);
            }
            catch (ExportingInterruptedException e)
            {
                Log.Warn(e.Message);
                return(false);
            }
            catch (Exception e)
            {
                Log.Error("Error exporting deck: " + e);
                return(false);
            }
            finally
            {
                try
                {
                    if (Config.Instance.ExportPasteClipboard && currentClipboard != "")
                    {
                        Clipboard.SetText(currentClipboard);
                    }
                }
                catch (Exception ex)
                {
                    Log.Error("Could not restore clipboard content after export: " + ex);
                }
            }
        }
 private static void LogDebugInfo(ExportingInfo info) => Log.Debug($"HsHandle={info.HsHandle} HsRect={info.HsRect} Ratio={info.Ratio} SearchBoxPosX={Config.Instance.ExportSearchBoxX} SearchBoxPosY={Config.Instance.ExportSearchBoxY} CardPosX={Config.Instance.ExportCard1X} Card2PosX={Config.Instance.ExportCard2X} CardPosY={Config.Instance.ExportCardsY} ExportPasteClipboard={Config.Instance.ExportPasteClipboard} ExportNameDeckX={Config.Instance.ExportNameDeckX} ExportNameDeckY={Config.Instance.ExportNameDeckY} PrioritizeGolden={Config.Instance.PrioritizeGolden} DeckExportDelay={Config.Instance.DeckExportDelay} EnableExportAutoFilter={Config.Instance.EnableExportAutoFilter} ExportZeroButtonX={Config.Instance.ExportZeroButtonX} ExportZeroButtonY={Config.Instance.ExportZeroButtonY} ForceClear={Config.Instance.ExportForceClear}");
        public static async Task <bool> Export(Deck deck)
        {
            if (deck == null)
            {
                return(false);
            }
            var currentClipboard = "";
            var altScreenCapture = Config.Instance.AlternativeScreenCapture;

            try
            {
                Log.Info("Exporting " + deck.GetDeckInfo());
                if (Config.Instance.ExportPasteClipboard && Clipboard.ContainsText())
                {
                    currentClipboard = Clipboard.GetText();
                }

                var info = new ExportingInfo();
                LogDebugInfo(info);

                var inForeground = await ExportingHelper.EnsureHearthstoneInForeground(info.HsHandle);

                if (!inForeground)
                {
                    return(false);
                }
                Log.Info($"Waiting for {Config.Instance.ExportStartDelay} seconds before starting the export process");
                await Task.Delay(Config.Instance.ExportStartDelay * 1000);

                if (!altScreenCapture)
                {
                    Core.Overlay.ForceHide(true);
                }

                await ClearDeck(info);
                await SetDeckName(deck, info);
                await ClearFilters(info);

                var lostFocus = await CreateDeck(deck, info);

                if (lostFocus)
                {
                    return(false);
                }
                await ClearSearchBox(info.HsHandle, info.SearchBoxPos);

                if (Config.Instance.ExportPasteClipboard)
                {
                    Clipboard.Clear();
                }
                Log.Info("Success exporting deck.");
                return(true);
            }
            catch (Exception e)
            {
                Log.Error("Error exporting deck: " + e);
                return(false);
            }
            finally
            {
                if (!altScreenCapture)
                {
                    Core.Overlay.ForceHide(false);
                }
                if (Config.Instance.ExportPasteClipboard && currentClipboard != "")
                {
                    Clipboard.SetText(currentClipboard);
                }
            }
        }
		///<summary>
		/// Returns -1 if Hearthstone loses focus
		/// </summary>
		public static async Task<int> AddCardToDeck(Card card, ExportingInfo info)
		{
			if(!User32.IsHearthstoneInForeground())
			{
				Core.MainWindow.ShowMessage("Exporting aborted", "Hearthstone window lost focus.").Forget();
				Logger.WriteLine("Exporting aborted, window lost focus", "DeckExporter");
				return -1;
			}

			if(Config.Instance.ExportForceClear)
				await ClearSearchBox(info.HsHandle, info.SearchBoxPos);

			await ClickOnPoint(info.HsHandle, info.SearchBoxPos);

			if(Config.Instance.ExportPasteClipboard)
			{
				Clipboard.SetText(GetSearchString(card));
				SendKeys.SendWait("^v");
			}
			else
				SendKeys.SendWait(GetSearchString(card));
			SendKeys.SendWait("{ENTER}");

			Logger.WriteLine("try to export card: " + card, "DeckExporter");
			await Task.Delay(Config.Instance.DeckExportDelay * 2);

			if(await CheckForSpecialCases(card, info.CardPosX + 50, info.Card2PosX + 50, info.CardPosY + 50, info.HsHandle))
				return 0;

			//Check if Card exist in collection
			if(CardExists(info.HsHandle, (int)info.CardPosX, (int)info.CardPosY, info.HsRect.Width, info.HsRect.Height))
			{
				//Check if a golden exist
				if(Config.Instance.PrioritizeGolden
				   && CardExists(info.HsHandle, (int)info.Card2PosX, (int)info.CardPosY, info.HsRect.Width, info.HsRect.Height))
				{
					await ClickOnPoint(info.HsHandle, new Point((int)info.Card2PosX + 50, (int)info.CardPosY + 50));

					if(card.Count == 2)
					{
						await ClickOnPoint(info.HsHandle, new Point((int)info.Card2PosX + 50, (int)info.CardPosY + 50));
						await ClickOnPoint(info.HsHandle, new Point((int)info.CardPosX + 50, (int)info.CardPosY + 50));
					}
				}
				else
				{
					await ClickOnPoint(info.HsHandle, new Point((int)info.CardPosX + 50, (int)info.CardPosY + 50));

					if(card.Count == 2)
					{
						//Check if two card are not available 
						await Task.Delay(200 - Config.Instance.DeckExportDelay);
						if(CardHasLock(info.HsHandle, (int)(info.CardPosX + info.HsRect.Width * 0.048),
						                               (int)(info.CardPosY + info.HsRect.Height * 0.287), info.HsRect.Width, info.HsRect.Height))
						{
							if(CardExists(info.HsHandle, (int)info.Card2PosX, (int)info.CardPosY, info.HsRect.Width, info.HsRect.Height))
							{
								await ClickOnPoint(info.HsHandle, new Point((int)info.Card2PosX + 50, (int)info.CardPosY + 50));
								return 0;
							}
							Logger.WriteLine("Only one copy found: " + card.Name, "DeckExporter");
							return 1;
						}

						await ClickOnPoint(info.HsHandle, new Point((int)info.CardPosX + 50, (int)info.CardPosY + 50));
					}
				}
			}
			else
				return card.Count;
			return 0;
		}
		public static async Task ClearSetsFilter(ExportingInfo info)
		{
			Logger.WriteLine("Clearing set filter...", "DeckExporter");
			// Then ensure "All Sets" is selected
			var setsPoint = new Point((int)Helper.GetScaledXPos(Config.Instance.ExportSetsButtonX, info.HsRect.Width, info.Ratio),
			                          (int)(Config.Instance.ExportSetsButtonY * info.HsRect.Height));

			// open sets menu
			await ClickOnPoint(info.HsHandle, setsPoint);
			// select "All Sets"
			await
				ClickOnPoint(info.HsHandle,
				                          new Point(
					                          (int)Helper.GetScaledXPos(Config.Instance.ExportAllSetsButtonX, info.HsRect.Width, info.Ratio),
					                          (int)(Config.Instance.ExportAllSetsButtonY * info.HsRect.Height)));
			// close sets menu
			await ClickOnPoint(info.HsHandle, setsPoint);
		}
	{
		private ExportingInfo _info;
		private readonly Func<Task<bool>> _onUnexpectedMousePos;
		public static async Task ClearManaFilter(ExportingInfo info)
		{
			Logger.WriteLine("Clearing \"Zero\" crystal...", "DeckExporter");

			// First, ensure mana filters are cleared
			var crystalPoint = new Point((int)Helper.GetScaledXPos(Config.Instance.ExportZeroButtonX, info.HsRect.Width, info.Ratio),
			                             (int)(Config.Instance.ExportZeroButtonY * info.HsRect.Height));

			if(IsZeroCrystalSelected(info.HsHandle, info.Ratio, info.HsRect.Width, info.HsRect.Height))
			{
				// deselect it
				await ClickOnPoint(info.HsHandle, crystalPoint);
			}
			else
			{
				// select it and then unselect it (in case other crystals are on)
				await ClickOnPoint(info.HsHandle, crystalPoint);
				await ClickOnPoint(info.HsHandle, crystalPoint);
			}
		}
		public static async Task ClearFilters(ExportingInfo info)
		{
			if(!Config.Instance.EnableExportAutoFilter)
				return;
			await ClearManaFilter(info);
			await ClearSetsFilter(info);
		}
		/// <summary>
		/// Returns true if Hearthstone lost focus in the process
		/// </summary>
		public static async Task<bool> CreateDeck(Deck deck, ExportingInfo info)
		{
			Logger.WriteLine("Creating deck...", "DeckExporter");
			deck.MissingCards.Clear();
			foreach(var card in deck.Cards.ToSortedCardList())
			{
				var missingCardsCount = await AddCardToDeck(card, info);
				if(missingCardsCount < 0)
					return true;
				if(missingCardsCount > 0)
				{
					var missingCard = (Card)card.Clone();
					missingCard.Count = missingCardsCount;
					deck.MissingCards.Add(missingCard);
				}
			}
			Logger.WriteLine(deck.MissingCards.Count + " missing cards", "DeckExporter");
			if(deck.MissingCards.Any())
				DeckList.Save();
			return false;
		}
        ///<summary>
        /// Returns -1 if Hearthstone loses focus
        /// </summary>
        public static async Task <int> AddCardToDeck(Card card, ExportingInfo info)
        {
            if (!User32.IsHearthstoneInForeground())
            {
                Core.MainWindow.ShowMessage("Exporting aborted", "Hearthstone window lost focus.").Forget();
                Log.Info("Exporting aborted, window lost focus");
                return(-1);
            }

            if (Config.Instance.ExportForceClear)
            {
                await ClearSearchBox(info.HsHandle, info.SearchBoxPos);
            }

            await ClickOnPoint(info.HsHandle, info.SearchBoxPos);

            if (Config.Instance.ExportPasteClipboard)
            {
                Clipboard.SetText(GetSearchString(card));
                SendKeys.SendWait("^v");
            }
            else
            {
                SendKeys.SendWait(GetSearchString(card));
            }
            SendKeys.SendWait("{ENTER}");

            Log.Info("try to export card: " + card);
            await Task.Delay(Config.Instance.DeckExportDelay * 2);

            if (await CheckForSpecialCases(card, info.CardPosX + 50, info.Card2PosX + 50, info.CardPosY + 50, info.HsHandle))
            {
                return(0);
            }

            //Check if Card exist in collection
            var cardExists = await CardExists(info.HsHandle, (int)info.CardPosX, (int)info.CardPosY, info.HsRect.Width, info.HsRect.Height);

            if (cardExists)
            {
                //Check if a golden exist
                if (Config.Instance.PrioritizeGolden &&
                    await CardExists(info.HsHandle, (int)info.Card2PosX, (int)info.CardPosY, info.HsRect.Width, info.HsRect.Height))
                {
                    await ClickOnPoint(info.HsHandle, new Point((int)info.Card2PosX + 50, (int)info.CardPosY + 50));

                    if (card.Count == 2)
                    {
                        await ClickOnPoint(info.HsHandle, new Point((int)info.Card2PosX + 50, (int)info.CardPosY + 50));
                        await ClickOnPoint(info.HsHandle, new Point((int)info.CardPosX + 50, (int)info.CardPosY + 50));
                    }
                }
                else
                {
                    await ClickOnPoint(info.HsHandle, new Point((int)info.CardPosX + 50, (int)info.CardPosY + 50));

                    if (card.Count == 2)
                    {
                        //Check if two card are not available
                        await Task.Delay(200 - Config.Instance.DeckExportDelay);

                        if (await CardHasLock(info.HsHandle, (int)(info.CardPosX + info.HsRect.Width * 0.048),
                                              (int)(info.CardPosY + info.HsRect.Height * 0.287), info.HsRect.Width, info.HsRect.Height))
                        {
                            var card2Exists = await CardExists(info.HsHandle, (int)info.Card2PosX, (int)info.CardPosY, info.HsRect.Width, info.HsRect.Height);

                            if (card2Exists)
                            {
                                await ClickOnPoint(info.HsHandle, new Point((int)info.Card2PosX + 50, (int)info.CardPosY + 50));

                                return(0);
                            }
                            Log.Info("Only one copy found: " + card.Name);
                            return(1);
                        }

                        await ClickOnPoint(info.HsHandle, new Point((int)info.CardPosX + 50, (int)info.CardPosY + 50));
                    }
                }
            }
            else
            {
                return(card.Count);
            }
            return(0);
        }
        public static async Task Export(Deck deck)
        {
            if (deck == null)
            {
                return;
            }
            var currentClipboard = "";

            try
            {
                Logger.WriteLine("Exporting " + deck.GetDeckInfo(), "DeckExporter");
                if (Config.Instance.ExportPasteClipboard && Clipboard.ContainsText())
                {
                    currentClipboard = Clipboard.GetText();
                }

                var info = new ExportingInfo();
                LogDebugInfo(info);

                var inForeground = await ExportingHelper.EnsureHearthstoneInForeground(info.HsHandle);

                if (!inForeground)
                {
                    return;
                }
                Logger.WriteLine("Waiting for " + Config.Instance.ExportStartDelay + " seconds before starting the export process", "DeckExporter");
                await Task.Delay(Config.Instance.ExportStartDelay * 1000);

                Core.Overlay.ForceHide(true);

                await ExportingActions.ClearDeck(info);

                await ExportingActions.SetDeckName(deck, info);

                await ExportingActions.ClearFilters(info);

                var lostFocus = await ExportingActions.CreateDeck(deck, info);

                if (lostFocus)
                {
                    return;
                }
                await ExportingActions.ClearSearchBox(info.HsHandle, info.SearchBoxPos);

                if (Config.Instance.ExportPasteClipboard)
                {
                    Clipboard.Clear();
                }
                Logger.WriteLine("Success exporting deck.", "DeckExporter");
            }
            catch (Exception e)
            {
                Logger.WriteLine("Error exporting deck: " + e, "DeckExporter");
            }
            finally
            {
                Core.Overlay.ForceHide(false);
                if (Config.Instance.ExportPasteClipboard && currentClipboard != "")
                {
                    Clipboard.SetText(currentClipboard);
                }
            }
        }
		private static void LogDebugInfo(ExportingInfo info)
		{
			Logger.WriteLine(
							 $"HsHandle={info.HsHandle} HsRect={info.HsRect} Ratio={info.Ratio} SearchBoxPosX={Config.Instance.ExportSearchBoxX} SearchBoxPosY={Config.Instance.ExportSearchBoxY} CardPosX={Config.Instance.ExportCard1X} Card2PosX={Config.Instance.ExportCard2X} CardPosY={Config.Instance.ExportCardsY} ExportPasteClipboard={Config.Instance.ExportPasteClipboard} ExportNameDeckX={Config.Instance.ExportNameDeckX} ExportNameDeckY={Config.Instance.ExportNameDeckY} PrioritizeGolden={Config.Instance.PrioritizeGolden} DeckExportDelay={Config.Instance.DeckExportDelay} EnableExportAutoFilter={Config.Instance.EnableExportAutoFilter} ExportZeroButtonX={Config.Instance.ExportZeroButtonX} ExportZeroButtonY={Config.Instance.ExportZeroButtonY} ForceClear={Config.Instance.ExportForceClear}",
							 "DeckExporter");
		}
		public static async Task<ExportingInfo> EnsureHearthstoneInForeground(ExportingInfo info)
		{
			if(User32.IsHearthstoneInForeground())
				return info;
			User32.ShowWindow(info.HsHandle, User32.GetHearthstoneWindowState() == WindowState.Minimized ? User32.SwRestore : User32.SwShow);
			User32.SetForegroundWindow(info.HsHandle);
			await Task.Delay(500);
			if(User32.IsHearthstoneInForeground())
				return new ExportingInfo();
			Core.MainWindow.ShowMessage("Exporting error", "Can't find Hearthstone window.").Forget();
			Log.Error("Can't find Hearthstone window.");
			return null;
		}