LabWindows/CVI

cancel
Showing results for 
Search instead for 
Did you mean: 

Tab control event Keypress

Solved!
Go to solution

Hello,

 

I'm using a Tab control and can't find out how to handle the following situation.

 

We know that when operating a Tab control we can jump from Tab to Tab by pressing <Ctrl-Tab>.

When at the last Tab I would like to jump to another conbtrol and not again to the first Tab.

 

Unfortunately in this situation <Ctrl-Tab> doesn't generate an EVENT_KEYPRESS.

 

Is there a way to handle this situation?

0 Kudos
Message 1 of 9
(5,402 Views)

I don't understand why you cannot get the keypress event: I have tried to modify TabExample example installing a callback on the tab control and properly get the keypress event on Ctrl+Tab. Here the code for the tab control callback function:

int CVICALLBACK TabCallback (int panel, int control, int event,
		void *callbackData, int eventData1, int eventData2)
{
  int	nextCtrl, lastTab, pageIdx, virtualKey, modifierKey;

  if (event == EVENT_KEYPRESS) {
    GetActiveTabPage (panel, control, &pageIdx);
    GetNumTabPages   (panel, control, &lastTab);
    lastTab--;		// Zero-based index
    virtualKey = eventData1 & VAL_VKEY_MASK;
    modifierKey = eventData1 & VAL_MODIFIER_KEY_MASK;
    // Properly handle Ctrl+Tab
    if (modifierKey == VAL_MENUKEY_MODIFIER && virtualKey == VAL_TAB_VKEY && pageIdx == lastTab) {
      GetCtrlAttribute (panel, PANEL_TAB, ATTR_NEXT_CTRL, &nextCtrl);
      SetActiveCtrl (panel, nextCtrl);
      return 1;  // Swallow the keypress event so that active page doesn't change
    }
  }

  return 0;
}

 

 

Alternatively, you can handle the situation inside a panel callback:

int CVICALLBACK PanelCallback (int panel, int event, void *callbackData,
  int	eventData1, int eventData2)
{
  int	lastTab, control, pageIdx, virtualKey, modifierKey, nextCtrl;

  if (event == EVENT_KEYPRESS) {
    if ((control = GetActiveCtrl (panel)) == PANEL_TAB) {
      GetActiveTabPage (panel, control, &pageIdx);
      GetNumTabPages   (panel, control, &lastTab);
      // eventData1: a 4-byte integer consisting of 3 fields: 0x00MMVVAA
      // MM = the modifier key, VV = the virtual key, AA = the ASCII key
      // key masks are defined in userint.h
      virtualKey = eventData1 & VAL_VKEY_MASK;
      modifierKey = eventData1 & VAL_MODIFIER_KEY_MASK;
      // Properly handle Ctrl+Tab
      if (modifierKey == VAL_MENUKEY_MODIFIER && virtualKey == VAL_TAB_VKEY && (pageIdx == lastTab - 1)) {
        GetCtrlAttribute (panel, PANEL_TAB, ATTR_NEXT_CTRL, &nextCtrl);
        SetActiveCtrl (panel, nextCtrl);
        return 1;
      }
    }
  }

  return 0;
}

 

 



Proud to use LW/CVI from 3.1 on.

My contributions to the Developer Community
________________________________________
If I have helped you, why not giving me a kudos?
0 Kudos
Message 2 of 9
(5,392 Views)

Thank you for your inputs.

But if a control is active on a tab page then <Ctrl-Tab> switches through the tabs without sending an EVENT_KEYPRESS.

Please see below

 

Tab Control.jpg

0 Kudos
Message 3 of 9
(5,383 Views)

I see. I cannot test it at the moment: I will make some test later this evening.

I can suppose that when the active control is e.g. the numeric the keypress event is sent to the numeric control callback, if any, and not to the tab control.

Nevertheless, keypress events are received from the panel callback as well, and I seem to remember that they are received there before the control callbacks, so you can try handling this particular key combination in the panel callback.



Proud to use LW/CVI from 3.1 on.

My contributions to the Developer Community
________________________________________
If I have helped you, why not giving me a kudos?
0 Kudos
Message 4 of 9
(5,374 Views)

