Difficult question. The answer is probably no, if all I found in the Intertubes is right, but it is worth a try. I need to override the Ctrl + Shift + Esc and the Ctrl + Esc combinations. It would be good to be able to override the Win key combinations, but I have a low level hook that does such, I only wish I didn't need it. If I can manage to block the start menu and the task manager entirely by policy, the overrides will no longer be needed but I couldn't find the correct policy to do so.
You can override Ctrl + Esc (I just tried in AutoHotkey, it works), but not Ctrl + Shift + Esc, no more than Ctrl + Alt + Del.
So using policies is probably the way to go... No experience in this field, I fear.
In case someone comes here looking for a non-AutoHotKey, here is a c# way.
It is possible to do this using a keyboard hook. A good hook class for this can be found on this CodeProject Article
Using the below code will prevent the WIN+LEFT or WIN+RIGHT from occurring. You can use this to override whichever keys you'd like.
This will even override hotkeys which you added via RegisterHotKey Win API.
Once you have those classes in your project you can add handlers to the static HookManager class like below.
//It's worth noting here that if you subscribe to the Key_Press event then it will break the international accent keys.
HookManager.KeyPress += HookManager_KeyPress;
HookManager.KeyDown += HookManager_KeyDown;
HookManager.KeyUp += HookManager_KeyUp;
You can also add mouse events, but for simplicity I'm just showing the keyboard hook.
I've also created a generic list so that I know which keys are currently down and I remove those keys from the list on the KeyUp event.
public static List<Keys> keysDown = new List<Keys>();
private static void HookManager_KeyDown(object sender, KeyEventArgs e)
{
//Used for overriding the Windows default hotkeys
if(keysDown.Contains(e.KeyCode) == false)
{
keysDown.Add(e.KeyCode);
}
if (e.KeyCode == Keys.Right && WIN())
{
e.Handled = true;
//Do what you want when this key combination is pressed
}
else if (e.KeyCode == Keys.Left && WIN())
{
e.Handled = true;
//Do what you want when this key combination is pressed
}
}
private static void HookManager_KeyUp(object sender, KeyEventArgs e)
{
//Used for overriding the Windows default hotkeys
while(keysDown.Contains(e.KeyCode))
{
keysDown.Remove(e.KeyCode);
}
}
private static void HookManager_KeyPress(object sender, KeyPressEventArgs e)
{
//Used for overriding the Windows default hotkeys
}
public static bool CTRL()
{
//return keysDown.Contains(Keys.LShiftKey)
if (keysDown.Contains(Keys.LControlKey) ||
keysDown.Contains(Keys.RControlKey) ||
keysDown.Contains(Keys.Control) ||
keysDown.Contains(Keys.ControlKey))
{
return true;
}
else
{
return false;
}
}
public static bool SHIFT()
{
//return keysDown.Contains(Keys.LShiftKey)
if (keysDown.Contains(Keys.LShiftKey) ||
keysDown.Contains(Keys.RShiftKey) ||
keysDown.Contains(Keys.Shift) ||
keysDown.Contains(Keys.ShiftKey))
{
return true;
}
else
{
return false;
}
}
public static bool WIN()
{
//return keysDown.Contains(Keys.LShiftKey)
if (keysDown.Contains(Keys.LWin) ||
keysDown.Contains(Keys.RWin))
{
return true;
}
else
{
return false;
}
}
public static bool ALT()
{
//return keysDown.Contains(Keys.LShiftKey)
if (keysDown.Contains(Keys.Alt))
{
return true;
}
else
{
return false;
}
}
So you need do override Hotkeys on your application?
Then the answer is probably yes, how?
No idea, but if this(http://www.inchwest.com/mapkeyboard.aspx) program can, so can you
Related
I have created a simple custom editor tool, which allows me to keep mouse position in a straight line. I require this to draw texture on a terrain in a straight line. Unfortunately, when I enable "Paint texture" tool in the terrain editor in inspector, my custom tool gets disabled and vice-versa. How can I keep both my custom tool and terrain paint tool enabled at once?
Custom tool selected but paint texture is deactivated-
Custom tool got deselected on paint texture selection-
Following is the OnToolGUI method
public override void OnToolGUI(EditorWindow window)
{
HandleUtility.AddDefaultControl(GUIUtility.GetControlID(FocusType.Passive));
Event e = Event.current;
if (!(window is SceneView))
return;
if (!ToolManager.IsActiveTool(this))
return;
if (e.shift)
{
if (e.type == EventType.MouseDown)
{
if (e.button == 0)
{
downY = e.mousePosition.y;
}
}
if (e.type == EventType.MouseDrag)
{
if (e.button == 0)
{
e.mousePosition = new Vector2(e.mousePosition.x, downY);
Debug.Log("Mouse Position: " + e.mousePosition);
}
}
}
As mentioned in the comments I guess it simply is the nature of the tools that they are exclusive and you can only have one active at a time.
As alternative I would rather simply
enable/disable this via a general header menu entry
(optionally) store that decision persistent in EditorPrefs (pretty much like PlayerPrefs but for the editor itself)
and accordingly attach a listener to SceneView.duringSceneGui
This could look somewhat like e.g.
public static class StraightLineTool
{
// Used for the displayed menu labels
// and also simply (ab)used as the unique key for the EditorPrefs
private const string k_MenuName = "My Tools/Straight Line Tool";
private static float downY;
// Property for simplifying access and setting more centralized
private static bool IsEnabled
{
get => EditorPrefs.GetBool(k_MenuName, false);
set => EditorPrefs.SetBool(k_MenuName, value);
}
// method to be called when clicking the menu button
[MenuItem(k_MenuName)]
private static void ToggleEnabled()
{
IsEnabled = !IsEnabled;
ApplySettings();
}
// adding a checkmark when is enabled and simply always allow to click it
[MenuItem(k_MenuName, true)]
private static bool ToggleEnabledValidate()
{
Menu.SetChecked(k_MenuName, IsEnabled);
return true;
}
// Called on every project loading or code recompilation
[InitializeOnLoadMethod]
private static void Initialize()
{
EditorApplication.delayCall -= ApplySettings;
EditorApplication.delayCall += ApplySettings;
}
private static void ApplySettings()
{
// remove so only happening once
EditorApplication.delayCall -= ApplySettings;
SceneView.duringSceneGui -= OnSceneGUI;
if (IsEnabled)
{
// if enabled start listening
SceneView.duringSceneGui += OnSceneGUI;
}
}
// Callback listening to any SceneView.duringSceneGui
private static void OnSceneGUI(SceneView sceneView)
{
// Not sure tbh what this does or if you need it still in this approach
// HandleUtility.AddDefaultControl(GUIUtility.GetControlID(FocusType.Passive));
var currentEvent = Event.current;
if (currentEvent.shift)
{
if (currentEvent.type == EventType.MouseDown)
{
if (currentEvent.button == 0)
{
downY = currentEvent.mousePosition.y;
}
}
if (currentEvent.type == EventType.MouseDrag)
{
if (currentEvent.button == 0)
{
currentEvent.mousePosition = new Vector2(currentEvent.mousePosition.x, downY);
Debug.Log("Mouse Position: " + currentEvent.mousePosition);
}
}
}
}
}
=> using this the tool will be enabled/disabled persistent even when restarting Unity
Then using this as start point you can probably still try to somehow integrate this somewhere more nicely into the SceneView menus - but maybe that is also overkill ;)
I have a cefSharp:ChromiumWebBrowser that loads various web pages for our WPF application.
One of these web pages handles keyboard shortcuts like (Alt+S and Alt+C). If the page is called from an external browser these shortcuts work as expected.
But when the shortcuts are used in the cefSharp:ChromiusWebBrowser Control they don't work.
I tried to figure out whether the Shortcuts get handled by the UserControl that contains the browser control by using
private bool _altKeyPressed = false;
protected override void OnPreviewKeyDown(KeyEventArgs e)
{
if (_altKeyPressed)
{
_altKeyPressed = false;
if (e.SystemKey == Key.S || e.SystemKey == Key.C)
{
e.Handled = false;
}
}
if (e.SystemKey == Key.LeftAlt || e.SystemKey == Key.RightAlt)
{
_altKeyPressed = true;
}
base.OnPreviewKeyDown(e);
}
I tried it with e.Handled = true and e.Handled = false. This code gets called but changing the Handled Property brought no improvement.
I also tried the same approach by hooking up to the PreviewKeyDown EventHandler like this
<cefSharp:ChromiumWebBrowser x:Name="_browser" PreviewKeyDown="_browser_OnPreviewKeyDown">
I am not showing the code for _browser_OnPreviewKeyDown because it is the same as in the OnPreviewKeyDown. Also this code gets called and has no change in behavior whether Handled is set to true or false.
Does anyone know how I can make the Chromium Control behave the same as an external browser in terms of Shortcuts?
Update
The browser did not have a keyboard handler. So I made one.
Please see the comments in OnKeyEvent to see where I am stuck at the moment.
Thank you
public class KeyboardHandler : IKeyboardHandler
{
private bool _cefAltKeyPressed;
public bool OnPreKeyEvent(IWebBrowser chromiumWebBrowser, IBrowser browser, KeyType type, int windowsKeyCode, int nativeKeyCode, CefEventFlags modifiers, bool isSystemKey, ref bool isKeyboardShortcut)
{
const int KEY_C = 67;
const int KEY_S = 83;
bool result = true;
if (_cefAltKeyPressed)
{
if (windowsKeyCode == KEY_C || windowsKeyCode == KEY_S)
{
isKeyboardShortcut = true;
result = false;
}
_cefAltKeyPressed = false;
}
if ((modifiers & CefEventFlags.AltDown) != 0 && type == KeyType.RawKeyDown)
{
_cefAltKeyPressed = true;
}
return result;
}
public bool OnKeyEvent(IWebBrowser chromiumWebBrowser, IBrowser browser, KeyType type, int windowsKeyCode, int nativeKeyCode, CefEventFlags modifiers, bool isSystemKey)
{
// With the code in OnPreKeyEvent, OnKeyEvent is only called, when Alt + S or Alt + C is pressed in the browser
// So what am I supposed to do with this Event now?
// I do not want to implement a search (Alt + S) or clear (Alt + C) functionality here, since that is part of the web site
// I just want the website to be able to receive the Alt + S and Alt + C keystrokes and allow it to handle it
return false;
}
}
So in short i'm simply trying to move a rectangle around a Canvas object in a WPF application. What i have here is my KeyDown event function. The problem is, when i hold a key down for long, it launches this function over and over again rapidly and screws up my rectangle location code.
My theory/logic behind it:
BECAUSE WHEN YOU HOLD A BUTTON DOWN ON A KEYBOARD IT DOES NOT MOVE SMOOTHLY (TEST IT ON THE SCROLL BAR IN YOUR BROWSER, IT STARTS, pauses, THEN CONTINUES SMOOTHLY), i want it to start a forms timer that moves the object in the UI. Then when the KeyUp event happens, the timer STOPS.
public void Window_KeyDown(object sender, KeyEventArgs e)
{
string msg;
string keystr = e.Key.ToString();
Key keyval = e.Key;
switch (keystr)
{
case "Down":
Console.WriteLine("Case 1");
Display.Content = "Down";
foreach (Character character in creatures)
{
//character.buttondown = true;
character.Position("Down");
}
break;
case "Up":
Console.WriteLine("Case 2");
Display.Content = "Up";
foreach (Character character in creatures)
{
//character.buttondown = true;
character.Position("Up");
}
break;
case "Left":
Console.WriteLine("Case 3");
Display.Content = "Left";
foreach (Character character in creatures)
{
//character.buttondown = true;
character.Position("Left");
}
break;
case "Right":
Display.Content = "Right";
foreach (Character character in creatures)
{
//character.buttondown = true;
character.Position("Right");
}
break;
}
}
public void Window_KeyUp(object sender, KeyEventArgs e)
{
Display.Content = "No key is pressed.";
foreach (Character character in creatures)
{
if (e.Key == Key.Right)
{
character.StopIt();
}
if (e.Key == Key.Left)
{
character.StopIt();
}
if (e.Key == Key.Up)
{
character.StopIt();
}
if (e.Key == Key.Down)
{
character.StopIt();
}
}
}
and just for reference if you need my rectangle class code i'll post what happens if the RIGHT arrow key is pressed:
Position is called
public void Position(String Direction)
{
if (Direction == "Right")
{
tmr = new System.Windows.Forms.Timer();
tmr.Interval = this.waitTime;
tmr.Tick += new EventHandler(GoRight);
tmr.Start();
}
}
GoRight is called:
public void GoRight(object sender, System.EventArgs e)
{
if (x < Background.ActualWidth - CharacterWidth)
{
if (goRight)
{
x += incrementSize;
CharacterImage.SetValue(Canvas.LeftProperty, x);
}
if (x > Background.ActualWidth - CharacterWidth)
{
goRight = false;
tmr.Stop();
}
}
}
Finally, StopIt is called in the KeyUp event:
public void StopIt()
{
tmr.Stop();
goRight = true;
goLeft = true;
goUp = true;
goDown = true;
}
I've only been learning c# for a couple months now so i'm trying to keep it relatively simple if possible, and only use .net.
Any help would be appreciated!!
EDIT:: MY SOLUTION:
I simply made a while(flag) loop around my switch case. Then i set flag = false within the cases. When Key UP is pressed i set flag equal to true again. YAY
I assume that you want your character to move on the initial KeyDown event. Then you want to ignore any subsequent KeyDown events until you get a KeyUp event.
So you can ignore the subsequent KeyDown events by checking e.IsRepeat e.g.
public void Window_KeyDown(object sender, KeyEventArgs e)
{
if (e.IsRepeat) return;
// rest of your code...
BTW, the non-smooth movement that you observe when scrolling an application is caused by the keyboard repeat delay. You can set this in the keyboard properties or though http://msdn.microsoft.com/en-us/library/system.windows.systemparameters.keyboarddelay.aspx
I don't know enough about WPF to tell you what is going on, though you may be correct about the push button/pause thing. It depends on how WPF treats keypresses. My guess would be that it does so the same way most Microsoft forms work; it has a pause to keep you from typing multiple characters at a time. There may be a way around this but I'm not sure.
What I will say though is that you should use something designed for games. When I first tried creating games I did so in a style similar to what you are doing and it doesn't work. What you are using is designed for office software and will not give you access to what you need; at least not without fighting and workarounds. As was suggested by Alex Beisley look into XNA. It's a dead language unfortunately but it died fairly recently. It uses c#, was made by Microsoft, and is powerful enough to do what you want without fighting you and easy enough to use once you get the hang of it. It's a shame to see it killed off.
If you want to torture yourself then I'd suggest going the route I've been trying which is to learn C++ and DirectX. It is not easy and you will need to be patient and go through multiple tutorials (no one tutorial seems to do a good job explaining anything). DirectX and C++ are not going anywhere soon, so they are a safe bet if you are looking to get into a long term language.
You may find if the CapsLock key has been pressed subscribing to the KeyDown/KeyUp event. And then toggle the state of the CapsLock based on that input. The problem with this approach is that you need the initial state of the CapsLock key to start toggling that.
One application of this could be giving the user a notification on a Login Page (this is what i need).
By the way i'm using Silverlight 5.
EDIT
The solution posted here says:
You can however find out if Capslock is on by making use of
KeyEventArgs.PlatformKeyCode that's actually send at onKeyDown.You can
look up the Virtual Key-code for capslock in here:
http://msdn.microsoft.com/en-us/library/ms927178.aspx
With this solution you can't determine the CapsLock state, because KeyEventArgs.PlatformKeyCode returns "an integer value that represents the key that is pressed or released (depending on which event is raised)". So if CapsLock is On and Key A is pressed then KeyEventArgs.PlatformKeyCode = 65, and on the other hand if CapsLock is off and Key A is pressed then KeyEventArgs.PlatformKeyCode = 65.
In other words you can't determine if the CapsLock is enabled or not based on the KeyEventArgs.PlatformKeyCode property.
The answer to this question also seems to have a solution, it checks two things:
the letter typed is Upper Case and Shift isn't pressed
the letter typed is Lower Case and Sift is pressed
Both of this cases implies that the CapsLock is On, but there is also a problem with this solution, given a KeyEventArgs you can know the pressed key in the keyboard but can't know the Char outputted by that key.
I'd suggest using a Behavior for this detection since you can hook into the PasswordChanged and KeyDown events to determine if the Caps Lock is on. Here is a quick behavior I wrote to detect if the Caps Lock is on. You can bind to the CapsLockOn behavior and use something like a data state behavior to hide/show your warning message.
public class DetectCapsLockBehavior : Behavior<PasswordBox>
{
private int _lastKey;
private ModifierKeys _modifiers;
[Category("Settings")]
public bool CapsLockOn
{
get { return (bool)GetValue(CapsLockOnProperty); }
set { SetValue(CapsLockOnProperty, value); }
}
public static readonly DependencyProperty CapsLockOnProperty = DependencyProperty.Register("CapsLockOn", typeof(bool), typeof(DetectCapsLockBehavior), new PropertyMetadata(null));
protected override void OnAttached()
{
AssociatedObject.PasswordChanged += new RoutedEventHandler(AssociatedObject_PasswordChanged);
AssociatedObject.KeyDown += new KeyEventHandler(AssociatedObject_KeyDown);
}
void AssociatedObject_KeyDown(object sender, KeyEventArgs e)
{
_lastKey = e.PlatformKeyCode;
_modifiers = Keyboard.Modifiers;
}
void AssociatedObject_PasswordChanged(object sender, RoutedEventArgs e)
{
if (_lastKey >= 0x41 && _lastKey <= 0x5a)
{
var lastChar = AssociatedObject.Password.Last();
if (_modifiers != ModifierKeys.Shift)
{
CapsLockOn = char.ToLower(lastChar) != lastChar;
}
else
{
CapsLockOn = char.ToUpper(lastChar) != lastChar;
}
}
}
}
NOTE: This is sample code, so there could be bugs. Just trying to demonstrate how it could be done.
region KeysDetection
bool bCaps = false;
bool bIns = false;
bool bNum = false;
public void FloatableWindow_KeyDown(object sender, KeyEventArgs e)
{
switch (e.Key)
{
case Key.CapsLock:
bCaps = !bCaps;
lbl_caps.Opacity = (bCaps) ? 1 : 0.5;
break;
case Key.Insert:
bIns = !bIns;
lbl_ins.Opacity = (bIns) ? 1 : 0.5;
break;
case Key.Unknown:
{
if (e.PlatformKeyCode == 144)
{
{
bNum = !bNum;
lbl_num.Opacity = (bNum) ? 1 : 0.5;
}
}
break;
}
}
}
#endregion
In this application, I need to be able to stop the response from a key which is held down in order to prevent unnessecary data from entering the output. The problem I'm having is, using the methods in my code below does prevent the keys from repeating, but it also stops them from being responsive enough - as the users are hitting the keys very quickly.
I'm not sure if it's my hardware, api restriction or a problem with my code, but the routines I have below do not simply come round fast enough to work without making the program impossible to use. A way of identifying if a key is being actively held down (and for how long) would also help another feature for the program and solve this current issue.
Any ideas?
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
e.SuppressKeyPress = isKeyDown;
isKeyDown = true;
}
private void Form1_KeyUp(object sender, KeyEventArgs e)
{
isKeyDown = false;
}
private void Form1_KeyPress(object sender, KeyPressEventArgs e)
{
if (!isStreamPlaying) return;
if (e.KeyChar.Equals('d') || e.KeyChar.Equals('j'))
{
//red hit
SoundPlayer hitSounds = new SoundPlayer(taikoLiveMapper.Properties.Resources.normal_hitnormal);
hitSounds.Play();
outputlist.Add(string.Format("320,240,{0},1,{1}", ms, 0));
lastms = ms;
}
else if (e.KeyChar.Equals('s') || e.KeyChar.Equals('k'))
{
//blue hit
SoundPlayer hitSounds = new SoundPlayer(taikoLiveMapper.Properties.Resources.normal_hitclap);
hitSounds.Play();
outputlist.Add(string.Format("320,240,{0},1,{1}", ms, 8));
lastms = ms;
}
}
You can use GetKeyState to find out if a key is down and use that to track the keys:
[DllImport("user32.dll")]
static extern short GetKeyState(int key);
static bool IsKeyPressed(Keys key)
{
short state = GetKeyState((int)key);
return ((state & 128) != 0);
}
int i = 0;
Dictionary<Keys, DateTime> downSince = new Dictionary<Keys, DateTime>();
private void UpdateKeyStates()
{
foreach (var entry in downSince.ToArray())
{
if (!IsKeyPressed(entry.Key))
downSince.Remove(entry.Key);
}
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
UpdateKeyStates();
if (!downSince.ContainsKey(e.KeyCode))
{
downSince.Add(e.KeyCode, DateTime.UtcNow);
i++;
}
Text = i.ToString() + " " +(int)(DateTime.UtcNow - downSince[e.KeyCode]).TotalMilliseconds;
}
private void Form1_KeyUp(object sender, KeyEventArgs e)
{
UpdateKeyStates();
}
This example counts i up every time a key is pressed, and shows for how long it has been pressed. It uses GetKeyState instead of tracking KeyDown/KeyUp since you might miss those messages if something else has focus.
According to the documentation, "[d]uplicate KeyDown events occur each time the key repeats, if the key is held down, but only one KeyUp event is generated when the user releases the key."
So the simplest solution is to ignore a repeated KeyDown event unless its corresponding KeyUp event has been seen.
Just worked for me.
Use Timers instead: initialize timers, one for each "action" (e.g. pressing d/j or s/k) move the red hit/blue hit code inside the timer and instead of your current code, have this:
if (e.KeyChar.Equals('d') || e.KeyChar.Equals('j'))
{
//red hit
if (!tmrRedHit.Enabled)
tmrRedHit.Enabled = true;
}
else if (e.KeyChar.Equals('s') || e.KeyChar.Equals('k'))
{
//blue hit
if (!tmrBlueHit.Enabled)
tmrBlueHit.Enabled = true;
}
And in the timers Elpased event also set their Enabled to false after the code is executed.