GLFW Keyboard events only registering when I've clicked on the screen - glfw

I have a piece of code that performs some keyboard event functions:
void
KeyboardCallback(GLFWwindow */*window*/, int key, int /*scancode*/, int action,
int /*mods*/)
{
if (( action == GLFW_PRESS|| action == GLFW_REPEAT ) && key == GLFW_KEY_X) {
camera_z = camera_z + (0.1*camera_z);
}
if (( action == GLFW_PRESS|| action == GLFW_REPEAT ) && key == GLFW_KEY_Z) {
if (camera_z >= 0.01) {
camera_z = camera_z - (0.1*camera_z);
}
}
}
However, the output only appears once I've clicked on the window once. Why is this happening? Is there a way to rectify this?

It seems, that your window does not have the input focus. Normally, the window will get the focus when it is shown on screen.
You're able to control this behaviour via window hints (before creation):
GLFW_FOCUSED specifies whether the windowed mode window will be given input focus when created
GLFW_FOCUS_ON_SHOW specifies whether the window will be given input focus when glfwShowWindow is called
To set the input focus at any time, call: glfwFocusWindow

Related

GLFW switching boolean toggle

I am using GLFW for keyboard input but the processing happens too quick thus my boolean switch on a single press gets changed like 10 times, as input is processed every frame. All I need that for a single press of space bar it would switch the state. My current code is below:
if (glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS)
{
show = !show;
}
Is there a better way of doing this?
Yes. glfwGetKey is meant to be used for continuous key input. GLFW manual lists glfwSetKeyCallback as a better alternative if you want one-time notification about key press.
Thus, for your case it'd be something like this:
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
if (key == GLFW_KEY_SPACE && action == GLFW_PRESS)
show = !show;
}
If you don't want to use this method for whatever reason, you can always implement a similar thing yourself. You'll need a boolean value (or array of values) representing the key state. Then, in your input handling, you must only react on the change of the button state, like so:
bool spacePressed;
// in handling
bool spaceCurrentlyPressed = glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS;
if (!spacePressed && spaceCurrentlyPressed) { // wasn't before, is now
show = !show;
}
spacePressed = spaceCurrentlyPressed;
I reccommend using GLFWs key callbacks instead of getting the key state yourself every frame. This way you will only receive one keypress and one keyrelease event per key.
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
if(action == GLFW_RELEASE) return; //only handle press events
if(key == GLFW_KEY_SPACE) show = !show;
}
//in main or init
glfwSetKeyCallback(window, key_callback);

CMFCToolBarComboBoxEdit handle delete button

CMFCToolBarComboBoxEdit handles the BackSpace button but it doesn't handle the delete button.
Is there any way to handle the delete button except PreTranslateMessage?
if yes, what is this way?
if no, then how can I get the current cursor position in the control and how to remove specific char using its index so I can remove the char which on the right of the cursor if nothing is selected?
Thanks in advance.
Yes use, PreTranslateMessage. If you detected the sequence that should be handled, call:
if (..) // Check if you have a message that should
// be passed to the window directly
{
TranslateMessage(pMsg);
DispatchMessage(pMsg);
return TRUE;
}
You can do this always in PreTranslateMessage, when you detect that the message should be handled by the default control, and should not be handled by any other control in the chain of windows that execute PreTranslateMessage. This is also helpful if you have a combo box open and want the Page Down/Up handled internally and not by the view or any accelerator.
I've handled the delete key in the PreTranslateMessage as follows:
BOOL PreTranslateMessage(MSG* pMsg)
{
if(WM_KEYDOWN == pMsg->message && VK_DELETE == pMsg->wParam)
{
int iStartChar = -1, iEndChar = -1;
GetSel(iStartChar, iEndChar);
if(iStartChar != iEndChar)
Clear(); //clear the selected text
else
{
SetSel(iStartChar, iStartChar + 1);
Clear();
}
}
return CMFCToolBarComboBoxEdit::PreTranslateMessage(pMsg);
}

most reliable mouse click check

How can I properly check on Windows if some user has clicked some button? At the moment I have following click-check code:
bool cButton::isCursorCrossing ( ) const
{
int posx, posy;
g_pVGuiSurface->SurfaceGetCursorPos ( posx, posy );
if ( posx > m_render_x && posx < m_render_x + buttonSize )
{
if ( posy > m_render_y && posy < m_render_y + buttonSize )
{
return true;
}
}
return false;
}
bool cButton::isClicked ( ) const
{
if ( isCursorCrossing ( ) )
{
if ( GetAsyncKeyState ( 0x01 ) & 1 )
{
return true;
}
}
return false;
}
but it sometimes does not work - I have to click button 5 to 10 times to see result, I think this is caused by GetAsyncKeyState.
You need to switch to a event-like system, instead of polling. GetAsyncKeyState will tell you if the mouse button is down at the very moment you call it. It has no memory to report if the user has recently clicked. So it's natural that it won't work reliably. Your app is not responding to user actions, it's only by coincidence when it happens to line up.
Windows sends messages to your application so you can reliably handle events. In the case of a mouse button click, your window will receive WM_LBUTTONDOWN and WM_LBUTTONUP.
Either find a way to handle these messages yourself, or figure out how your framework can forward you these events.
Well the most reliable is to use messages. The OS sends messages when an event eg. A mouse click occurs or a button on the keyboard is pressed/released.
So if you look into "Windows message loop" you will probably fond the answer. Night me allt to take in at first but it's every good knowledge for Windows programming.