After making some tests I can confirm your analysis: when pressing Ctrl+Tab on a control inside the panel, no KEYPRESS event is received from the control, from the tab control or from the panel owning the tab control. I tried also installing the main callback to see if I can detect some condition under which to trap that particular situation but with no success.

It is possible that that event is handled internally by the tab control and its events are not exposed to the system; I don't know how much native tab control inherits from the former EasyTab, but in that instrument code Ctrl+Tab key combination was specifically handled by swallowing its events: maybe the tab control operates in a similar way.

 

Handling the EVENT_ACTIVE_TAB_CHANGE is not a feasible solution since it is received after the tab page has already changed: even if you return to the previous page the user will notably see the page changes.



Proud to use LW/CVI from 3.1 on.

My contributions to the Developer Community
________________________________________
If I have helped you, why not giving me a kudos?
0 Kudos
Message 5 of 9
(5,369 Views)

This issue is recorded under known issue 241929 (it is not currently in the Known Issues List by mistake, but it will be there next time I revise the list). This is a limitation of the way our UI framework is designed. The problem is that <Ctrl>+Tab is a built-in hotkey for the Tab control. For hotkeys, the event goes straight to the control owning the hotkey as you suspected. For now, we do not intend to change this behavior because it is fundamental to our implementation of hotkeys.

 

We have not been able to find a work around to accomplish what you described. Could you provide some additional information about why this behavior is useful in your UI, and then maybe we can help come up with alternative solutions?

 

 

National Instruments
0 Kudos
Message 6 of 9
(5,313 Views)

Thank you for your answer.

 

My UI is seperated in different frames. Using the <Tab> key allows to jump from control to control.

But in order to go more quickly to the wanted control I have implemented <Ctrl>+<Tab> to jump from frame to frame.

 

The issue is that when I'm on the tab control I cannot get out of it with <Ctrl>+<Tab>.

main panel.jpg

Message 7 of 9
(5,303 Views)
Solution
Accepted by topic author Bertrand_ENAC

I believe I found a workaround. You can use InstallWinMsgCallback to install a callback for the panel and check for the WM_KEYDOWN message. This is a bit more involved because you will not receive eventData1 and eventData2 to tell you what key and modifier is being used, so you will have to check for the control key separately (I use a global flag to specify if CTRL is pressed).

 

In main, you will have to install the callback like so:

 

InstallWinMsgCallback (panelHandle, WM_KEYDOWN, MyCallback, VAL_MODE_INTERCEPT, NULL, &postHandle);

...
//in clean-up
RemoveWinMsgCallback (panelHandle, WM_KEYDOWN); 

 

Then in the callback, use the following code:

int CVICALLBACK MyCallback (int panelHandle, int message, unsigned int *wParam, unsigned int *lParam, void* callbackData)
{
	int	lastTab, control, pageIdx, nextCtrl;
	switch(message)
	{
		case WM_KEYDOWN:
			if(*wParam == VK_CONTROL)
			{
				ctrlDown = 1;
			}
			else if(*wParam == VK_TAB)
			{
				if ((control = GetActiveCtrl(panelHandle)) == PANEL_TAB) 
				{
					GetActiveTabPage (panelHandle, control, &pageIdx);
					GetNumTabPages   (panelHandle, control, &lastTab);
					if(pageIdx == lastTab - 1)
					{
						GetCtrlAttribute (panelHandle, PANEL_TAB, ATTR_NEXT_CTRL, &nextCtrl);
						SetCtrlAttribute(panelHandle, PANEL_TAB, ATTR_CTRL_INDEX, pageIdx); 
						SetActivePanel(panelHandle);
						SetActiveCtrl (panelHandle, nextCtrl);
						return 1;
					}
				}
			}
			break;
		case WM_KEYUP:
			if(*wParam == VK_CONTROL)
				ctrlDown = 0;
	}
	return 0;
}

 Note: You must call SetActivePanel before SetActiveCtrl to transfer focus from the tab page to the panel.

National Instruments
Message 8 of 9
(5,263 Views)

Thank you very munch

 

Bertrand

0 Kudos
Message 9 of 9
(5,236 Views)