Difference between revisions of "TextFieldFilters"

From X-Plane SDK
Jump to: navigation, search
m (1 revision)
 
Line 1: Line 1:
{{unreviewed_sdk_import}}These filters are from XSquawkBox - they are tested and in a shipping plugin.
+
=Keyboard Filters=
 +
These filters are from XSquawkBox - they are tested and in a shipping plugin.
  
 
These filters take the form of a widget function and a helper function that attaches them - a simple way to specialize widget behavior.
 
These filters take the form of a widget function and a helper function that attaches them - a simple way to specialize widget behavior.
 
+
==Protecting from null characters==
----
+
! Protecting from null characters
+
 
Older versions of the SDK sometimes sent null characters to text fields, crashing the sim.  This small snippet protects a widget from this.  This is unneeded for newer versions of X-Plane.
 
Older versions of the SDK sometimes sent null characters to text fields, crashing the sim.  This small snippet protects a widget from this.  This is unneeded for newer versions of X-Plane.
  
Line 13: Line 12:
 
                                   long                inParam2)
 
                                   long                inParam2)
 
  {
 
  {
if (inMessage == xpMsg_KeyPress)
+
if (inMessage == xpMsg_KeyPress)
{
+
{
char theChar = KEY_CHAR(inParam1);
+
char theChar = KEY_CHAR(inParam1);
 
+
if (theChar == 0)
+
if (theChar == 0)
return 1; // Eat the null char!
+
return 1; // Eat the null char!
}
+
}
return 0;
+
return 0;
 
  }
 
  }
 
+
 
  void ProtectTextWidget(XPWidgetID inWidgetID)
 
  void ProtectTextWidget(XPWidgetID inWidgetID)
 
  {
 
  {
XPAddWidgetCallback(inWidgetID, WidgetFunc_EatNullChars);
+
XPAddWidgetCallback(inWidgetID, WidgetFunc_EatNullChars);
 
  }
 
  }
----
+
== Cut Copy and Paste with the OS ==
! Cut Copy and Paste with the OS
+
 
This attaches control V, C, and X as cut/copy/patste.  It works on Mac and Windows.
 
This attaches control V, C, and X as cut/copy/patste.  It works on Mac and Windows.
  
Line 34: Line 32:
 
  {
 
  {
 
  #if IBM
 
  #if IBM
HGLOBAL  hglb;
+
HGLOBAL  hglb;
LPTSTR    lptstr;
+
LPTSTR    lptstr;
bool retVal = false;
+
bool retVal = false;
static XPLMDataRef hwndDataRef = XPLMFindDataRef("sim/operation/windows/system_window");
+
static XPLMDataRef hwndDataRef = XPLMFindDataRef("sim/operation/windows/system_window");
HWND hwndMain = (HWND) XPLMGetDatai(hwndDataRef);
+
HWND hwndMain = (HWND) XPLMGetDatai(hwndDataRef);
 
+
if (!IsClipboardFormatAvailable(CF_TEXT))
+
if (!IsClipboardFormatAvailable(CF_TEXT))
return false;
+
return false;
 
+
if (!OpenClipboard(hwndMain))
+
if (!OpenClipboard(hwndMain))
return false;
+
return false;
 
+
hglb = GetClipboardData(CF_TEXT);
+
hglb = GetClipboardData(CF_TEXT);
if (hglb != NULL)
+
if (hglb != NULL)
{
+
{
lptstr = (LPSTR)GlobalLock(hglb);
+
lptstr = (LPSTR)GlobalLock(hglb);
if (lptstr != NULL)
+
if (lptstr != NULL)
{
+
{
outText = lptstr;
+
outText = lptstr;
GlobalUnlock(hglb);
+
GlobalUnlock(hglb);
  retVal = true;
+
  retVal = true;
}
+
}
}
+
}
 
+
CloseClipboard();
+
CloseClipboard();
 
+
return retVal;
+
return retVal;
 
  #endif
 
  #endif
 
  #if APL
 
  #if APL
ScrapRef scrap;
+
ScrapRef scrap;
if (::GetCurrentScrap(&scrap) != noErr)
+
if (::GetCurrentScrap(&scrap) != noErr)
return false;
+
return false;
 
+
SInt32 byteCount = 0;
+
SInt32 byteCount = 0;
OSStatus status = ::GetScrapFlavorSize(scrap, kScrapFlavorTypeText, &byteCount);
+
OSStatus status = ::GetScrapFlavorSize(scrap, kScrapFlavorTypeText, &byteCount);
if (status != noErr)
+
if (status != noErr)
return false;
+
return false;
 
+
outText.resize(byteCount);
+
outText.resize(byteCount);
 
+
return (::GetScrapFlavorData(scrap, kScrapFlavorTypeText, &byteCount, &*outText.begin() ) == noErr);
+
return (::GetScrapFlavorData(scrap, kScrapFlavorTypeText, &byteCount, &*outText.begin() ) == noErr);
 
  #endif
 
  #endif
 
  }
 
  }
 
