protected override bool IsInputChar(char charCode) {
if (this.Focused) {
return true;
}
else {
return base.IsInputChar(charCode);
}
}
I put this in my custom control, and all works well. "ALT+C" still works on the button, but "C" goes to my custom control.
18 April 2015
.net - Keyboard input in custom controls
I'm working on a custom control in .net WinForms that allows the user to input characters when it is focused. So far so good, but there's also a button on the form that has a hotkey assigned. It's label is New &chapter, so whenever I press "ALT+C", it's OnClick event fires. However, I noticed that it also fires when I just press "C", and that of course conflicts with my custom control, which doesn't even receive the keystroke for "C" anymore. I also noticed this doesn't happen when I'm typing in a regular text box.
After a lengthy search I found this hotkey behavour is by design, so I needed to find a workaround for my control. After some more searching I finally found this event that does te trick:
04 April 2015
Windows - The behaviour of the standard textbox
For a custom textbox project, I observed the behaviour of the standard Windows textbox control, as to replicate this in the custom one. If you think of a behaviour not listed, please leave a comment below.
Terms
- The caret represents the focussed character in the text. It is marked by displaying a blinking bar behind it.
- The selection represents a range of characters from the caret until a second character. This character may occur before or after the caret.
Keyboard navigation
- Shift left/right: the selection is expanded/contracted by one character.
- Shift control left/right: the selection is expanded/contracted by one word.
- Shift up/down: the selection is expanded/contracted to the character above/below the caret.
- Home: the newline character of the line that contains the caret becomes the caret.
- End: the last character of the line that contains the caret becomes the caret.
- Page up/down: the text is scrolled so that the first/last visible becomes the last/first visible line. The character that occupies the screen space that the caret occupied becomes the caret.
Keyboard other
- A key or key combination that represents a glyph; no selection: the character is inserted behind the caret, and becomes the caret.
- A key or key combination that represents a glyph; with selection: the selection is removed. The first character before it becomes the caret. The character is inserted behind the caret, and becomes the caret.
- Backspace; no selection: the caret is removed. It's predecessor becomes the caret.
- Backspace; with selection: the selection is removed. The first character before it becomes the caret.
- Delete; no selection: the character following the caret is removed.
- Delete; with selection: the selection is removed. The first character before it becomes the caret.
- Control+A: the selection is expanded, spanning from the first until the last character of the text.
- Control+X: if there is a selection, the characters in it are copied to the clipboard. The selection is then removed.
- Control+C: if there is a selection, the characters in it are copied to the clipboard.
- Control+V: if the clipboard contains text, each character in that text is inserted behind the caret. The last one then becomes the caret.
Mouse
- Click: if there is a selection, the selection is cleared. The clicked character becomes the caret. If before a line, the newline character becomes the caret. If after a line, the last character of the lines becomes the caret.
- Double click: the clicked word becomes the selection. The last character of this selection becomes the caret.
- Shift click: the range between the caret and the clicked character becomes the selection. The last character of this selection becomes the caret.
- Click and drag: the caret follows the mouse. The selection expands and contracts from the clicked character to the caret, as long as the mouse button is not released. When the caret crosses the edge of the text area, it will scroll as well.
06 February 2015
Visual Studio - Use a theme with Windows high contrast
When you set Windows in a high contrast theme, Visual Studio follows suit, adapts the same colors, and does not allow you to pick another theme anymore. To make matters worse, it shows all the code in the same color; orange in my case. You could customize it, and set all the colors yourself, but that's a lot of work. There is a registry trick however, to fool the IDE and use a theme anyway. I did this for Visual Studio 2013, but it should work in 2012 and probably other versions as well.
- So open up RegEdit and navigate to the key HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\12.0_Config\Themes. If you use VS 2012, that would be 11.0_Config.
- You see a list of GUID's there. When you click one, you can see the theme's name. Select the theme you want, right-click it's key and export it.
- {a5c004b4-2d4b-494e-bf01-45fc492522c7} is the high contrast theme. Rename the key to the GUID of the theme you want after renaming that theme first. I simply swapped there names.
- Finally, choose File > Import, and import the .reg file you just exported.
- Now if you open Visual Studio, it should be using your theme.
08 January 2015
HTML5 - Wheel of fortune
For a small project I needed a wheel of fortune – also known as prize wheel, winning wheel and roulette wheel, but I couldn't find anything that did it the way I wanted it. So I made my own with these specifications:
- HTML5 canvas,
- No images,
- Dynamic number of sections,
- Spin on the click of a button.
- jQuery: who can live without it...
- Please: to generate random colors for the sections.
- A button called btnSpin that calls the function spin(),
- A canvas called Wheel,
- An arrow left of the canvas to mark the selected name.
var names = @Html.Raw(Json.Encode(Model.Names)); //Creates a javascript array from a C# list.
var n = names.length;
var colors = []; //Randomized based on 'n' further on.
var fps = 1000 / 30; //Animation speed.
var angle = 0;
var velocity = 1; //For the slowing down of the rotation.
var variation = 0; //So it doesn't always stop at the same name.
$(function () {
colors = Please.make_color({ colors_returned: n });
draw(angle);
$('#btnSpin').removeAttr('disabled');
})
function random(min, max) {
return Math.random() * (max - min) + min;
}
function getFontSize() { //The more names, the smaller they are displayed.
if (n < 10)
return 28;
else if(n < 20)
return 18;
else
return 10;
}
function spin() {
variation = random(0.15, 0.25);
window.setTimeout(animate, fps); //Begin the animation.
$('#btnSpin').attr('disabled', 'disabled');
}
function animate() { //Continue spinning until the wheel slowed down enough. Higher velocity means slower rotation.
velocity += variation * (velocity < 40 ? 1 : (velocity / 40));
draw(angle += Math.PI / velocity);
if (velocity > 200) {
velocity = 1;
$('#btnSpin').removeAttr('disabled');
}
else {
window.setTimeout(animate, fps);
}
}
function draw(angle) {
var canvas = document.getElementById("Wheel");
var ctx = canvas.getContext('2d');
var cx = canvas.width / 2;
var cy = canvas.height / 2;
var radius = cy - 5;
var range = Math.PI * 2;
var a = angle;
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.strokeStyle = '#222';
ctx.lineWidth = 3;
for (var i = 0; i < n; i++) {
ctx.save(); //Save the current state of the canvas.
ctx.translate(cx, cy);
ctx.rotate((a + (a + range / n)) / 2 + (range / 2) + (range / n / 2));
ctx.translate(-cx, -cy);
ctx.beginPath();
ctx.arc(2, cy, 6, 0, range);
ctx.closePath();
ctx.shadowColor = '#fff';
ctx.shadowBlur = 10;
ctx.shadowOffsetX = 0;
ctx.shadowOffsetY = 0;
ctx.fillStyle = '#222';
ctx.fill(); //Draws the handles on the outside of the wheel.
ctx.restore();
ctx.save();
ctx.beginPath();
ctx.moveTo(cx, cy);
ctx.arc(cx, cy, radius, a, a + range / n);
ctx.closePath();
ctx.fillStyle = colors[i];
ctx.fill(); //Draws the filled area of the sections.
ctx.beginPath();
ctx.moveTo(cx, cy);
ctx.arc(cx, cy, radius, a, a + range / n);
ctx.closePath();
ctx.stroke(); //Draws the outline of the sections.
ctx.translate(cx, cy);
ctx.rotate((a + (a + range / n)) / 2 + (range / 2));
ctx.translate(-cx, -cy);
ctx.beginPath();
ctx.rect(0, cy - 40, cx - 40, 80);
ctx.closePath();
ctx.clip(); //Makes sure the names don't draw outside their section.
ctx.fillStyle = '#222';
ctx.font = getFontSize() + 'px Verdana';
ctx.fillText(names[i], 20, cy + 10);
ctx.restore(); //Start fresh every time.
a += range / n;
}
ctx.beginPath();
ctx.arc(cx, cy, radius / 10, 0, range);
ctx.stroke();
ctx.fillStyle = '#444';
ctx.fill();
}
Windows - Hide drives in File Explorer
My administrator mapped some network folders as drives on everyone's PC that I don't have any use for. Getting rid of them is accomplished through the registry:
The registry key
- Open RegEdit, and open the subkey HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer.
- If it doesn't exist yet, add a new DWORD value called NoDrives.
- Put a decimal value in it, as specified below.
The value
Each drive letter has a value double that of the previous letter. So A=1, B=2, C=4 and so on until X=8388608, Y=16777216, Z=33554432. Take the drives you want to hide, add the values of their letters together and that's the value you need to put in the registry.08 October 2014
WPF - Use a System.Drawing.Image as ImageSource
I had a System.Drawing.Image thumbnail that I wanted to use as the ImageSource of an Image element in WPF. The following code – compiled with some help – did the trick:
using draw = System.Drawing;
...
draw.Image thumb = Browser.WebView.Capture(false); //The original image.
using (MemoryStream stream = new MemoryStream()) {
thumb.Save(stream, draw.Imaging.ImageFormat.Bmp);
stream.Position = 0;
stream.Seek(0, SeekOrigin.Begin);
BitmapImage bi = new BitmapImage();
bi.BeginInit();
bi.StreamSource = stream;
bi.CacheOption = BitmapCacheOption.OnLoad;
bi.EndInit();
Thumbnail.Source = bi; //The image element.
thumb.Dispose();
}
06 October 2014
.net - Discretely perform a mouse click
For an application I needed to perform a mouse click on a control in a way the user wouldn't even notice it. This was achieved as follows:
First the following Windows functions need to be imported. I've put these in a static class called "OS".
[StructLayout(LayoutKind.Sequential)]
public struct Win32Point {
public Int32 X;
public Int32 Y;
};
[DllImport("user32.dll")]
public static extern bool GetCursorPos(ref Win32Point pt);
[DllImport("user32.dll")]
public static extern bool SetCursorPos(int x, int y);
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern void mouse_event(long dwFlags, long dx, long dy, long cButtons, long dwExtraInfo);
The control in question is hidden. On it's load event this takes place:
OS.Win32Point pos = new OS.Win32Point();
OS.GetCursorPos(ref pos); //Gets the current mouse position.
int x = ((int)Left + (int)Width) - 220;
int y = ((int)Top + (int)Height) - 35;
OS.SetCursorPos(x, y); //Moves the mouse the where I need my click.
Browser.Visibility = Visibility.Visible; //Makes the control visible.
OS.mouse_event(0x02 | 0x04, 0, 0, 0, 0); //Performs the click.
Task.Run(async delegate { //Introduces a short delay to avoid that the mouse moves back before the click occures.
await Task.Delay(100); //.net framework 4.5 is needed to delay it like this.
OS.SetCursorPos(pos.X, pos.Y); //Moves the mouse back to it's original position.
});
Subscribe to:
Posts (Atom)
