private void SoundConfig_Load(object sender, EventArgs e) { _programmaticallyChangingValue = true; cbEnableMaster.Checked = Global.Config.SoundEnabled; cbEnableNormal.Checked = Global.Config.SoundEnabledNormal; cbEnableRWFF.Checked = Global.Config.SoundEnabledRWFF; cbMuteFrameAdvance.Checked = Global.Config.MuteFrameAdvance; if (!OSTailoredCode.IsWindows()) { // Disable DirectSound and XAudio2 on Mono rbOutputMethodDirectSound.Enabled = false; rbOutputMethodXAudio2.Enabled = false; } rbOutputMethodDirectSound.Checked = Global.Config.SoundOutputMethod == Config.ESoundOutputMethod.DirectSound; rbOutputMethodXAudio2.Checked = Global.Config.SoundOutputMethod == Config.ESoundOutputMethod.XAudio2; rbOutputMethodOpenAL.Checked = Global.Config.SoundOutputMethod == Config.ESoundOutputMethod.OpenAL; BufferSizeNumeric.Value = Global.Config.SoundBufferSizeMs; tbNormal.Value = Global.Config.SoundVolume; nudNormal.Value = Global.Config.SoundVolume; tbRWFF.Value = Global.Config.SoundVolumeRWFF; nudRWFF.Value = Global.Config.SoundVolumeRWFF; UpdateSoundDialog(); _programmaticallyChangingValue = false; }
private bool CoolSetCurrentDirectory(string path, string currDirSpeedHack = null) { string target = $"{_currentDirectory}\\"; // first we'll bypass it with a general hack: dont do any setting if the value's already there (even at the OS level, setting the directory can be slow) // yeah I know, not the smoothest move to compare strings here, in case path normalization is happening at some point // but you got any better ideas? if (currDirSpeedHack == null) { currDirSpeedHack = CoolGetCurrentDirectory(); } if (currDirSpeedHack == path) { return(true); } if (OSTailoredCode.IsWindows()) { // WARNING: setting the current directory is SLOW!!! security checks for some reason. // so we're bypassing it with windows hacks fixed(byte *pstr = &System.Text.Encoding.Unicode.GetBytes($"{target}\0")[0]) return(SetCurrentDirectoryW(pstr)); } if (System.IO.Directory.Exists(_currentDirectory)) // race condition for great justice { Environment.CurrentDirectory = _currentDirectory; // that's right, you can't set a directory as current that doesnt exist because .net's got to do SENSELESS SLOW-ASS SECURITY CHECKS on it and it can't do that on a NONEXISTENT DIRECTORY return(true); } return(false); }
private IBufferedSoundProvider _bufferedProvider; // One of the preceding buffers, or null if no source is set public Sound(IntPtr mainWindowHandle) { if (OSTailoredCode.IsWindows()) { if (Global.Config.SoundOutputMethod == Config.ESoundOutputMethod.OpenAL) { _outputDevice = new OpenALSoundOutput(this); } if (Global.Config.SoundOutputMethod == Config.ESoundOutputMethod.DirectSound) { _outputDevice = new DirectSoundSoundOutput(this, mainWindowHandle); } if (Global.Config.SoundOutputMethod == Config.ESoundOutputMethod.XAudio2) { _outputDevice = new XAudio2SoundOutput(this); } } else { _outputDevice = new OpenALSoundOutput(this); // at the moment unix/mono can only support OpenAL (so ignore whatever is set in the config) } if (_outputDevice == null) { _outputDevice = new DummySoundOutput(this); } }
private void PopulateDeviceList() { IEnumerable <string> deviceNames = Enumerable.Empty <string>(); if (OSTailoredCode.IsWindows()) { if (rbOutputMethodDirectSound.Checked) { deviceNames = DirectSoundSoundOutput.GetDeviceNames(); } if (rbOutputMethodXAudio2.Checked) { deviceNames = XAudio2SoundOutput.GetDeviceNames(); } } if (rbOutputMethodOpenAL.Checked) { deviceNames = OpenALSoundOutput.GetDeviceNames(); } listBoxSoundDevices.Items.Clear(); listBoxSoundDevices.Items.Add("<default>"); listBoxSoundDevices.SelectedIndex = 0; foreach (var name in deviceNames) { listBoxSoundDevices.Items.Add(name); if (name == Global.Config.SoundDevice) { listBoxSoundDevices.SelectedItem = name; } } }
/// <summary> /// Takes an absolute path and attempts to convert it to a relative, based on the system, /// or global base if no system is supplied, if it is not a subfolder of the base, it will return the path unaltered /// </summary> public static string TryMakeRelative(string absolutePath, string system = null) { var parentPath = string.IsNullOrWhiteSpace(system) ? GetGlobalBasePathAbsolute() : MakeAbsolutePath(GetPlatformBase(system), system); #if true if (!IsSubfolder(parentPath, absolutePath)) { return(absolutePath); } return(OSTailoredCode.IsWindows() ? absolutePath.Replace(parentPath, ".") : "./" + OSTailoredCode.SimpleSubshell("realpath", $"--relative-to=\"{parentPath}\" \"{absolutePath}\"", $"invalid path {absolutePath} or missing realpath binary")); #else // written for Unix port but may be useful for .NET Core if (!IsSubfolder(parentPath, absolutePath)) { return(OSTailoredCode.CurrentOS == OSTailoredCode.DistinctOS.Windows || parentPath.TrimEnd('.') != $"{absolutePath}/" ? absolutePath : "."); } return(OSTailoredCode.CurrentOS == OSTailoredCode.DistinctOS.Windows ? absolutePath.Replace(parentPath, ".") : absolutePath.Replace(parentPath.TrimEnd('.'), "./")); #endif }
public static void Cleanup() { if (OSTailoredCode.IsWindows()) { KeyInput.Cleanup(); GamePad.Cleanup(); } }
private void tbbOpenFolder_Click(object sender, EventArgs e) { var frmWares = PathManager.MakeAbsolutePath(Global.Config.PathEntries.FirmwaresPathFragment, null); if (!OSTailoredCode.IsWindows() && !Directory.Exists(frmWares)) { Directory.CreateDirectory(frmWares); } System.Diagnostics.Process.Start(frmWares); }
/// <remarks>Algorithm for Windows taken from https://stackoverflow.com/a/485516/7467292</remarks> public static string GetRelativePath(string fromPath, string toPath) { if (OSTailoredCode.IsWindows()) { Win32.FileAttributes fromAttr = GetPathAttribute(fromPath); Win32.FileAttributes toAttr = GetPathAttribute(toPath); var path = new StringBuilder(260); // MAX_PATH if (Win32.PathRelativePathTo( path, fromPath, fromAttr, toPath, toAttr) == false) { throw new ArgumentException("Paths must have a common prefix"); } return(path.ToString()); } #if true return(PathManager.IsSubfolder(toPath, fromPath) ? "./" + OSTailoredCode.SimpleSubshell("realpath", $"--relative-to=\"{toPath}\" \"{fromPath}\"", $"invalid path {fromPath} or missing realpath binary") : fromPath); #else // written for Unix port but may be useful for .NET Core // algorithm taken from https://stackoverflow.com/a/340454/7467292 var dirSepChar = Path.DirectorySeparatorChar; string from = !fromPath.EndsWith(dirSepChar.ToString()) ? fromPath + dirSepChar : fromPath; string to = !toPath.EndsWith(dirSepChar.ToString()) ? toPath + dirSepChar : toPath; Uri fromUri = new Uri(from); Uri toUri = new Uri(to); if (fromUri.Scheme != toUri.Scheme) { return(toPath); } Uri relativeUri = fromUri.MakeRelativeUri(toUri); string relativePath = Uri.UnescapeDataString(relativeUri.ToString()); if (string.Equals(toUri.Scheme, Uri.UriSchemeFile, StringComparison.OrdinalIgnoreCase)) { relativePath = relativePath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar); } return(relativePath.TrimEnd(dirSepChar)); #endif }
private string CoolGetCurrentDirectory() { if (OSTailoredCode.IsWindows()) { // GUESS WHAT! // .NET DOES A SECURITY CHECK ON THE DIRECTORY WE JUST RETRIEVED // AS IF ASKING FOR THE CURRENT DIRECTORY IS EQUIVALENT TO TRYING TO ACCESS IT // SCREW YOU var buf = new byte[32768]; fixed(byte *pBuf = &buf[0]) return(System.Text.Encoding.Unicode.GetString(buf, 0, 2 * (int)GetCurrentDirectoryW(32767, pBuf))); } return(Environment.CurrentDirectory); }
public static void Initialize() { if (OSTailoredCode.IsWindows()) { KeyInput.Initialize(); IPCKeyInput.Initialize(); GamePad.Initialize(); GamePad360.Initialize(); } else { OTK_Keyboard.Initialize(); OTK_GamePad.Initialize(); } Instance = new Input(); }
/// <remarks>Algorithm for Windows taken from https://stackoverflow.com/a/7710620/7467292</remarks> public static bool IsSubfolder(string parentPath, string childPath) { if (OSTailoredCode.IsWindows()) { var parentUri = new Uri(parentPath); for (var childUri = new DirectoryInfo(childPath).Parent; childUri != null; childUri = childUri?.Parent) { if (new Uri(childUri.FullName) == parentUri) { return(true); } } return(false); } #if true return(OSTailoredCode.SimpleSubshell("realpath", $"-L \"{childPath}\"", $"invalid path {childPath} or missing realpath binary") .StartsWith(OSTailoredCode.SimpleSubshell("realpath", $"-L \"{parentPath}\"", $"invalid path {parentPath} or missing realpath binary"))); #else // written for Unix port but may be useful for .NET Core { var parentUri = new Uri(parentPath.TrimEnd('.')); try { for (var childUri = new DirectoryInfo(childPath).Parent; childUri != null; childUri = childUri?.Parent) { if (new Uri(childUri.FullName).AbsolutePath.TrimEnd('/') == parentUri.AbsolutePath.TrimEnd('/')) { return(true); } } } catch { // ignored } return(false); } #endif }
/// <summary> /// starts an ffmpeg process and sets up associated sockets /// </summary> private void OpenFileSegment() { try { _ffmpeg = OSTailoredCode.ConstructSubshell( OSTailoredCode.IsWindows() ? Path.Combine(PathManager.GetDllDirectory(), "ffmpeg.exe") : "ffmpeg", $"-y -f nut -i - {_token.Commandline} \"{_baseName}{(_segment == 0 ? string.Empty : $"_{_segment}")}{_ext}\"", checkStdout: false, checkStderr: true // ffmpeg sends informative display to stderr, and nothing to stdout ); _commandline = $"ffmpeg {_ffmpeg.StartInfo.Arguments}"; _ffmpeg.ErrorDataReceived += new DataReceivedEventHandler(StderrHandler); _stderr = new Queue <string>(Consolebuffer); _ffmpeg.Start(); }
public bool IsAvailable(Type tool) { if (!ServiceInjector.IsAvailable(Global.Emulator.ServiceProvider, tool) || !lazyAsmTypes.Value.Contains(tool.AssemblyQualifiedName) || // not a tool (tool == typeof(LuaConsole) && !OSTailoredCode.IsWindows())) // simply doesn't work (for now) { return(false); } ToolAttribute attr = tool.GetCustomAttributes(false).OfType <ToolAttribute>().SingleOrDefault(); if (attr == null) { return(true); // no ToolAttribute on given type -> assumed all supported } var displayName = Global.Emulator.DisplayName(); var systemId = Global.Emulator.SystemId; return(!attr.UnsupportedCores.Contains(displayName) && // not unsupported (!attr.SupportedSystems.Any() || attr.SupportedSystems.Contains(systemId))); // supported (no supported list -> assumed all supported) }
public void Restart() { var runningScripts = new List <LuaFile>(); if (LuaImp != null) // Things we need to do with the existing LuaImp before we can make a new one { if (LuaImp.IsRebootingCore) { // Even if the lua console is self-rebooting from client.reboot_core() we still want to re-inject dependencies LuaImp.Restart(Emulator.ServiceProvider); return; } if (LuaImp.GuiLibrary != null && LuaImp.GuiLibrary.HasLuaSurface) { LuaImp.GuiLibrary.DrawFinish(); } runningScripts = LuaImp.RunningScripts.ToList(); foreach (var file in runningScripts) { LuaImp.CallExitEvent(file); LuaImp.GetRegisteredFunctions().RemoveAll(lf => lf.Lua == file.Thread); UpdateRegisteredFunctionsDialog(); file.Stop(); } } var currentScripts = LuaImp?.ScriptList; // Temp fix for now LuaImp = OSTailoredCode.IsWindows() ? (PlatformEmuLuaLibrary) new EmuLuaLibrary(Emulator.ServiceProvider) : (PlatformEmuLuaLibrary) new NotReallyLuaLibrary(); if (currentScripts != null) { LuaImp.ScriptList.AddRange(currentScripts); } InputBox.AutoCompleteCustomSource.AddRange(LuaImp.Docs.Select(a => $"{a.Library}.{a.Name}").ToArray()); foreach (var file in runningScripts) { string pathToLoad = ProcessPath(file.Path); try { LuaSandbox.Sandbox(file.Thread, () => { LuaImp.SpawnAndSetFileThread(pathToLoad, file); LuaSandbox.CreateSandbox(file.Thread, Path.GetDirectoryName(pathToLoad)); file.State = LuaFile.RunState.Running; }, () => { file.State = LuaFile.RunState.Disabled; }); } catch (Exception ex) { MessageBox.Show(ex.ToString()); } } UpdateDialog(); }
/// <summary> /// Loads the tool dialog T (T must implement <see cref="IToolForm"/>) , if it does not exist it will be created, if it is already open, it will be focused /// </summary> /// <typeparam name="T">Type of tool you want to load</typeparam> /// <param name="toolPath">Path to the .dll of the external tool</param> /// <param name="focus">Define if the tool form has to get the focus or not (Default is true)</param> /// <returns>An instantiated <see cref="IToolForm"/></returns> public T Load <T>(string toolPath, bool focus = true) where T : class, IToolForm { bool isExternal = typeof(T) == typeof(IExternalToolForm); if (!IsAvailable <T>() && !isExternal) { return(null); } T existingTool; if (isExternal) { existingTool = (T)_tools.FirstOrDefault(t => t is T && t.GetType().Assembly.Location == toolPath); } else { existingTool = (T)_tools.FirstOrDefault(t => t is T); } if (existingTool != null) { if (existingTool.IsDisposed) { _tools.Remove(existingTool); } else { if (focus) { existingTool.Show(); existingTool.Focus(); } return(existingTool); } } IToolForm newTool = CreateInstance <T>(toolPath); if (newTool == null) { return(null); } if (newTool is Form) { (newTool as Form).Owner = GlobalWin.MainForm; } if (isExternal) { ApiInjector.UpdateApis(GlobalWin.ApiProvider, newTool); } ServiceInjector.UpdateServices(Global.Emulator.ServiceProvider, newTool); string toolType = typeof(T).ToString(); // auto settings if (newTool is IToolFormAutoConfig) { ToolDialogSettings settings; if (!Global.Config.CommonToolSettings.TryGetValue(toolType, out settings)) { settings = new ToolDialogSettings(); Global.Config.CommonToolSettings[toolType] = settings; } AttachSettingHooks(newTool as IToolFormAutoConfig, settings); } // custom settings if (HasCustomConfig(newTool)) { if (!Global.Config.CustomToolSettings.TryGetValue(toolType, out var settings)) { settings = new Dictionary <string, object>(); Global.Config.CustomToolSettings[toolType] = settings; } InstallCustomConfig(newTool, settings); } newTool.Restart(); if (!OSTailoredCode.IsWindows() && newTool is RamSearch) { // the mono winforms implementation is buggy, skip to the return statement and call Show in MainForm instead } else { newTool.Show(); } return((T)newTool); }
public DisplayConfigLite() { InitializeComponent(); rbNone.Checked = Global.Config.TargetDisplayFilter == 0; rbHq2x.Checked = Global.Config.TargetDisplayFilter == 1; rbScanlines.Checked = Global.Config.TargetDisplayFilter == 2; rbUser.Checked = Global.Config.TargetDisplayFilter == 3; PathSelection = Global.Config.DispUserFilterPath ?? ""; RefreshState(); rbFinalFilterNone.Checked = Global.Config.DispFinalFilter == 0; rbFinalFilterBilinear.Checked = Global.Config.DispFinalFilter == 1; rbFinalFilterBicubic.Checked = Global.Config.DispFinalFilter == 2; tbScanlineIntensity.Value = Global.Config.TargetScanlineFilterIntensity; checkLetterbox.Checked = Global.Config.DispFixAspectRatio; checkPadInteger.Checked = Global.Config.DispFixScaleInteger; cbFullscreenHacks.Checked = Global.Config.DispFullscreenHacks; cbAutoPrescale.Checked = Global.Config.DispAutoPrescale; cbAlternateVsync.Checked = Global.Config.DispAlternateVsync; if (Global.Config.DispSpeedupFeatures == 2) { rbDisplayFull.Checked = true; } if (Global.Config.DispSpeedupFeatures == 1) { rbDisplayMinimal.Checked = true; } if (Global.Config.DispSpeedupFeatures == 0) { rbDisplayAbsoluteZero.Checked = true; } rbOpenGL.Checked = Global.Config.DispMethod == Config.EDispMethod.OpenGL; rbGDIPlus.Checked = Global.Config.DispMethod == Config.EDispMethod.GdiPlus; rbD3D9.Checked = Global.Config.DispMethod == Config.EDispMethod.SlimDX9; cbStatusBarWindowed.Checked = Global.Config.DispChrome_StatusBarWindowed; cbCaptionWindowed.Checked = Global.Config.DispChrome_CaptionWindowed; cbMenuWindowed.Checked = Global.Config.DispChrome_MenuWindowed; cbStatusBarFullscreen.Checked = Global.Config.DispChrome_StatusBarFullscreen; cbMenuFullscreen.Checked = Global.Config.DispChrome_MenuFullscreen; trackbarFrameSizeWindowed.Value = Global.Config.DispChrome_FrameWindowed; cbFSAutohideMouse.Checked = Global.Config.DispChrome_Fullscreen_AutohideMouse; SyncTrackbar(); cbAllowDoubleclickFullscreen.Checked = Global.Config.DispChrome_AllowDoubleClickFullscreen; nudPrescale.Value = Global.Config.DispPrescale; // null emulator config hack { NullEmulator.NullEmulatorSettings s; if (Global.Emulator is NullEmulator) { s = (Global.Emulator as dynamic).GetSettings(); } else { s = (NullEmulator.NullEmulatorSettings)Global.Config.GetCoreSettings <NullEmulator>(); } checkSnowyNullEmulator.Checked = s.SnowyDisplay; } if (Global.Config.DispManagerAR == Config.EDispManagerAR.None) { rbUseRaw.Checked = true; } else if (Global.Config.DispManagerAR == Config.EDispManagerAR.System) { rbUseSystem.Checked = true; } else if (Global.Config.DispManagerAR == Config.EDispManagerAR.Custom) { rbUseCustom.Checked = true; } else if (Global.Config.DispManagerAR == Config.EDispManagerAR.CustomRatio) { rbUseCustomRatio.Checked = true; } if (Global.Config.DispCustomUserARWidth != -1) { txtCustomARWidth.Text = Global.Config.DispCustomUserARWidth.ToString(); } if (Global.Config.DispCustomUserARHeight != -1) { txtCustomARHeight.Text = Global.Config.DispCustomUserARHeight.ToString(); } if (Global.Config.DispCustomUserARX != -1) { txtCustomARX.Text = Global.Config.DispCustomUserARX.ToString(); } if (Global.Config.DispCustomUserARY != -1) { txtCustomARY.Text = Global.Config.DispCustomUserARY.ToString(); } txtCropLeft.Text = Global.Config.DispCropLeft.ToString(); txtCropTop.Text = Global.Config.DispCropTop.ToString(); txtCropRight.Text = Global.Config.DispCropRight.ToString(); txtCropBottom.Text = Global.Config.DispCropBottom.ToString(); RefreshAspectRatioOptions(); if (!OSTailoredCode.IsWindows()) { // Disable SlimDX on Unix rbD3D9.Enabled = false; rbD3D9.AutoCheck = false; cbAlternateVsync.Enabled = false; label13.Enabled = false; label8.Enabled = false; } }
void UpdateThreadProc() { while (true) { var keyEvents = OSTailoredCode.IsWindows() ? KeyInput.Update().Concat(IPCKeyInput.Update()) : OTK_Keyboard.Update(); if (OSTailoredCode.IsWindows()) { GamePad.UpdateAll(); GamePad360.UpdateAll(); } else { OTK_GamePad.UpdateAll(); } //this block is going to massively modify data structures that the binding method uses, so we have to lock it all lock (this) { _NewEvents.Clear(); //analyze keys foreach (var ke in keyEvents) { HandleButton(ke.Key.ToString(), ke.Pressed, InputFocus.Keyboard); } lock (FloatValues) { //FloatValues.Clear(); // analyse OpenTK xinput (or is it libinput?) foreach (var pad in OTK_GamePad.EnumerateDevices()) { foreach (var but in pad.buttonObjects) { HandleButton(pad.InputNamePrefix + but.ButtonName, but.ButtonAction(), InputFocus.Pad); } foreach (var sv in pad.GetFloats()) { var n = $"{pad.InputNamePrefix}{sv.Item1} Axis"; var f = sv.Item2; if (trackdeltas) { FloatDeltas[n] += Math.Abs(f - FloatValues[n]); } FloatValues[n] = f; } } //analyze xinput foreach (var pad in GamePad360.EnumerateDevices()) { string xname = $"X{pad.PlayerNumber} "; for (int b = 0; b < pad.NumButtons; b++) { HandleButton(xname + pad.ButtonName(b), pad.Pressed(b), InputFocus.Pad); } foreach (var sv in pad.GetFloats()) { string n = xname + sv.Item1; float f = sv.Item2; if (trackdeltas) { FloatDeltas[n] += Math.Abs(f - FloatValues[n]); } FloatValues[n] = f; } } //analyze joysticks foreach (var pad in GamePad.EnumerateDevices()) { string jname = $"J{pad.PlayerNumber} "; for (int b = 0; b < pad.NumButtons; b++) { HandleButton(jname + pad.ButtonName(b), pad.Pressed(b), InputFocus.Pad); } foreach (var sv in pad.GetFloats()) { string n = jname + sv.Item1; float f = sv.Item2; //if (n == "J5 RotationZ") // System.Diagnostics.Debugger.Break(); if (trackdeltas) { FloatDeltas[n] += Math.Abs(f - FloatValues[n]); } FloatValues[n] = f; } } // analyse moose // other sorts of mouse api (raw input) could easily be added as a separate listing under a different class if (WantingMouseFocus.Contains(System.Windows.Forms.Form.ActiveForm)) { var P = System.Windows.Forms.Control.MousePosition; if (trackdeltas) { // these are relative to screen coordinates, but that's not terribly important FloatDeltas["WMouse X"] += Math.Abs(P.X - FloatValues["WMouse X"]) * 50; FloatDeltas["WMouse Y"] += Math.Abs(P.Y - FloatValues["WMouse Y"]) * 50; } // coordinate translation happens later FloatValues["WMouse X"] = P.X; FloatValues["WMouse Y"] = P.Y; var B = System.Windows.Forms.Control.MouseButtons; HandleButton("WMouse L", (B & System.Windows.Forms.MouseButtons.Left) != 0, InputFocus.Mouse); HandleButton("WMouse C", (B & System.Windows.Forms.MouseButtons.Middle) != 0, InputFocus.Mouse); HandleButton("WMouse R", (B & System.Windows.Forms.MouseButtons.Right) != 0, InputFocus.Mouse); HandleButton("WMouse 1", (B & System.Windows.Forms.MouseButtons.XButton1) != 0, InputFocus.Mouse); HandleButton("WMouse 2", (B & System.Windows.Forms.MouseButtons.XButton2) != 0, InputFocus.Mouse); } else { //dont do this: for now, it will interfere with the virtualpad. dont do something similar for the mouse position either //unpress all buttons //HandleButton("WMouse L", false); //HandleButton("WMouse C", false); //HandleButton("WMouse R", false); //HandleButton("WMouse 1", false); //HandleButton("WMouse 2", false); } } if (_NewEvents.Count != 0) { //WHAT!? WE SHOULD NOT BE SO NAIVELY TOUCHING MAINFORM FROM THE INPUTTHREAD. ITS BUSY RUNNING. AllowInput allowInput = GlobalWin.MainForm.AllowInput(false); foreach (var ie in _NewEvents) { //events are swallowed in some cases: if (ie.LogicalButton.Alt && ShouldSwallow(GlobalWin.MainForm.AllowInput(true), ie)) { continue; } if (ie.EventType == InputEventType.Press && ShouldSwallow(allowInput, ie)) { continue; } EnqueueEvent(ie); } } IgnoreEventsNextPoll = false; } //lock(this) //arbitrary selection of polling frequency: Thread.Sleep(10); } }