+
 
  bool XSBSetTextToClipboard(const std::string& inText)
 
  bool XSBSetTextToClipboard(const std::string& inText)
 
  {
 
  {
 
  #if IBM
 
  #if IBM
LPTSTR  lptstrCopy;
+
LPTSTR  lptstrCopy;
HGLOBAL hglbCopy;
+
HGLOBAL hglbCopy;
static XPLMDataRef hwndDataRef = XPLMFindDataRef("sim/operation/windows/system_window");
+
static XPLMDataRef hwndDataRef = XPLMFindDataRef("sim/operation/windows/system_window");
HWND hwndMain = (HWND) XPLMGetDatai(hwndDataRef);
+
HWND hwndMain = (HWND) XPLMGetDatai(hwndDataRef);
 
+
if (!OpenClipboard(hwndMain))
+
if (!OpenClipboard(hwndMain))
return false;
+
return false;
EmptyClipboard();
+
EmptyClipboard();
 
+
hglbCopy = GlobalAlloc(GMEM_MOVEABLE, sizeof(TCHAR) * (inText.length() + 1));
+
hglbCopy = GlobalAlloc(GMEM_MOVEABLE, sizeof(TCHAR) * (inText.length() + 1));
if (hglbCopy == NULL)
+
if (hglbCopy == NULL)
{
+
{
CloseClipboard();
+
CloseClipboard();
return false;
+
return false;
}
+
}
 
+
lptstrCopy = (LPSTR)GlobalLock(hglbCopy);
+
lptstrCopy = (LPSTR)GlobalLock(hglbCopy);
strcpy(lptstrCopy, inText.c_str());
+
strcpy(lptstrCopy, inText.c_str());
GlobalUnlock(hglbCopy);
+
GlobalUnlock(hglbCopy);
 
+
SetClipboardData(CF_TEXT, hglbCopy);
+
SetClipboardData(CF_TEXT, hglbCopy);
CloseClipboard();
+
CloseClipboard();
return true;
+
return true;
 
  #endif
 
  #endif
 
  #if APL
 
  #if APL
ScrapRef scrap;
+
ScrapRef scrap;
if (::ClearCurrentScrap() != noErr) return false;
+
if (::ClearCurrentScrap() != noErr) return false;
if (::GetCurrentScrap(&scrap) != noErr) return false;
+
if (::GetCurrentScrap(&scrap) != noErr) return false;
 
+
return ::PutScrapFlavor( scrap, kScrapFlavorTypeText, kScrapFlavorMaskNone, inText.size(), &*inText.begin()) == noErr;
+
return ::PutScrapFlavor( scrap, kScrapFlavorTypeText, kScrapFlavorMaskNone, inText.size(), &*inText.begin()) == noErr;
 
+
 
  #endif
 
  #endif
 
  }
 
  }
 