How to react to LVN_ITEMCHANGED notification only when user finishes selecting action on multipe selection CListCtrl?

I have a dialog with two list controls and one custom control with some graphic preview.
The first has a list of one kind of entities (1a, 1b, 1c,...) and the second has a list of another kind of entites (2a, 2b, 2c,...), both of them are multi-select.
I want to allow user to select a set of entities that will be highlighted on preview, but only those from a list where the last selection has been made.
For example:
select 1a,1b,1c -> highlight them on preview
select 2a,2b,2c -> unhighlight 1a,1b,1c and highlight 2a,2b,2c
If I process each LVN_ITEMCHANGED notification, the preview will be flickering, so I want to paint the preview when user finishes selection with a function like this:
void CPreviewPage::PaintSelection(HWND hWnd)
{
m_preview.DeselectAll();
SelectArray select;
if(hWnd == m_lstFirst.GetSafeHwnd())
{
for(int i = 0; i < m_lstFirst.GetItemCount(); i++)
{
if( m_lstFirst.GetItemState(i, LVNI_SELECTED) & LVNI_SELECTED)
{
Entity *pEnt = (Entity *) m_lstFirst.GetItemData(i);
select.append(pEnt);
}
}
}
else
if(hWnd == m_lstSecond.GetSafeHwnd())
{
for( int i = 0; i < m_lstSecond.GetItemCount(); i++ )
{
if( m_lstSecond.GetItemState(i, LVNI_SELECTED) & LVNI_SELECTED)
{
Entity *pEnt = (Entity *) m_lstSecond.GetItemData(i);
select.append(pEnt);
}
}
}
m_preview.PaintSelect(&select);
}
The problem is; when I have 2a selected, then hold shift and click 2c (to select 2a-2c), I get multiple LVN_ITEMCHANGED and can't detect which of them is last. If I could, then it would be possible to repaint the preview at the right moment, which is when the user finishes his/her selecting action.
I tried to call the repaint function when I get LVNI_FOCUSED:
void CPreviewPage::OnLstSecondSelChanged(NMHDR *pNMHDR, LRESULT *pResult)
{
NM_LISTVIEW* pNMListView = (NM_LISTVIEW*) pNMHDR;
if((pNMListView->uChanged & LVIF_STATE) && (pNMListView->uNewState & LVNI_FOCUSED) )
PaintSelection(pNMHDR->hwndFrom);
}
However, the LVNI_FOCUSED isn't guaranteed to be the last, and I don't want to add a button to call PaintSelection function.
So the question is: when is the right moment when I will have the state of all items set, according to user selection so I can call PaintSelection?

Global alt+space hotkey grabbing - weird keyboard focus behaviour

I'm grabbing Alt+Space global hotkey using xcb_grab_key, as follows:
xcb_key_symbols_t *keysyms = xcb_key_symbols_alloc(c);
xcb_keycode_t *keycodes = xcb_key_symbols_get_keycode(keysyms, XK_space), keycode;
// add bindings for all screens
xcb_screen_iterator_t iter;
iter = xcb_setup_roots_iterator (xcb_get_setup (c));
for (; iter.rem; xcb_screen_next (&iter)) {
int i = 0;
while(keycodes[i] != XCB_NO_SYMBOL) {
keycode = keycodes[i];
xcb_grab_key(c, true, iter.data->root, XCB_MOD_MASK_ANY, keycode, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_SYNC);
i += 1;
}
}
Then in Qt's QAbstractNativeEventFilter subclass I process it and emit a Qt signal if key matches Alt+Space:
xcb_keycode_t *keycodes = xcb_key_symbols_get_keycode(keysyms, XK_space);
int i = 0;
bool found = false;
while(keycodes[i] != XCB_NO_SYMBOL) {
if(event->detail == keycodes[i]) {
if(event->state & GetModifier(c, keysyms, XK_Alt_L) || event->state & GetModifier(c, keysyms, XK_Alt_R)) {
xcb_allow_events(c, XCB_ALLOW_ASYNC_KEYBOARD, event->time);
emit gotHotKey();
found = true;
} else {
xcb_allow_events(c, XCB_ALLOW_REPLAY_KEYBOARD, event->time);
}
break;
}
i += 1;
}
if(found) return true;
(GetModifier is copied from VLC but I think this part doesn't matter since Alt-key is matched correctly)
The problem I'm having is that after show()ing main window when the hotkey is pressed, keyboard is most of the times1 not focused properly. I can type, but the cursor is not visible, input's border is not highlighted, and the shortcut Ctrl+Q for quitting desn't work. It can be worked around by moving the window, or pressing space - then focus is restored - cursor+border reappears and Ctrl+Q works. What might be causing this behaviour?
I'm using Qt 5.0.0 and xcb 1.8.1. Complete application can be downloaded for compiling from github.
1 it means sometimes the issue is not reproducible - focus is set correctly even for repeated window hide/shows, but then other times it happens multiple times in a row of hide/shows. It occurs more often than not overall.
(Edit: I've implemented a (very ugly...) workaround, so to reproduce the issue for the github project, the following code needs to be removed)
#ifndef WIN32
// Very ugly workaround for the problem described at http://stackoverflow.com/questions/14553810/
// (just show and hide a modal dialog box, which for some reason restores proper keyboard focus)
hackDialog.setGeometry(0, 0, 0, 0);
hackDialog.setModal(true);
hackDialog.show();
QTimer::singleShot(100, &hackDialog, SLOT(reject()));
#endif