Link to home
Start Free TrialLog in
Avatar of coder1313514512456
coder1313514512456Flag for United States of America

asked on

C# Winform: Textbox can only capture most control characters, but not E, J, L, or R

I have a textbox in C# which, upon a KeyDown event, fires off to a method that outputs comprehensive keyboard input data.  (This is as a test for creating shortcuts that do various actions).

For most control key sequences, it works this way:  the user has focus on the textbox, and if you tap the control key, the following output will display:

checkForShortcuts():  KeyCode == ['ControlKey'], KeyValue == [17], KeyData == [ControlKey, Control], kKey == [ControlKey], cKey == '<' (17).

(I have substituted '<' in the above output statement for character 17, which looks like a left pointing triangle.)

If you type  a Control-T, it will show this:

checkForShortcuts():  KeyCode == ['ControlKey'], KeyValue == [17], KeyData == [ControlKey, Control], kKey == [ControlKey], cKey == '<' (17).
checkForShortcuts():  KeyCode == ['T'], KeyValue == [84], KeyData == [T, Control], kKey == [T], cKey == 'T' (84).

(There are two lines because I hold down the control key before pressing T, sometimes if I just wait I will get a whole slew of outputs about the control key being pressed.)


The problem:

The problem is that there are a few control keys that simply do not fire that I'd like to use.

They are:

^E, ^J, ^L, and ^R.

(Also, ^A will not fire but instead issue a Select All, however, this is desired functionality.)


QUESTION:  How can I capture these other control characters?  This should be a very simple and obvious thing to do.