+
 
  static int WidgetFunc_CutCopyPaste(
 
  static int WidgetFunc_CutCopyPaste(
 
                                   XPWidgetMessage      inMessage,
 
                                   XPWidgetMessage      inMessage,
Line 121: Line 119:
 
                                   long                inParam2)
 
                                   long                inParam2)
 
  {
 
  {
if (inMessage == xpMsg_KeyPress)
+
if (inMessage == xpMsg_KeyPress)
{
+
{
char theChar = KEY_VKEY(inParam1);
+
char theChar = KEY_VKEY(inParam1);
XPLMKeyFlags flags = KEY_FLAGS(inParam1);
+
XPLMKeyFlags flags = KEY_FLAGS(inParam1);
 
+
if ((flags & (xplm_DownFlag + xplm_ControlFlag)) == (xplm_DownFlag + xplm_ControlFlag))
+
if ((flags & (xplm_DownFlag + xplm_ControlFlag)) == (xplm_DownFlag + xplm_ControlFlag))
{
+
{
long selStart = XPGetWidgetProperty(inWidget, xpProperty_EditFieldSelStart, NULL);
+
long selStart = XPGetWidgetProperty(inWidget, xpProperty_EditFieldSelStart, NULL);
long selEnd = XPGetWidgetProperty(inWidget, xpProperty_EditFieldSelEnd, NULL);
+
long selEnd = XPGetWidgetProperty(inWidget, xpProperty_EditFieldSelEnd, NULL);
long strLen = XPGetWidgetDescriptor(inWidget, NULL, 0);
+
long strLen = XPGetWidgetDescriptor(inWidget, NULL, 0);
std::string txt;
+
std::string txt;
txt.resize(strLen);
+
txt.resize(strLen);
XPGetWidgetDescriptor(inWidget, &*txt.begin(), txt.size()+1);
+
XPGetWidgetDescriptor(inWidget, &*txt.begin(), txt.size()+1);
if (theChar == XPLM_VK_V)
+
if (theChar == XPLM_VK_V)
{
+
{
std::string scrap;
+
std::string scrap;
if (XSBGetTextFromClipboard(scrap) && !scrap.empty())
+
if (XSBGetTextFromClipboard(scrap) && !scrap.empty())
{
+
{
if ((selEnd > selStart) && (selStart >= 0) && (selEnd <= strLen))
+
if ((selEnd > selStart) && (selStart >= 0) && (selEnd <= strLen))
{
+
{
txt.replace(selStart, selEnd - selStart, scrap);
+
txt.replace(selStart, selEnd - selStart, scrap);
XPSetWidgetDescriptor(inWidget, txt.c_str());
+
XPSetWidgetDescriptor(inWidget, txt.c_str());
XPSetWidgetProperty(inWidget, xpProperty_EditFieldSelStart, selStart + scrap.size());
+
XPSetWidgetProperty(inWidget, xpProperty_EditFieldSelStart, selStart + scrap.size());
XPSetWidgetProperty(inWidget, xpProperty_EditFieldSelEnd, selStart + scrap.size());
+
XPSetWidgetProperty(inWidget, xpProperty_EditFieldSelEnd, selStart + scrap.size());
} else if ((selStart >= 0) && (selStart <= strLen)) {
+
} else if ((selStart >= 0) && (selStart <= strLen)) {
txt.insert(selStart, scrap);
+
txt.insert(selStart, scrap);
XPSetWidgetDescriptor(inWidget, txt.c_str());
+
XPSetWidgetDescriptor(inWidget, txt.c_str());
XPSetWidgetProperty(inWidget, xpProperty_EditFieldSelStart, selStart + scrap.size());
+
XPSetWidgetProperty(inWidget, xpProperty_EditFieldSelStart, selStart + scrap.size());
XPSetWidgetProperty(inWidget, xpProperty_EditFieldSelEnd, selStart + scrap.size());
+
XPSetWidgetProperty(inWidget, xpProperty_EditFieldSelEnd, selStart + scrap.size());
}
+
}
}
+
}
return 1;
+
return 1;
}
+
}
if ((theChar == XPLM_VK_C) || (theChar == XPLM_VK_X))
+
if ((theChar == XPLM_VK_C) || (theChar == XPLM_VK_X))
{
+
{
if ((selStart >= 0) && (selStart < selEnd) && (selEnd <= strLen))
+
if ((selStart >= 0) && (selStart < selEnd) && (selEnd <= strLen))
{
+
{
std::string scrap = txt.substr(selStart, selEnd - selStart);
+
std::string scrap = txt.substr(selStart, selEnd - selStart);
if (XSBSetTextToClipboard(scrap) && (theChar == XPLM_VK_X))
+
if (XSBSetTextToClipboard(scrap) && (theChar == XPLM_VK_X))
{
+
{
txt.erase(selStart, selEnd - selStart);
+
txt.erase(selStart, selEnd - selStart);
XPSetWidgetDescriptor(inWidget, txt.c_str());
+
XPSetWidgetDescriptor(inWidget, txt.c_str());
XPSetWidgetProperty(inWidget, xpProperty_EditFieldSelEnd, selStart);
+
XPSetWidgetProperty(inWidget, xpProperty_EditFieldSelEnd, selStart);
}
+
}
}
+
}
return 1;
+
return 1;
}
+
}
}
+
}
}
+
}
return 0;
+
return 0;
 
  }
 
  }
 
