554 views
in GUI Development by

Hello,

I tried to implement a menu on my GUI, inspired by the "menus" example available in Embedded Wizard.

I added in my items events from my physical inputs to interact with the menu but nevertheless, I have got problems dispite the fact that in the prototyper everything works just fine using the PC's keyboard:

  • The first problem is that the escape key does not execute the "OnExit" signal.
  • The second is more complex. Everytime I enter a sub-menu, I have all the available sub-menus loaded at once (and the sub-sub-menus). When I press the buttons to go down or up in my menu, I can see that the main menu and all the loaded sub-menus interact with that key.

The unit containing this menu and sub-menus is quite consequent, so I do not know which part of code to send.

Thank you for the help,

Krzysztof,

2 Answers

0 votes
by

Hello Krzysztof,

the description in your question about the simultanously controlled menus is confusing me. I have understood, that you have HW-buttons. How do you feed the button events to the GUI application? Do you use the way explained in Processing Key Events

May be you can post the code where the HW-button events are dispatched? Also you can post your project for evaluation purpose?

Best regards

Paul Banach

0 votes
by

Dear paul,

I did not know that it was possible to tell that a keyboard key was hit. So I tried to modify the menu implementation, to integrate my input.

I deleted my implementation, and added the use of the "DriveKeyboardHitting" method. but it does not work unfortunetelly. 

I implemented it in my function as: 

Application::Start.DriveKeyboardHitting(Core::KeyCode.Escape, '\0', bKey_Escape);

where Application::Start is my root component pointed by my profile. But in that case, I have the following error message:

[12.4.2019  8:51:20] Error ProjectClass::KeyManagement.OnSetbKey_Escape (8:20) : Unexpected type expression 'Application::Start' left to the method call 'DriveKeyboardHitting()'. Instead of the type a value expression is expected.

I guess I am missing something,

 

Nevertheless, to answer you question, the signal is read in a property with the OnGet as:

$if( (!$prototyper) && ($HW == MulticS) )
var int32 s32Status = 0;
var bool Value = false;

native( s32Status, Value )
{
  s32Status = s32MZed_eData_Get( EW_OutMenus_EnterSw, &Value, sizeof(Value) );
}

if( s32Status == 0 )
{
  pure EW_OutMenus_EnterSw = Value;
}
$endif

return pure EW_OutMenus_EnterSw;
//============================================================================//
// NAME : s32MZed_eData_Get
//============================================================================//
// ROLE : Get Zed Data
//----------------------------------------------------------------------------//
// INPUT  :
// OUTPUT :
//  0 : Succed
// -1 : Bad Id
// -2 : No Data
// -3 : Bad mapping
//============================================================================//
TS32 s32MZed_eData_Get(TU16 Fu16DataId, void *FpvData, TU16 Fu16DataSize)
{
	TS32 s32RetVal = Ds32MZed_iSuccess;
	TstMZed_iStructConf *pstDataStruct;
	TU16 u16Count;
	TU8	 u8Tmp;
	//TU16 u16APPZEDVersion;	

	//sanity check
	if(   (Fu16DataId >= Ceu16MZed_eLastId)
	   || (FpvData == 0)
	   || (pu8MZed_iData == 0) )
	{
		s32RetVal	= Ds32MZed_iError;
	}
	else
	{
		//Prepare environment if data is APP or GPU
		if(Fu16DataId < Ceu16MZed_eEndOfInputId)
		{
			pstDataStruct = CtstMZed_iInputsStructMap;
		}
		else if(Fu16DataId > Ceu16MZed_eEndOfInputId)
		{
			Fu16DataId -= (Ceu16MZed_eEndOfInputId + 1);
			pstDataStruct = CtstMZed_iOutputsStructMap;
		}
		else //if(Fu16DataId == Ceu16MZed_eEndOfInputId)
		{
			return(Ds32MZed_iError);	
		}

		//Check if data is a bitfield or a word array
		if( pstDataStruct[Fu16DataId].u16Size )
		{
			//Adaptive cast
			if( Fu16DataSize == sizeof(TU16) && (pstDataStruct[Fu16DataId].u16Size == sizeof(TU8)) )
			{
				*(TU16 *)FpvData = (TU16)pu8MZed_iData[pstDataStruct[Fu16DataId].u16Offset];
			}
			else if( (Fu16DataSize == sizeof(TU32)) && (pstDataStruct[Fu16DataId].u16Size == sizeof(TU16)) )
			{
				*(TU32 *)FpvData =	 ((TU32)pu8MZed_iData[pstDataStruct[Fu16DataId].u16Offset + 0]<<8)
									|((TU32)pu8MZed_iData[pstDataStruct[Fu16DataId].u16Offset + 1]<<0);
			}
			else if( (Fu16DataSize == sizeof(TU32)) && (pstDataStruct[Fu16DataId].u16Size == sizeof(TU8)) )
			{
				*(TU32 *)FpvData = (TU32)pu8MZed_iData[pstDataStruct[Fu16DataId].u16Offset];
			}
			else
			{
				//Copy data
				for( u16Count=0U; (u16Count<pstDataStruct[Fu16DataId].u16Size) && (u16Count<Fu16DataSize); u16Count++ )
				{
					((TU8 *)FpvData)[u16Count]=	pu8MZed_iData[u16Count + pstDataStruct[Fu16DataId].u16Offset];
				}
			}
		}
		else
		{
			//Copy bits
			u8Tmp = pu8MZed_iData[pstDataStruct[Fu16DataId].u16Offset];
			u8Tmp >>= pstDataStruct[Fu16DataId].u8Shift;
			u8Tmp &= pstDataStruct[Fu16DataId].u8Mask;

			//Adaptive cast
			if( Fu16DataSize == sizeof(TU16) )
			{
				*(TU16 *)FpvData = (TU16)u8Tmp;
			}
			else if( Fu16DataSize == sizeof(TU32) )
			{
				*(TU32 *)FpvData = (TU32)u8Tmp;
			}
			else
			{
				*(TU8 *)FpvData = u8Tmp;
			}
		}
	}

	return s32RetVal;
}