Also:
Since this is .NET (4.0), I'm just using all the defaults in Visual Studio (2010).  The essential code is:

        protected void checkForShortcuts(TextBoxBase tbb, KeyEventArgs e)
        {
            Keys kKey = e.KeyCode;
            char cKey = char.ToUpper ( (char)e.KeyValue );
            
            rtbOutput.AppendText( string.Format(
                    "checkForShortcuts():  KeyCode == ['{0}'], KeyValue == [{1}], KeyData == [{2}], kKey == [{3}], cKey == '{4}' ({5})."
                    + Environment.NewLine, e.KeyCode, e.KeyValue, e.KeyData, kKey, cKey, (int) cKey) );

        // ...

Open in new window


Avatar of Jacques Bourgeois (James Burger)
Jacques Bourgeois (James Burger)
Flag of Canada image

You possibily have a menu in which those shortcuts are defined. In such a case the menu grabs the key combination and you never get it in your event handler.

Hello, to solve that you need to use the PreviewKeyDown event of your TextBox controls, something like this:
protected void checkForShortcuts(TextBoxBase tbb, PreviewKeyDownEventArgs e)
{
    Keys kKey = e.KeyCode;
    char cKey = char.ToUpper((char)e.KeyValue);

    rtbOutput.AppendText(string.Format(
            "checkForShortcuts():  KeyCode == ['{0}'], KeyValue == [{1}], KeyData == [{2}], kKey == [{3}], cKey == '{4}' ({5})."
            + Environment.NewLine, e.KeyCode, e.KeyValue, e.KeyData, kKey, cKey, (int)cKey));
}

private void textBox1_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{
    checkForShortcuts(textBox1, e);
}

Open in new window

The problem with PreviewKeyDown is that you will end up with 2 operations firing on the same shortcut.

Not a very good design. If Ctrl-C was copying in some places, but doing something else elsewhere, users would become confused.

You would be better to simply select another shortcut, either for the menu, either for the operation you want to perform in that specific TextBox.
Really.. I don't see where is the problem, he can decide what to do with that event, he can ignore it or do something with it.

For example, do nothing when the user press Ctrl+C:
if (e.KeyData == (Keys.Control | Keys.C))
    return;

Open in new window


Maybe I don't see your point...
SOLUTION
Avatar of Carlos Villegas
Carlos Villegas
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of coder1313514512456

ASKER

James, yv989c,

Wow, thanks guys, didn't know about either of those items.

The thing of it is, I do have a menu but I'm not capturing those control characters.

At least, I don't think I am.  They aren't listed in the menu's shortcuts, but I do have menu items.

Any way I can get these shortcuts back?  I'd like to use some of these control characters, and I can also see running into this problem in the future.

Hwo can I remove any old/hidden control keys handled by the menu so I can use these control keys?


Thanks again to you both!


yv989c, thanks I will definitely keep IsInputKey in mind.  The thing is, in this case my method isn't even being called, so I don't have a place that I can put that if statement.  But I did not know about overriding menu shortcuts with IsInputKey, thanks.
The problem is that the user can be confused if he has the same Ctrl shortcut do different things in different places.

A Ctrl shortcut should be unique in the applications.

When the same shortcut can be used in different places, Alt is the preferred modifier to add to the key.

This is only standard practice in Windows. As soon as you do not follow standard practices, you confuse a lot of users.
That is right, I agreed with James.
Hello coder:
Hwo can I remove any old/hidden control keys handled by the menu so I can use these control keys?

A way to do this is to check all the items in your Menu and check the Shortcut property, then set it to none, something like:
void RemoveMyMenuShortCuts()
{
    // myMenu is your form MenuStrip
    RemoveShortCuts(myMenu);
}

void RemoveShortCuts(MenuStrip myMenu)
{
    foreach (ToolStripMenuItem subItem in myMenu.Items)
    {
        RemoveShortCuts(subItem);
    }
}
void RemoveShortCuts(ToolStripMenuItem item)
{
    if (item.ShortcutKeys != Keys.None)
        item.ShortcutKeys = Keys.None;

    foreach (ToolStripMenuItem subItem in item.DropDownItems)
    {
        RemoveShortCuts(subItem);
    }
}

Open in new window


Be careful of how you use this, as James said, this can end up confusing the user.
Doing it with code as in the loops would remove all the shorcuts, not only the ones in conflict.

And if this application has been used before (is it an update or a new application?), removing the shortcuts would also be bad for the users who use them. This is why I would leave the menus as they are and use other shortcuts for internal processing in the application.

You could also ask the users if they would use the menu more often than the function on the control. The one that is used most often should be the one that has a shortcut.

If you decide to remove them from the menus anyway, instead of removing the shortcut keys through code, I would do it manually in the Form Designer.

If in fact this is your problem (as far as I understand, this has not been proven yet), and if you do not see them, this is because the ShowShortCutKeys of the menus that have these keys has been set to False.

In the Form Designer, go through all the menu entries and check their ShortcutKeys property. If you see one that correspond to the ones you want to handle, simply right click on the property and Reset it. Do the same for the ShowShortcutKeys property if it is set to False.
Greenfield project.  No user base.  May have initially had some shortcuts which were removed.  I'll double check...no.

Show shortcuts is true.  Very few current menu shortcuts and none the same as the ones I'm trying to capture.

For example, there is no ^R shortcut, yet a ^R does not engage the event.  (But a ^Q or ^S or ^T will engage the event and call the method.)

Curious.
Is the keyboard defined as English US in the control panel?

I'll give you an example I have to deal with here with some people who have their keyboard set to French.

When you receive Keys.Q in a KeyDown event, the key that is received maybe something else than Q. Keys.Q is not Q, it is the value 81. This the numeric value associated with the leftmost key of the topmost of the 3 letter rows of the keyboard. On a French keyboard, Q and Z are inverted compared to what we have in North America. But the numerical values are not. When a French user type Ctrl-Z, the application still receives value 81. What you receive in the code is still Keys.Q although the user has pressed a key on which "Z" is written.

Try the following in the KeyDown event of a TextBox:
Private Sub TextBox1_KeyDown(sender As Object, e As System.Windows.Forms.KeyEventArgs) Handles TextBox1.KeyDown
    MessageBox.Show(CInt(e.KeyValue).ToString)
End Sub

Open in new window

Run the form, go in the textbox and press the "e" key. If you do not get 69, then this is your problem. We will go for the solution on the next post if this is it.
On two different machines, they are both set to English-US.

One is a Dell laptop, the other is a Macintosh running bootcamp and reads English-US (Apple).

Both behave identically.

I did output the KeyValue integers as can be seen in the above example, the problem is that pressing a Control R (or a ^e or ^L or whatever) will not run the method the way the other control characters do.  Sp I can't capture what key it thinks is being pressed.


Important update:  It has to be the environment.

I just created a new solution without a menu, just a winform with one read only textbox and found that it was not taking these same keys.  It would fire on other control characters but not this same set.

Yet this same set of keys was having trouble on both the Dell and the Mac/bootcamp, which would point to an executable problem.


Curious...


Just to be sure, when I say a keyboard set to English-US, I mean the keyboard, not the regional settings. These are different things that are often thoughth as being the same.

If it is indeed the environment, it is possible for an application to grab and filter out the keys. This was very often seen in Windows 3.1 to have such applications used as a kind of macro that could type for you. You pressed Ctrl-E in any application, and there goes you email address into anything that has the focus.

Because of security restrictions, it is harder to do today, but I unserstand that is it still feasible.

Type msconfig in any DOS (command prompt) window. Go to the startup tab and disable everything there. Also make sure that there is nothing in the Start...Programs...Startup menu. This will disable most (but not all) of the applications that start automatically when you launch Windows. If your problem is solved after that, then you know that one of these applications is grabbing the key combinations you are trying to catch yourself.

***** HOWEVER *****

Since you also have the problem on a Mac, I would put a little more emphasis on your Curious...

Dummy question, but it has to be asked. Did you try with different keyboards, or did you use the same physical keyboard for all the tests?

ANOTHER THING TO TRY

Create a menu and add a shortcut key for those you cannot catch on one of the entries. Does it fire the click event of that menu when you activate the shortcut?

Sorry I've been missing comments, especially that one last night.  I must have forgotten to refresh the browser page.

I have just tried it on yet another computer (a laptop) and gotten the same results.

That's two laptops and a tower, all running Windows 7.  The keyboards are all different; on laptops I'm just using the laptop's keyboard and on the mac I'm using the mac keyboard.  If I say, open a console and echo one of these key combinations, the key combination can be seen.  It would appear to be just in the app.

Or any winform I make in VS2010 in this environment?

-TEST-
Made a basic winform with a window and one textbox.  Fails.

..perhaps this is the issue?  Could it be that some kind of library I've accidentally linked with is capturing these shortcuts?  The thing there is though that I'm using just a plain winform, nothing special.  I don't think it's malware into the dev environment because I'm running modern anti-virus software that is updated and scans almost nightly (unless I interrupt it).

-TEST-

Ok, I just tested making that same window with one textbox on one of my other machines, and guess what?

It works.  All control keys respond as they should.

The weird thing:  When running that one program created from the other development environment, its keys do not work.  The program created from the one machine doesn't work on either.  The program created from the second machine does work on it.

So it seems I'm in a development library issue??

As I told you in my last post : it is possible for an application to grab and filter out the keys.

From what you tell, at a distance, it is the most plausible cause.

You might want to do the following.

Take the simple application that has the problem, start it in Visual Studio and hit a breakpoint. The Debug menu has an option to list the modules loaded. You will get all the dlls used by your application, with a version number that is more precise than the one you get in the References window.

Do the same on the computer that has the simple application that does run.

Compare both listing. You will be able to see the dlls that are not the same, and maybe pinpoint the problem.

Could it be just that one machine is on 4.0 and the other on 4.0 SP1?

What if you tried to target framework 3.5 in the machine that causes the problem?

Brought the exe that was created on machine#2 to machine#1.  It works.

Development environment issue, must be.  Not a system wide key event grabber.

If I make the same program on machine #1, those keys do not work on either machine #1, #2, or #3.

Same program.
When created on machine #1 doesn't work correctly on anything.
When created on machine #2 works.


Sincerely,

Confused


Just saw your response.  Working on it...
Both machines are running the same version of VS2010, and have no updates waiting.

I can get the Modules list up on the bad machine (#1) but not the good machine (#1).

For some reason, machine #2 only lists 9 windows, whereas the bad dev environment has 17 or so debug windows available.  Of course I've got the app running in debug and breaking at the same place, so it's not that I'm not debugging.  (Otherwise I guess the windows list would be 1 for the breakpoint window.)  I can't find anything that displays the Modules window, not in the preferences or in help or online suggestions.





I meant, "not the good machine (#2)".

Are you on the Express version on machine #2? Not all windows are available on the Express Edition of Visual Studio.

Even in Visual Studio Professional, if you have your environment set for Visual Basic, you do not see all the tools. You need to set Tools...Imports and Settings... to General Development Settings in order to get access to all the tools. BE AWARE that doing so changes most of the shortcut keys and some options will switch menus when you switch to General DS.
Sorry, just saw your post.

Am not on express.  Not sure if I follow the rest of your idea there, however.  Do you mean some option in Tools > Import and Export Settings?  I don't see an option there to do anything other than import and export settings to and from settings files.  There's Tools > Customize, which does seem to affect Menu behavior, however it doesn't appear to have groups of settings ... Not seeing anything obvious in Tools > Settings.  Maybe I'm looking directly at something and just overthinking it.
If you select Reset All Settings and go on with any of the 2 selections there (the first one is the best, because it will enable you to restore your old settings should you not like the changes that will be done to your environment), you will have a choice of different basic settings for the Visual Studio environment.

User generated image
One of these has already be selected for you when you installed Visual Studio, according to the choices you made at that time. These set of settings are made to ease the transition from another environment. So people who come from VB6 and install only VB.NET when installing Visual Studio end up with the same shortcuts that they were used to in VB6, and similar menu options will be in the same menus.

However, since Microsoft assume that beginners will be using VB instead of another language, they hide a lot of tools when the Visual Basic Development Settings is activated. If you select the General Development Settings however, you end up with more menu options and more tools to work with in many of the Visual Studio windows. BUT THIS WILL REDEFINE SOME OF YOUR ENVIRONMENT, inclucing the shortcuts that will change a lot. If you are used to debug Step by Step with F8, it will now be F10.

James,

Thanks for the incredibly detailed explanations and instructions, just on everything.

I've compared the two module lists.  They are nearly identical except that the one that builds correctly (machine #2) has an additional module "Accessibility.dll".  I have a hard time believing that this is the difference that's being caused because the issue would seem to be that machine #1 is the one that should have extra modules in it that's stealing input.  Also, I wouldn't know where to get the Accessibility module from (though I'd certainly be interested whether or not it would help.

I'm still trying to wrap my brain around a problem in which something on one machine has problems everywhere and then the same code build on another machines has problems nowhere.

Perhaps a memory issue?  I'm feeling kind of toyed by this thing.

Strange that you have Accessibility. It can be added by Add Reference in the Project menu.

This dll is normally used in applications conceived for people with disabilities. As an example, it could be used to have the system read the text of every control that gets the focus read aloud the text in the speakers.

It does have some keyboard features, but since it's the application without it that has the problem, it is not the problem. You probably just hit something, such as one of the Accessible... properties of controls, and the reference was added automatically.

Could you zip the small project you built with only one window and a TextBox and post it, including the .exe in the bin directory. The one that does not get your keys. I could try the exe here, and then look at the code in Debug so see if I find something.

I now remember adding Accessibility, had forgotten about it before.  One of the things I am doing is to see how modern accessible winform development can be accomplished, and I just added the Accessibility out of curiosity.  Again, the environment that has accessibility is the one that works, and I believe it to be irrelevant.

This forum will not allow me to post an executable nor a zip that contains an executable, as it's disallowed by the forum agreement.  How can I get this zip to you?

You will find my email address on my web site at http://www3.sympatico.ca/jbfi/homeus.htm. Zip everything. The .exe alone would be rejected.
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
ARRRG!

I had thought I had tried that!

It would be nice to be able to have the form capture keyboard input no matter where the cursor was on the form.  I don't need to capture keyboard input when the application doesn't have focus / isn't active, but this is kind of important.

I'm trying to be able to make applications for blind people and I think I do need to know how to do this.

Would you suggest that I close this question and then ask a new one about how to do such a thing?  I am looking for a read only textbox solution, but there are other applications that I can imagine that this would be applicable in.


What would you suggest I do?

Avatar of Mike Tomlinson
As James suggested, you might want to try going a little lower level.  Override WndProc() for the Form and trap WM_KEYDOWN.  Examples abound on the net...  =)
But, this can be accomplish enabling the Form.KeyPreview property and by using the Form.KeyDown event... I'm wrong?
According to James, apparently not when the ReadOnly Property on the TextBox has been set to True (see his last post).  I haven't checked it myself...
Yeah, what I was just going to say is on keypress to do a e.Handled=true, at least for keys that would modify the input box.  Allow keys like arrows and home and end.

As suggested, it is possible to trap keys on the form. When the KeyPreview property of the form is set to True, the keys go through the form before going to the controls.

But as I told in my answer, I tried that and found out that the problem with the 4 or 5 key combinations that are trapped when the TextBox.ReadOnly property is True also transfers to the form. So you can trap any other keys, but not those.

Couldn't you simply use other shortcuts?

Another alternative. Since it is ReadOnly, why does it have to be a TextBox. You could do this in a Label. The only reason to use a ReadOnly TextBox, unless the property is toggled on and off for some reason, is to enable the user to copy and paste the text. If this is not a requirement, a Label could very well do the work.

-----

A little out of topic, but you mentioned sooner that you "remember adding Accessibility". Why didn't you pursue on this feature since you are working with blind peoples? Accessibility has been conceived specially for those kind of applications.

I did something for people with eyesight disabilities many years ago, and it was a pain. When .NET came along with those Accessybility features, I gave them a quick look out of curiosities, and remember very well thinking "if only that thing would have existed a few years back, we would have saved weeks on that application".
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
The accessibility feature, for what I have seen when I gave it a look, has been designed exactly for what you say: It's best to make one app that everyone can use.
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Just including the Accessibility dll also seems to do it(!). Looks like I have some choices

I'll update this when I get home, really want to try that contextmenustrip
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
This really works great.  KeyPreview and ContextMenuStrip against the form solve it and JamesBuger completely explained why the problem was occurring (very interesting, by the way) and why the solution works.  In the future I'll also be including the reference to Accessibility.dll in my project just to learn about it a little more.  Thanks very much to everyone.