+
 
  void AttachCutCopyPaste(XPWidgetID inWidget)
 
  void AttachCutCopyPaste(XPWidgetID inWidget)
 
  {
 
  {
XPAddWidgetCallback(inWidget, WidgetFunc_CutCopyPaste);
+
XPAddWidgetCallback(inWidget, WidgetFunc_CutCopyPaste);
}
+
  }
 +
[[Category:Code Snippets]]

Latest revision as of 20:49, 20 April 2009

Keyboard Filters

These filters are from XSquawkBox - they are tested and in a shipping plugin.

These filters take the form of a widget function and a helper function that attaches them - a simple way to specialize widget behavior.

Protecting from null characters

Older versions of the SDK sometimes sent null characters to text fields, crashing the sim. This small snippet protects a widget from this. This is unneeded for newer versions of X-Plane.

static	int	WidgetFunc_EatNullChars(
                                  XPWidgetMessage      inMessage,
                                  XPWidgetID           inWidget,
                                  long                 inParam1,
                                  long                 inParam2)
{
	if (inMessage == xpMsg_KeyPress)
	{
		char	theChar = KEY_CHAR(inParam1);

		if (theChar == 0)
			return 1;	// Eat the null char!
	}
	return 0;
}

void	ProtectTextWidget(XPWidgetID inWidgetID)
{
	XPAddWidgetCallback(inWidgetID, WidgetFunc_EatNullChars);
}

Cut Copy and Paste with the OS

This attaches control V, C, and X as cut/copy/patste. It works on Mac and Windows.

bool	XSBGetTextFromClipboard(std::string& outText)
{
#if IBM
		HGLOBAL   	hglb;
		LPTSTR    	lptstr;
		bool		retVal = false;
		static XPLMDataRef hwndDataRef = XPLMFindDataRef("sim/operation/windows/system_window");
		HWND hwndMain = (HWND) XPLMGetDatai(hwndDataRef);

	if (!IsClipboardFormatAvailable(CF_TEXT))
		return false;

	if (!OpenClipboard(hwndMain))
		return false;

	hglb = GetClipboardData(CF_TEXT);
	if (hglb != NULL)
	{
		lptstr = (LPSTR)GlobalLock(hglb);
		if (lptstr != NULL)
		{
			outText = lptstr;
			GlobalUnlock(hglb);
  			retVal = true;
		}
	}

	CloseClipboard();

	return retVal;
#endif
#if APL
		ScrapRef	scrap;
	if (::GetCurrentScrap(&scrap) != noErr)
		return false;

	SInt32		byteCount = 0;
	OSStatus	status = ::GetScrapFlavorSize(scrap, kScrapFlavorTypeText, &byteCount);
	if (status != noErr)
		return false;

	outText.resize(byteCount);

	return (::GetScrapFlavorData(scrap, kScrapFlavorTypeText, &byteCount, &*outText.begin() ) == noErr);
#endif
}

