Is it possible to determine the pressed letter key depending on the layout?
Here is code (class):
class GlobalKeyboardHookEventArgs : HandledEventArgs
{
public GlobalKeyboardHook.KeyboardState KeyboardState { get; private set; }
public GlobalKeyboardHook.LowLevelKeyboardInputEvent KeyboardData { get; private set; }
public GlobalKeyboardHookEventArgs(
GlobalKeyboardHook.LowLevelKeyboardInputEvent keyboardData,
GlobalKeyboardHook.KeyboardState keyboardState)
{
KeyboardData = keyboardData;
KeyboardState = keyboardState;
}
}
//Based on https://gist.github.com/Stasonix
class GlobalKeyboardHook : IDisposable
{
public event EventHandler<GlobalKeyboardHookEventArgs> KeyboardPressed;
public GlobalKeyboardHook()
{
_windowsHookHandle = IntPtr.Zero;
_user32LibraryHandle = IntPtr.Zero;
_hookProc = LowLevelKeyboardProc; // we must keep alive _hookProc, because GC is not aware about SetWindowsHookEx behaviour.
_user32LibraryHandle = LoadLibrary("User32");
if (_user32LibraryHandle == IntPtr.Zero)
{
int errorCode = Marshal.GetLastWin32Error();
throw new Win32Exception(errorCode, $"Failed to load library 'User32.dll'. Error {errorCode}: {new Win32Exception(Marshal.GetLastWin32Error()).Message}.");
}
.............
and call:
private void OnKeyPressed(object sender, GlobalKeyboardHookEventArgs e)
{
KeysConverter kc = new KeysConverter();
if (e.KeyboardState == GlobalKeyboardHook.KeyboardState.KeyDown)
{
GrabbedKeys += kc.ConvertToString(e.KeyboardData.VirtualCode);
return;
}
if (e.KeyboardData.VirtualCode != GlobalKeyboardHook.VkSnapshot)
return;
}
Its work fine, if I press on keyboard 's' my programm stored 's', but how I can make same for russian keyboard layout? If keyboard layout is ru-RU, I press 's' and my app stored 'ы'?
Related
I'm having this problem using Unity's Advertisment. Specifically after watching the video and clicking the X button to close the video, I should give the prize to the player (go to the next level). The problem is that the OnUnityAdsDidFinish function calls if (showResult == ShowResult.Finished) multiple times. What am I doing wrong? how do I call the FindObjectOfType () .LoadNextLevel () function once; ? Thank you in advance
public class UnityAdsInterstitial : MonoBehaviour, IUnityAdsListener
{
private string gameID = "******";
//nome scelto nella DashBoard di Unity
private string interstitialID = "interstitial";
private string myPlacementId = "rewardedVideo";
public int randomHighValue = 30;
private bool TestMode = true;
private bool adsClosed = false;
public Button _button;
private void Awake()
{
_button = GetComponent<Button>();
}
void Start()
{
Debug.Log("Ads start");
_button = GameObject.Find("StartAds").GetComponent<Button>();
_button.interactable = Advertisement.IsReady(myPlacementId);
if (_button) _button.onClick.AddListener(ShowRewardedVideo);
Advertisement.Initialize(gameID, TestMode);
Advertisement.AddListener(this);
if (adsClosed)
{
adsClosed = false;
}
}
public void ShowInterstitial()
{
if (Advertisement.IsReady(interstitialID) )
{
Advertisement.Show(interstitialID);
}
}
public void ShowRewardedVideo()
{
if (Advertisement.IsReady(myPlacementId))
{
Debug.Log("Rewarded video is Ready");
Advertisement.Show(myPlacementId);
}
else
{
Debug.Log("Rewarded video is not ready at the moment! Please try again later!");
}
}
public void HideBanner()
{
Advertisement.Banner.Hide();
}
public void OnUnityAdsReady(string placementdID)
{
if (placementdID == interstitialID)
{
Debug.Log("InterstitialIsReady");
}
if (placementdID == myPlacementId)
{
Debug.Log("RewardedIsReady");
_button.interactable = true;
}
}
public void OnUnityAdsDidFinish(string placementdID, ShowResult showResult)
{
if (showResult == ShowResult.Finished)
{
// Reward the user for watching the ad to completion.
if (!adsClosed)
{
adsClosed = true;
FindObjectOfType<LevelLoader>().LoadNextLevel();
}
}
else if (showResult == ShowResult.Skipped)
{
// Do not reward the user for skipping the ad.
}
else if (showResult == ShowResult.Failed)
{
Debug.LogWarning("The ad did not finish due to an error.");
}
}
public void OnUnityAdsDidError(string message)
{
Debug.Log("OnUnityAdsDidError");
}
public void OnUnityAdsDidStart(string message)
{
Debug.Log("OnUnityAdsDidStart");
}
I would start my investigation by checking the placement id (in case there are more placements)
Checking that the callback is for the proper placement id
if (showResult == ShowResult.Finished && placementId == myPlacementId)
{
// Reward the user for watching the ad to completion.
if (!adsClosed)
{
adsClosed = true;
FindObjectOfType<LevelLoader>().LoadNextLevel();
}
}
The second would be that I only have one active instance of UnityAdsInterstitial. You can check this in debug mode by the reference of the object. If more than one instance starts from somewhere else in your code, then you should just limit to one.
I'm working on a small extension for autocad using its .net api.
I'm trying to filter keys using IMessageFilter. And it "sort of" works.
the problem is, its "leaking" first 2 keys I press through... and after that it starts working.
I'm not sure where the bug is occurring (tried posting this at autodesk forum to no avail).
as for the "ps2" , its an instance of autocads "paletteset" object which houses UserControls to fit into acad graphic interface.
I'd appreciate any idea as to why the only first 2 keys get leaked, or methods as to why this is occurring.
here's my code:
[CommandMethod("TestCheck")]
public void MyTab()
{
filter = new MyMessageFilter(ps1, ps2);
filter.OnNumber+=filter_OnNumber;
...
}
private bool keyboardFilterEnabled = false;
public bool KeyboardFilterEnabled
{
get { return keyboardFilterEnabled; }
set
{
keyboardFilterEnabled = value;
if (keyboardFilterEnabled == true)
System.Windows.Forms.Application.AddMessageFilter(filter);
else
System.Windows.Forms.Application.RemoveMessageFilter(filter);
}
}
}
public delegate void NotifyParentDelegate(Keys source);
public class MyMessageFilter : IMessageFilter
{
public MyMessageFilter(PaletteSet p1, PaletteSet p2)
: base()
{
PaletteSet ps1 = p1;
PaletteSet ps2 = p2;
}
public event NotifyParentDelegate OnNumber;
public event NotifyParentDelegate OnLetter;
public event NotifyParentDelegate OnControl;
public const int WM_KEYDOWN = 0x0100;
public bool PreFilterMessage(ref Message m)
{
if (m.Msg == WM_KEYDOWN)
{
// Check for the Escape keypress
Keys kc = (Keys)(int)m.WParam & Keys.KeyCode;
if (m.Msg == WM_KEYDOWN && kc == Keys.Escape)
{
return false;
}
if (m.Msg == WM_KEYDOWN && char.IsDigit((char)kc) == true)
{
OnNumber(kc);
return false;
}
return true;
}
return false;
}
}
public void filter_OnNumber(Keys source)
{
ps2.Focus();
if (ps2.KeepFocus != true)
{ps2.KeepFocus=true; }
formDimensions.input_dimension.Focus();
//SendKeys.Send(source.ToString());
}
I have an application written in C# which plays little .wav files. It uses the SoundPlayer class in the System.Media namepace to play the sounds, using a thread that calls the SoundPlayer.PlaySync method to play the .wav file. It's all wrapped up in a class that looks like this:
public class SoundController {
private object soundLocker = new object();
protected Thread SoundThread { get; set; }
protected string NextSound { get; set; }
protected AutoResetEvent PlayASoundPlag { get; set; }
protected Dictionary<string, SoundPlayer> Sounds { get; set; }
protected bool Stopping { get; set; }
public string SoundPlaying { get; private set; }
public SoundController() {
PendingCount = 0;
PlayASoundFlag = new AutoResetEvent( false );
Sounds = new Dictionary<string, SoundPlayer>();
soundLocker = new object();
Stopping = false;
SoundThread = new Thread( new ThreadStart( SoundPlayer ) ) { Name = "SoundThread", IsBackground = true };
SoundThread.Start();
}
private void SoundPlayer() {
do {
PlayASoundFlag.WaitOne();
bool soundWasPlayed = false;
while ( !Stopping && NextSound != null ) {
lock ( soundLocker ) {
SoundPlaying = NextSound;
NextSound = null;
}
Sounds[ SoundPlaying ].PlaySync();
lock ( soundLocker ) {
SoundPlaying = null;
soundWasPlayed = true;
}
}
} while ( !Stopping );
}
public bool HasSound( string key ) {
return Sounds.ContainsKey( key );
}
public void PlayAlarmSound( string key, bool stopCurrentSound ) {
if ( !Sounds.ContainsKey( key ) )
throw new ArgumentException( "Sound unknown", "key" );
lock ( soundLocker ) {
NextSound = key;
if ( SoundPlaying != null && stopCurrentSound )
Sounds[ SoundPlaying ].Stop();
PlayASoundFlag.Set();
}
}
}
When my program calls the PlaySound method, and a sound is currently playing, the Stop method is called, but the sound that's playing doesn't actually stop. I've placed trace points on the call to Stop and a line I added after it just so I could see when the call was made and when it returned, while listening with headphones. It's obvious that the sound plays all the way through to the end.
How do I get the sounds to stop playing reliably?
Unfortunately this is a messy process, but this works:
class Program
{
static void Main(string[] args)
{
SoundPlayerEx player = new SoundPlayerEx(#"c:\temp\sorry_dave.wav");
player.SoundFinished += player_SoundFinished;
Console.WriteLine("Press any key to play the sound");
Console.ReadKey(true);
player.PlayAsync();
Console.WriteLine("Press a key to stop the sound.");
Console.ReadKey(true);
player.Stop();
Console.WriteLine("Press any key to continue");
}
static void player_SoundFinished(object sender, EventArgs e)
{
Console.WriteLine("The sound finished playing");
}
}
public static class SoundInfo
{
[DllImport("winmm.dll")]
private static extern uint mciSendString(
string command,
StringBuilder returnValue,
int returnLength,
IntPtr winHandle);
public static int GetSoundLength(string fileName)
{
StringBuilder lengthBuf = new StringBuilder(32);
mciSendString(string.Format("open \"{0}\" type waveaudio alias wave", fileName), null, 0, IntPtr.Zero);
mciSendString("status wave length", lengthBuf, lengthBuf.Capacity, IntPtr.Zero);
mciSendString("close wave", null, 0, IntPtr.Zero);
int length = 0;
int.TryParse(lengthBuf.ToString(), out length);
return length;
}
}
public class SoundPlayerEx : SoundPlayer
{
public bool Finished { get; private set; }
private Task _playTask;
private CancellationTokenSource _tokenSource = new CancellationTokenSource();
private CancellationToken _ct;
private string _fileName;
private bool _playingAsync = false;
public event EventHandler SoundFinished;
public SoundPlayerEx(string soundLocation)
: base(soundLocation)
{
_fileName = soundLocation;
_ct = _tokenSource.Token;
}
public void PlayAsync()
{
Finished = false;
_playingAsync = true;
Task.Run(() =>
{
try
{
double lenMs = SoundInfo.GetSoundLength(_fileName);
DateTime stopAt = DateTime.Now.AddMilliseconds(lenMs);
this.Play();
while (DateTime.Now < stopAt)
{
_ct.ThrowIfCancellationRequested();
//The delay helps reduce processor usage while "spinning"
Task.Delay(10).Wait();
}
}
catch (OperationCanceledException)
{
base.Stop();
}
finally
{
OnSoundFinished();
}
}, _ct);
}
public new void Stop()
{
if (_playingAsync)
_tokenSource.Cancel();
else
base.Stop(); //To stop the SoundPlayer Wave file
}
protected virtual void OnSoundFinished()
{
Finished = true;
_playingAsync = false;
EventHandler handler = SoundFinished;
if (handler != null)
handler(this, EventArgs.Empty);
}
}
So why doesn't it work "normally"? Its a well known problem. The SoundPlayer is a "fire and forget" piece of code, and if you don't cancel it on the same thread that you started it on, it will not do anything. A lot of people complain about it and as I'm sure you've seen there are very few solutions out side of using raw wave_out calls or moving to DirectX (or with WPF, using the MediaPlayer control).
This SoundPlayerEx class has a couple properties that let you know when the sound is finished or to cancel playing a sound that you started asynchronously. There is no need to create a new thread to work on, making it a lot easier to use.
Feel free to expand on the code, it was a quick and dirty solution to your problem. The two classes you need are the SoundInfo class and the SoundPlayerEx class, the rest of the code above is a demo (replace the wav file with one of your own).
Note this is not a universal solution as it relies on the winmm.dll, so this will not port over to Mono (not sure if Mono has a SoundPlayer class or not). Also since its a dirty solution, you won't get the Finished event or property if you don't use the PlayAsync call.
I trying to allow people to write to NFC tags using my app, so that my app gets launched with a custom parameter. I want to be able to reprogram NFC tags which already have data on them.
I am using the following code but the problem is, that WP always recognizes the action which is already on the NFC tag and interrupts because it wants to launch the NFC tag action which was written anytime before.
How can I tell the OS to stop triggering the action of the tag so that I can immediately rewrite it?
public enum NfcHelperState
{
Initializing,
Waiting,
Ready,
Writing,
Finished,
Error,
NoDeviceFound
}
public class NfcHelper
{
private NfcHelperState _state = NfcHelperState.Initializing;
public NfcHelperState State
{
get { return _state; }
}
private ProximityDevice _nfcDevice;
private long _subscriptionId;
public NfcHelper()
{
Init();
}
public void Init()
{
UpdateState();
_nfcDevice = ProximityDevice.GetDefault();
if (_nfcDevice == null)
{
UpdateState(NfcHelperState.NoDeviceFound);
return;
}
UpdateState(NfcHelperState.Waiting);
}
private void UpdateState(NfcHelperState? state = null)
{
if (state.HasValue)
{
_state = state.Value;
}
if (OnStatusMessageChanged != null)
{
OnStatusMessageChanged(this, _state);
}
}
public void WriteToTag()
{
UpdateState(NfcHelperState.Ready);
_subscriptionId = _nfcDevice.SubscribeForMessage("WriteableTag", WriteableTagDetected);
}
private void WriteableTagDetected(ProximityDevice sender, ProximityMessage message)
{
UpdateState(NfcHelperState.Writing);
try
{
var str = "action=my_custom_action";
str += "\tWindowsPhone\t";
str += CurrentApp.AppId;
_nfcDevice.PublishBinaryMessage("LaunchApp:WriteTag", GetBufferFromString(str),
WriteToTagComplete);
}
catch (Exception e)
{
UpdateState(NfcHelperState.Error);
StopWaitingForTag();
}
}
private void WriteToTagComplete(ProximityDevice sender, long messageId)
{
sender.StopPublishingMessage(messageId);
UpdateState(NfcHelperState.Finished);
StopWaitingForTag();
}
private void StopWaitingForTag()
{
_nfcDevice.StopSubscribingForMessage(_subscriptionId);
}
private static IBuffer GetBufferFromString(string str)
{
using (var dw = new DataWriter())
{
dw.UnicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.Utf16LE;
dw.WriteString(str);
return dw.DetachBuffer();
}
}
public delegate void NfcStatusMessageChangedHandler(object myObject, NfcHelperState newState);
public event NfcStatusMessageChangedHandler OnStatusMessageChanged;
}
WriteToTag is called when a button in my app is tapped and the app waits for a writable tag. If a writable tag is recognized, WriteableTagDetected gets called and immediately starts the writing process. However, this is interrupted by the WP dialog which asks whether to perform the NFC action or not. After writing, WriteToTagComplete should be called, where StopWaitingForTag gets called and ends the write process.
I hope you guys can help me :)
Turns out I thought the wrong way. I didn't need to wait for a tag to arrive in order to rewrite it. In fact, there's no need to do _nfcDevice.SubscribeForMessage("WriteableTag", WriteableTagDetected); before writing. Just start using PublishBinaryMessage and it will write to the tag once it arrives at the device.
My final code looks like the following:
public enum NfcHelperState
{
Initializing,
Ready,
WaitingForWriting,
FinishedWriting,
ErrorWriting,
NoDeviceFound
}
public class NfcHelper
{
private NfcHelperState _state = NfcHelperState.Initializing;
public NfcHelperState State
{
get { return _state; }
}
private ProximityDevice _nfcDevice;
private long? _writingMessageId;
public NfcHelper()
{
Init();
}
public void Init()
{
UpdateState();
_nfcDevice = ProximityDevice.GetDefault();
if (_nfcDevice == null)
{
UpdateState(NfcHelperState.NoDeviceFound);
return;
}
UpdateState(NfcHelperState.Ready);
}
private void UpdateState(NfcHelperState? state = null)
{
if (state.HasValue)
{
_state = state.Value;
}
if (OnStatusMessageChanged != null)
{
OnStatusMessageChanged(this, _state);
}
}
public void WriteToTag()
{
StopWritingMessage();
UpdateState(NfcHelperState.WaitingForWriting);
try
{
var str = new StringBuilder();
str.Append("action=my_custom_action");
str.Append("\tWindowsPhone\t{");
str.Append(CurrentApp.AppId);
str.Append("}");
_writingMessageId = _nfcDevice.PublishBinaryMessage("LaunchApp:WriteTag", GetBufferFromString(str.ToString()),
WriteToTagComplete);
}
catch
{
UpdateState(NfcHelperState.ErrorWriting);
StopWritingMessage();
}
}
private void WriteToTagComplete(ProximityDevice sender, long messageId)
{
UpdateState(NfcHelperState.FinishedWriting);
StopWritingMessage();
}
private void StopWritingMessage()
{
if (_writingMessageId.HasValue)
{
_nfcDevice.StopPublishingMessage(_writingMessageId.Value);
_writingMessageId = null;
}
}
private static IBuffer GetBufferFromString(string str)
{
using (var dw = new DataWriter())
{
dw.UnicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.Utf16LE;
dw.WriteString(str);
return dw.DetachBuffer();
}
}
public delegate void NfcStatusMessageChangedHandler(object myObject, NfcHelperState newState);
public event NfcStatusMessageChangedHandler OnStatusMessageChanged;
}
I my program I need to capture when the Print Screen key is pressed down but it is not working (however it works with other keys).
I guess this has something to do with windows hijacking my authority and since im still new at this I'd love to know how I can get around this issue.
Here's my current code:
namespace Boom_Screenshot_
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window
{
//SETTINGS
Key TRIGGER_KEY = Key.PrintScreen;
public Window1()
{
InitializeComponent();
}
private void Window_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == TRIGGER_KEY)
{
MessageBox.Show("'PrintScreen' was pressed.");
}
}
}
}
I have an answer for you that I found here (I don't speak Chinese so don't ask me what it says :). You have to set a hook. He provides a wrapper class. I repeat some code here without the Chinese characters. RegisterHotKey.cs ...
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace TestKeydown
{
public class RegisterHotKeyClass
{
private IntPtr m_WindowHandle = IntPtr.Zero;
private MODKEY m_ModKey = MODKEY.MOD_CONTROL;
private Keys m_Keys = Keys.A;
private int m_WParam = 10000;
private bool Star = false;
private HotKeyWndProc m_HotKeyWnd = new HotKeyWndProc();
public IntPtr WindowHandle
{
get { return m_WindowHandle; }
set { if (Star)return; m_WindowHandle = value; }
}
public MODKEY ModKey
{
get { return m_ModKey; }
set { if (Star)return; m_ModKey = value; }
}
public Keys Keys
{
get { return m_Keys; }
set { if (Star)return; m_Keys = value; }
}
public int WParam
{
get { return m_WParam; }
set { if (Star)return; m_WParam = value; }
}
public void StarHotKey()
{
if (m_WindowHandle != IntPtr.Zero)
{
if (!RegisterHotKey(m_WindowHandle, m_WParam, m_ModKey, m_Keys))
{
throw new Exception("");
}
try
{
m_HotKeyWnd.m_HotKeyPass = new HotKeyPass(KeyPass);
m_HotKeyWnd.m_WParam = m_WParam;
m_HotKeyWnd.AssignHandle(m_WindowHandle);
Star = true;
}
catch
{
StopHotKey();
}
}
}
private void KeyPass()
{
if (HotKey != null) HotKey();
}
public void StopHotKey()
{
if (Star)
{
if (!UnregisterHotKey(m_WindowHandle, m_WParam))
{
throw new Exception("");
}
Star = false;
m_HotKeyWnd.ReleaseHandle();
}
}
public delegate void HotKeyPass();
public event HotKeyPass HotKey;
private class HotKeyWndProc : NativeWindow
{
public int m_WParam = 10000;
public HotKeyPass m_HotKeyPass;
protected override void WndProc(ref Message m)
{
if (m.Msg == 0x0312 && m.WParam.ToInt32() == m_WParam)
{
if (m_HotKeyPass != null) m_HotKeyPass.Invoke();
}
base.WndProc(ref m);
}
}
public enum MODKEY
{
MOD_ALT = 0x0001,
MOD_CONTROL = 0x0002,
MOD_SHIFT = 0x0004,
MOD_WIN = 0x0008,
}
[DllImport("user32.dll")]
public static extern bool RegisterHotKey(IntPtr wnd, int id, MODKEY mode, Keys vk);
[DllImport("user32.dll")]
public static extern bool UnregisterHotKey(IntPtr wnd, int id);
}
}
Calling code in a Form ...
private RegisterHotKeyClass _RegisKey = new RegisterHotKeyClass();
void _Regis_HotKey()
{
MessageBox.Show("ok");
}
private void Form1_Load(object sender, EventArgs e)
{
_RegisKey.Keys = Keys.PrintScreen;
_RegisKey.ModKey = 0;
_RegisKey.WindowHandle = this.Handle;
_RegisKey.HotKey += new RegisterHotKeyClass.HotKeyPass(_Regis_HotKey);
_RegisKey.StarHotKey();
}
Below is my pure WPF solution.
We can achieve this in xaml by using NavigationCommands (Namespace: System.Window.Input) class which provides a standard set of navigation commands (e.g. NextPage, PreviousPage, Refresh, Search etc.)
Implementation Approach:
So we can call any custom code to execute on application refresh using NavigationCommands.Refresh as
<UserControl.CommandBindings>
<CommandBinding Command='NavigationCommands.Refresh'
Executed="ApplicationRefresh_Executed">
</CommandBinding>
</UserControl.CommandBindings>
Now in code behind class of UserControl we can define method as
private void ApplicationRefresh_Executed(object sender, ExecutedRoutedEventArgs e)
{
// Implementation goes here.
}