This is the way all our inputs are read, and it works, but till now we never used the menu implementation

 

Best regards,

Krzysztof,

by

Hello Krzysztof,

from your comment I understood, that you have tried to call the method DriveKeyboardHitting() from Chora code. In such case, this is (usually) not the right approach. DriveKeyboardHitting() is one of few methods intended to be called from the main-loop when keyboard events are received.

The article Main Loop describes the aspects of platform integration. There you see following C code. This code feeds the GUI application with an event generated by the keyboard:

/* ...and provide it to the application. */
if ( cmd != CoreKeyCodeNoKey )
{
  /* feed the application with a 'press' and 'release' event */
  events |= CoreRoot__DriveKeyboardHitting( rootObject, cmd, 0, 1 );
  events |= CoreRoot__DriveKeyboardHitting( rootObject, cmd, 0, 0 );
}

I have understood, that in your application you have never used the keyboard events as described above. All related events were dispatched in another way (e.g. by using notifyobservers?). In such case, you have surely some mechanisms implemented in your application to control the context of the actual interaction. For example, if your application shows an alert dialog, then the mechanisms have to to take care that as long as the alert is visible no other GUI components do react to the keyboard events.

The menu system (to work correctly in such case) has also to respect the actual context. In other words, if you present a sub menu, the superior menu has to 'deactivate' the processing of keyboard events. These mechanisms are not necessary if the keyboard events are dispatched by the DriveKeyboardEvents() method. The Mosaic framework takes care of the event dispatching by following the concept of so-called focus path.

From your answer I also understood, that you have tried to combine the both approaches. Concret you wanted to call DriveKeyboardHitting() from Chora code as reaction to a received keyboard notification. Well, this is possible. In such case, however, you have to call the method in context of the application root object. The caller has to know the root object. Can you implement the code to handle the notification directly within the application root class? Then you could call the method DriveKeyboardHitting() as follows:

// Feed a press and release event for the given key code.
DriveKeyboardHitting( Core::KeyCode.Escape, '\0', true );
DriveKeyboardHitting( Core::KeyCode.Escape, '\0', false );

Best regards

Paul Banach

Ask Embedded Wizard

Welcome to the question and answer site for Embedded Wizard users and UI developers.

Ask your question and receive answers from the Embedded Wizard support team or from other members of the community!

Embedded Wizard Website | Privacy Policy | Imprint

...