Suppose I have a 2D array. It has four rows and four columns. Now I want that initially I place some marker in the array at some location. Say, array[x][y] = 1 -> marker. I want to move this marker in the array in 8 dimensions by using buttons. Like, on up, location is [x-1][y]. Down is [x+1][y]. Left is [x][y-1]. And right is [x][y+1]. Now I have my logic that this is how I will do it!
1st Question: How to associate my buttons of up down sideways to move in the array?
2nd Question: How will I tackle the other four dimensions as I'll be using two buttons for other complex 4 changing location as <^ two buttons are pressed and location now is [x-1][y-1]!
Kindly direct me or help me with the button associations.
You can use a keyboard hook to trigger your logic when the arrow keys are pressed. You would define a callback function containing code like:
if ( WM_KEYDOWN == wParam && VK_UP == lParam )
//do up logic
else if ( WM_KEYDOWN == wParam && VK_DOWN == lParam )
//do down logic
else if ....
For the diagonal buttons, you can use the home, pgup, pgdn, and end keys on the numeric keypad of the keyboard (this would require a keyboard with numeric keypad). These buttons correspond to the arrow combinations like <^, and would keep the implementation simple.
For information on how to use a keyboard hook, see this post:
C++ Win32 keyboard events
For list of virtual key codes (ie VK_UP) see this link:
http://msdn.microsoft.com/en-us/library/ms927178.aspx
Related
I need to intercept key pressings and other user actions in my RichEdit box. I found it too complex to intercept user input in WM_KEYDOWN or WM_CHAR since some of the key pressings fire WM_CHAR, some of them not and also it has some other problems.
So I decided to listen EN_UPDATE messages, cuz it is said that this event fires on every change and just before RichEdit control starts to redraw itself ( https://learn.microsoft.com/en-us/windows/desktop/controls/en-update ). Well it sounds like trustworthy mechanism which allows to intercept all the changes.
But I found that not every WM_KEYDOWN causes firing of EN_UPDATE. I rapidly pressed many buttons (usual "char" buttons like "d", "f" and so on, no special keys), and found that when I inputed 100 chars, and WM_KEYDOWN also fired 100 times, but EN_UPDATE fired only 96 times (the number of activations of EN_UPDATE varies, sometimes it equals to the number of keypressings, don't know what it depends on). The number of WM_KEYDOWN and the number of characters entered are always equal of course.
Here's the code:
BOOL CEditorView::OnCommand( WPARAM wParam, LPARAM lParam )
{
static long count = 0;
if( HIWORD( wParam) == EN_UPDATE )
{
if( (HWND)lParam == g_hwnd_RE )
{
if( g_allowProcessing )
{
count++;
}
}
}
return CDockablePane::OnCommand( wParam, lParam );
}
///// and WM_KEYDOWN
case WM_KEYDOWN:
{
g_testCount++;
return DefSubclassProc( hwnd, msg, wp, lp );
break;
}
Am I doing something wrong or is it just specific working style of EN_UPDATE? Like may be it accumulates changes when user input is too fast.
EN_UPDATE is sent when the control is about to redraw itself. This does not imply that the control has to update after each WM_KEYDOWN, the control might have some caching mechanism to update delaying when keys are down within a little margin, for example.
This is not standard per control, you may have a control that updates on each keypress, even if there is 1 ms delay between keys, and you may have a control that updates each second, no matter how many keys it gets. It depends on the control.
Therefore, if you really want to get notified of every key, you have to use WM_KEYDOWN. EN_UPDATE is usually used to take the current state of the control and update another control.
I'm self studying using the Pearson, Computer Graphics with OpenGL's book.
I'm currently trying to make a simple square move, but before I get ahead of myself I need to be sure I understand what keys are built into Glut.
I'm aware of the following keys:
GLUT_KEY_F1, GLUT_KEY_F2, ..., GLUT_KEY_F12 - F1 through F12 keys
GLUT_KEY_PAGE_UP, GLUT_KEY_PAGE_DOWN - Page Up and Page Down keys
GLUT_KEY_HOME, GLUT_KEY_END - Home and End keys
GLUT_KEY_LEFT, GLUT_KEY_RIGHT, GLUT_KEY_UP, GLUT_KEY_DOWN - Arrow
keys
GLUT_KEY_INSERT - Insert key
I either found them in my book or here on Stackoverflow in another post.
But are there any more? eg, for all keys on a keyboard and mouse?
Thanks.
glut divides key in keyboard by glutSpecialFunc w/c takes special keys such as F1,F2..., NUMPADS, etc. while glutKeyboardFunc takes all keys that can be represented by a character like the alphabets, numbers, ESC (27 in 'ASCII'), ENTER (32 in 'ASCII'), etc.
in summary, glutKeyboardFunc take char parameters that can be represented without using any '\' (backslash, like '\t', '\n') before any character the rest are handled by glutSpecialFunc
the keyboard have two sets of buttons: those that can be represented using ASCII code and those that could not. the ones that can be represented in ASCII returns 1 byte when pressed, the ones that couldn't return two bytes the first of which is NULL
glut abstract this by giving you two set of functions to handle keyboard events: one to handle normal ASCII standard buttons glutKeyboardFunc, the other to handle special two byte buttons glutSpecialFunc
the special function have constants for common keyboard special buttons :
GLUT_KEY_F1:0x0001,
GLUT_KEY_F2:0x0002,
GLUT_KEY_F3:0x0003,
GLUT_KEY_F4:0x0004,
GLUT_KEY_F5:0x0005,
GLUT_KEY_F6:0x0006,
GLUT_KEY_F7:0x0007,
GLUT_KEY_F8:0x0008,
GLUT_KEY_F9:0x0009,
GLUT_KEY_F10:0x000A,
GLUT_KEY_F11:0x000B,
GLUT_KEY_F12:0x000C,
GLUT_KEY_LEFT:0x0064,
GLUT_KEY_UP:0x0065,
GLUT_KEY_RIGHT:0x0066,
GLUT_KEY_DOWN:0x0067,
GLUT_KEY_PAGE_UP:0x0068,
GLUT_KEY_PAGE_DOWN:0x0069,
GLUT_KEY_HOME:0x006A,
GLUT_KEY_END:0x006B,
GLUT_KEY_INSERT:0x006C,
GLUT_KEY_REPEAT_OFF:0x0000,
GLUT_KEY_REPEAT_ON:0x0001,
GLUT_KEY_REPEAT_DEFAULT:0x0002.
mouse clicks can be handled with the glutMouseFunc and the constants associated with the mouse buttons are:
GLUT_LEFT_BUTTON:0x0000,
GLUT_MIDDLE_BUTTON:0x0001,
GLUT_RIGHT_BUTTON:0x0002
glut can also handle joysticks with the glutJoystickFunc which has the following constants:
GLUT_HAS_JOYSTICK:0x0264,
GLUT_OWNS_JOYSTICK:0x0265,
GLUT_JOYSTICK_BUTTONS:0x0266,
GLUT_JOYSTICK_AXES:0x0267,
GLUT_JOYSTICK_POLL_RATE:0x0268,
GLUT_JOYSTICK_BUTTON_A:0x0001,
GLUT_JOYSTICK_BUTTON_B:0x0002,
GLUT_JOYSTICK_BUTTON_C:0x0004,
GLUT_JOYSTICK_BUTTON_D:0x0008.
if you are using a gaming mouse or a keyboard/joystick with more buttons you can test for what each button returns by outputting the button pressed to the console then directly use this value in your code to know if one of those button is pressed
I have an empty win32 project.
CASE WM_CHAR:
under this case I need to store each keystroke in an array, then output it to the screen using
TextOut();
I figured it's going to be something like this:
char store[LARGE_NUMBER];
then under the case wm_char header I store the character in store then use a counter to move along the array for each key which is pressed. I just don't know how to record a specific key on the keyboard, not just any key - which calls the wm_char case.
Thanks
The wParam parameter holds the character code of the key that was pressed. Take a look at the documentation. lParam holds further information about the key press (was it a special key, was the key held down etc.).
I have 3 list control on one dialog box but only one is showing focus.
if i clicked on 2nd list control then focus disaappear from 1st one.
Means at a time only one list showing focus.
How to make focus remain on all list control on same dialog box?
I don't think that this is technically possible. 'Focus' is an attribute that can only be applied to an individual element.
Think of it in terms of 'focus' is the element that the user is currently interacting with. How would a user be expected to interact with 3 distinct elements at the same time?
As Brian says - focus can only be on one control at time. I'm guessing you are trying to change the other list controls based on the first list box. One way to do it is to associate a variable with each list control, like mListCtrl1, mListCtrl2. Then add a handler for the NM_CLICK event, and have some code like this:
void CTabTestDlg::OnNMClickList3(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMITEMACTIVATE pNMItemActivate = (LPNMITEMACTIVATE)(pNMHDR);
// TODO: Add your control notification handler code here
*pResult = 0;
UpdateData(true);
DWORD dwData = mListCtrl1.GetItemData(pNMItemActivate->iItem);
int max = mListCtrl2.GetItemCount();
for (int i=0;i<max;i++)
{
DWORD dwData2 = mListCtrl2.GetItemData(i);
if (dwData==dwData2)
{
mListCtrl2.SetItemState(i,LVIS_SELECTED,LVIS_SELECTED);
break;
}
}
UpdateData(false);
}
Note that I have the control set to "Always show selection", and "Single selection"
I hope that I can explain my problem well enough for someone to help.
Basically, I have a horizontal scrollbar (ranged 0 to 1000) and an edit control that represents the position of the scrollbar divided by 1000, so that the user can use either the scrollbar to select a range of numbers between 0 and 1 up to a 3 decimal precision (.001, .002, ..., .987, etc.), or enter their own number in the edit box. As they scroll the scrollbar, the number in the edit control changes to reflect the new scroll position. When a new number is entered, the scrollbar sets itself to a new position reflecting the number entered. Meanwhile I also perform some calculations with this number as it changes (through either the scrollbar or the edit control) and display the results in another dialog.
Here is my problem: I'm having trouble deciding which event handlers to use to produce the proper behavior when a user enters a number into the edit control.
I'm using a double value variable called fuelMargin to handle my edit control and a CScrollBar control variable called fuelScroll to handle the scrollbar.
In my HSCROLL event I set the edit control to the scroll position / 1000. No problems there; when the user scrolls the scrollbar the edit box is correctly updated.
As for the edit box, my first attempt was an ONCHANGE event:
void MarginDlg::OnEnChangeFueledit()
{
CEdit* editBox;
editBox = (CEdit*)GetDlgItem(IDC_FUELEDIT);
CString editString;
editBox->GetWindowText(editString);
if (editString.Compare(".") != 0 && editString.Compare("0.") != 0
&& editString.Compare(".0") != 0 && editString.Compare("0.0") != 0
&& editString.Compare(".00") != 0 && editString.Compare("0.00") != 0)
{
UpdateData();
UpdateData(FALSE);
if (fuelMargin > 1)
{
UpdateData();
fuelMargin = 1;
UpdateData(FALSE);
}
if (fuelMargin < 0)
{
UpdateData();
fuelMargin = 0;
UpdateData(FALSE);
}
fuelScroll.SetScrollPos(int(fuelMargin*1000));
}
}
I needed that first if statement in there to keep from doing an UpdateData() when the user is trying to type a number like .5 or .05 or .005. It does produce a few wonky behaviors, though; when the user tries to type something like .56, after the .5 an UpdateData() is performed, the number becomes 0.5, and the cursor is moved to the far left, so if they tried to type .56 they would accidentally end up typing 60.5 -- which goes to 1, since I won't let them enter numbers lower than 0 or higher than 1. If they enter 0.56, however, this behavior is avoided.
For my second attempt, I commented out my ONCHANGE event and put in an ONKILLFOCUS event instead:
void MarginDlg::OnEnKillfocusFueledit()
{
UpdateData();
UpdateData(FALSE);
if (fuelMargin > 1)
{
UpdateData();
fuelMargin = 1;
UpdateData(FALSE);
}
if (fuelMargin < 0)
{
UpdateData();
fuelMargin = 0;
UpdateData(FALSE);
}
fuelScroll.SetScrollPos(int(fuelMargin*1000));
}
So now the user can finish typing their number and all is hunky dory--as long as they click out of the edit box. The scrollbar won't move and results won't be calculated until the box loses focus.
I want the results to be calculated as the numbers in the box are being typed; I want the scrollbar to move as the numbers are being typed. But I don't want typing to be disrupted, i.e. the actual numbers in the box changed or the cursor moved in any way.
Suggestions?
Thanks!
With the first approach, it looks like you're almost there: the only really significant problem is that the repeated calls to UpdateData() mess with the cursor position as the user is typing.
Given that you're trying to have a reasonably complex interaction between the controls, what I'd suggest is not to do validation in the OnChange() at all, so that as the user is typing he can type what he wants (which is how most numeric edit controls work anyway). When the user closes the dialog the controls are on (or clicks a button that uses the data in some way) then validation should be triggered, and a suitable error shown.
Once you're free from validating in OnChange(), you can fix the "cursor moves" problem by simply not calling UpdateData() in OnChange(). Instead, just parse the number from "editString" and, if it's in the valid range, update the scrollbar. That way, the scrollbar updates as the user types, and if they type in an invalid value the scrollbar stays put, and they'll get an error when they move to whatever the next stage is. Something like this (not tested):
void MarginDlg::OnEnChangeFueledit()
{
CString editString;
GetDlgItem(IDC_FUELEDIT)->GetWindowText(editString);
double editValue;
if ((sscanf(editString,"%lf",&editValue) == 1)
{
if (editValue >= 0.0) && (editValue <= 1.0))
fuelScroll.SetScrollPos(int(editValue*1000));
}
}
The only remaining important problem to note is that, if the user types some invalid value, or a number out of the valid range, then the edit control and the scrollbar will be out of sync. The simplest way to deal with that is to just decide that the edit control is the "master" value: that is, when we want to know what the user entered, we always look at the edit control, not the scrollbar, and validate data.
As for your second approach, one possible solution might be to implement a timer message handler: in the timer handler you could say the equivalent of "if the user hasn't typed anything for a second, I'll assume they're done, and parse the number and update the scrollbar". I'm not so keen on that as a solution, though.
I'd suggest watching for the Enter key, and performing UpdateData() then as well as OnKillFocus and OnChange. The more user-friendly the better.
Next, make sure your UpdateData() routine only works in the direction you need:
If ".5" is entered in the edit control, run your UpdateData() routine when the OnChange event is raised, but make sure to update your scrollbar only. Don't worry about updating the edit control to "0.5" until OnKillFocus is raised. Any updates in the reverse direction (to the edit control) will mess with your cursor. If your edit control is somehow bound to this double variable and auto updates when the var changes, consider leaving the double and your edit control seperate from each other until the OnKillFocus event is raised.
The same concept applies in the other direction as well. When the user scrolls, don't mess with the scrollbar. Just update the edit control and leave it at that.
I should add that XAML's data-binding features really help in situations like this, if you know how to use them properly. It's unfortunate for us native-type developers that it's so difficult to implement similar functionality using only event handlers.