bool	XSBSetTextToClipboard(const std::string& inText)
{
#if IBM
		LPTSTR  lptstrCopy;
		HGLOBAL hglbCopy;
		static XPLMDataRef hwndDataRef = XPLMFindDataRef("sim/operation/windows/system_window");
		HWND hwndMain = (HWND) XPLMGetDatai(hwndDataRef);

	if (!OpenClipboard(hwndMain))
		return false;
	EmptyClipboard();

	hglbCopy = GlobalAlloc(GMEM_MOVEABLE, sizeof(TCHAR) * (inText.length() + 1));
	if (hglbCopy == NULL)
	{
		CloseClipboard();
		return false;
	}

	lptstrCopy = (LPSTR)GlobalLock(hglbCopy);
	strcpy(lptstrCopy, inText.c_str());
	GlobalUnlock(hglbCopy);

	SetClipboardData(CF_TEXT, hglbCopy);
	CloseClipboard();
	return true;
#endif
#if APL
	ScrapRef	scrap;
	if (::ClearCurrentScrap() != noErr) return false;
	if (::GetCurrentScrap(&scrap) != noErr) return false;

	return ::PutScrapFlavor( scrap, kScrapFlavorTypeText, kScrapFlavorMaskNone, inText.size(), &*inText.begin()) == noErr;

#endif
}

static int	WidgetFunc_CutCopyPaste(
                                  XPWidgetMessage      inMessage,
                                  XPWidgetID           inWidget,
                                  long                 inParam1,
                                  long                 inParam2)
{
	if (inMessage == xpMsg_KeyPress)
	{
		char			theChar = KEY_VKEY(inParam1);
		XPLMKeyFlags	flags = KEY_FLAGS(inParam1);

		if ((flags & (xplm_DownFlag + xplm_ControlFlag)) == (xplm_DownFlag + xplm_ControlFlag))
		{
			long	selStart = XPGetWidgetProperty(inWidget, xpProperty_EditFieldSelStart, NULL);
			long	selEnd = XPGetWidgetProperty(inWidget, xpProperty_EditFieldSelEnd, NULL);
			long	strLen = XPGetWidgetDescriptor(inWidget, NULL, 0);
			std::string	txt;
			txt.resize(strLen);
			XPGetWidgetDescriptor(inWidget, &*txt.begin(), txt.size()+1);
			if (theChar == XPLM_VK_V)
			{
				std::string	scrap;
				if (XSBGetTextFromClipboard(scrap) && !scrap.empty())
				{
					if ((selEnd > selStart) && (selStart >= 0) && (selEnd <= strLen))
					{
						txt.replace(selStart, selEnd - selStart, scrap);
						XPSetWidgetDescriptor(inWidget, txt.c_str());
						XPSetWidgetProperty(inWidget, xpProperty_EditFieldSelStart, selStart + scrap.size());
						XPSetWidgetProperty(inWidget, xpProperty_EditFieldSelEnd, selStart + scrap.size());
					} else if ((selStart >= 0) && (selStart <= strLen)) {
						txt.insert(selStart, scrap);
						XPSetWidgetDescriptor(inWidget, txt.c_str());
						XPSetWidgetProperty(inWidget, xpProperty_EditFieldSelStart, selStart + scrap.size());
						XPSetWidgetProperty(inWidget, xpProperty_EditFieldSelEnd, selStart + scrap.size());
					}
				}
				return 1;
			}
			if ((theChar == XPLM_VK_C) || (theChar == XPLM_VK_X))
			{
				if ((selStart >= 0) && (selStart < selEnd) && (selEnd <= strLen))
				{
					std::string	scrap = txt.substr(selStart, selEnd - selStart);
					if (XSBSetTextToClipboard(scrap) && (theChar == XPLM_VK_X))
					{
						txt.erase(selStart, selEnd - selStart);
						XPSetWidgetDescriptor(inWidget, txt.c_str());
						XPSetWidgetProperty(inWidget, xpProperty_EditFieldSelEnd, selStart);
					}
				}
				return 1;
			}
		}
	}
	return 0;
}

void	AttachCutCopyPaste(XPWidgetID inWidget)
{
	XPAddWidgetCallback(inWidget, WidgetFunc_CutCopyPaste);
 }