@@ -397,11 +397,9 @@ public: | |||
if (OK (AudioObjectGetPropertyData (deviceID, &pa, 0, nullptr, &size, &isAlive)) && isAlive == 0) | |||
return; | |||
Float64 sr; | |||
size = sizeof (sr); | |||
pa.mSelector = kAudioDevicePropertyNominalSampleRate; | |||
if (OK (AudioObjectGetPropertyData (deviceID, &pa, 0, nullptr, &size, &sr))) | |||
sampleRate = sr; | |||
const double currentRate = getNominalSampleRate(); | |||
if (currentRate > 0) | |||
sampleRate = currentRate; | |||
UInt32 framesPerBuf = (UInt32) bufferSize; | |||
size = sizeof (framesPerBuf); | |||
@@ -525,6 +523,30 @@ public: | |||
} | |||
} | |||
double getNominalSampleRate() const | |||
{ | |||
AudioObjectPropertyAddress pa; | |||
pa.mSelector = kAudioDevicePropertyNominalSampleRate; | |||
pa.mScope = kAudioObjectPropertyScopeGlobal; | |||
pa.mElement = kAudioObjectPropertyElementMaster; | |||
Float64 sr = 0; | |||
UInt32 size = (UInt32) sizeof (sr); | |||
return OK (AudioObjectGetPropertyData (deviceID, &pa, 0, nullptr, &size, &sr)) ? (double) sr : 0.0; | |||
} | |||
bool setNominalSampleRate (double newSampleRate) const | |||
{ | |||
if (std::abs (getNominalSampleRate() - newSampleRate) < 1.0) | |||
return true; | |||
AudioObjectPropertyAddress pa; | |||
pa.mSelector = kAudioDevicePropertyNominalSampleRate; | |||
pa.mScope = kAudioObjectPropertyScopeGlobal; | |||
pa.mElement = kAudioObjectPropertyElementMaster; | |||
Float64 sr = newSampleRate; | |||
return OK (AudioObjectSetPropertyData (deviceID, &pa, 0, 0, sizeof (sr), &sr)); | |||
} | |||
//============================================================================== | |||
String reopen (const BigInteger& inputChannels, | |||
const BigInteger& outputChannels, | |||
@@ -549,25 +571,23 @@ public: | |||
numInputChans = activeInputChans.countNumberOfSetBits(); | |||
numOutputChans = activeOutputChans.countNumberOfSetBits(); | |||
// set sample rate | |||
AudioObjectPropertyAddress pa; | |||
pa.mSelector = kAudioDevicePropertyNominalSampleRate; | |||
pa.mScope = kAudioObjectPropertyScopeGlobal; | |||
pa.mElement = kAudioObjectPropertyElementMaster; | |||
Float64 sr = newSampleRate; | |||
if (! OK (AudioObjectSetPropertyData (deviceID, &pa, 0, 0, sizeof (sr), &sr))) | |||
if (! setNominalSampleRate (newSampleRate)) | |||
{ | |||
updateDetailsFromDevice(); | |||
error = "Couldn't change sample rate"; | |||
} | |||
else | |||
{ | |||
// change buffer size | |||
UInt32 framesPerBuf = (UInt32) bufferSizeSamples; | |||
AudioObjectPropertyAddress pa; | |||
pa.mSelector = kAudioDevicePropertyBufferFrameSize; | |||
pa.mScope = kAudioObjectPropertyScopeGlobal; | |||
pa.mElement = kAudioObjectPropertyElementMaster; | |||
UInt32 framesPerBuf = (UInt32) bufferSizeSamples; | |||
if (! OK (AudioObjectSetPropertyData (deviceID, &pa, 0, 0, sizeof (framesPerBuf), &framesPerBuf))) | |||
{ | |||
updateDetailsFromDevice(); | |||
error = "Couldn't change buffer size"; | |||
} | |||
else | |||
@@ -643,7 +643,7 @@ public: | |||
if (metadataValues.size() > 0) | |||
{ | |||
// The meta data should have been santised for the AIFF format. | |||
// The meta data should have been sanitised for the AIFF format. | |||
// If it was originally sourced from a WAV file the MetaDataSource | |||
// key should be removed (or set to "AIFF") once this has been done | |||
jassert (metadataValues.getValue ("MetaDataSource", "None") != "WAV"); | |||
@@ -1024,7 +1024,7 @@ public: | |||
if (metadataValues.size() > 0) | |||
{ | |||
// The meta data should have been santised for the WAV format. | |||
// The meta data should have been sanitised for the WAV format. | |||
// If it was originally sourced from an AIFF file the MetaDataSource | |||
// key should be removed (or set to "WAV") once this has been done | |||
jassert (metadataValues.getValue ("MetaDataSource", "None") != "AIFF"); | |||
@@ -42,7 +42,7 @@ public: | |||
bool fileMightContainThisPluginType (const String& fileOrIdentifier) override; | |||
String getNameOfPluginFromIdentifier (const String& fileOrIdentifier) override; | |||
bool pluginNeedsRescanning (const PluginDescription&) override; | |||
StringArray searchPathsForPlugins (const FileSearchPath&, bool recursive); | |||
StringArray searchPathsForPlugins (const FileSearchPath&, bool recursive) override; | |||
bool doesPluginStillExist (const PluginDescription&) override; | |||
FileSearchPath getDefaultLocationsToSearch() override; | |||
bool canScanForPlugins() const override { return true; } | |||
@@ -840,9 +840,9 @@ public: | |||
if (audioUnit != nullptr) | |||
{ | |||
UInt32 paramListSize = 0; | |||
UInt32 dummy = 0, paramListSize = 0; | |||
AudioUnitGetProperty (audioUnit, kAudioUnitProperty_ParameterList, kAudioUnitScope_Global, | |||
0, 0, ¶mListSize); | |||
0, &dummy, ¶mListSize); | |||
if (paramListSize > 0) | |||
{ | |||
@@ -1145,7 +1145,7 @@ public: | |||
} | |||
//============================================================================== | |||
int getNumParameters() { return effect != nullptr ? effect->numParams : 0; } | |||
int getNumParameters() override { return effect != nullptr ? effect->numParams : 0; } | |||
float getParameter (int index) override | |||
{ | |||
@@ -49,7 +49,7 @@ public: | |||
virtual int toInt (const ValueUnion&) const noexcept { return 0; } | |||
virtual int64 toInt64 (const ValueUnion&) const noexcept { return 0; } | |||
virtual double toDouble (const ValueUnion&) const noexcept { return 0; } | |||
virtual String toString (const ValueUnion&) const { return String::empty; } | |||
virtual String toString (const ValueUnion&) const { return String(); } | |||
virtual bool toBool (const ValueUnion&) const noexcept { return false; } | |||
virtual ReferenceCountedObject* toObject (const ValueUnion&) const noexcept { return nullptr; } | |||
virtual Array<var>* toArray (const ValueUnion&) const noexcept { return nullptr; } | |||
@@ -274,7 +274,7 @@ public: | |||
} | |||
String toString (const ValueUnion& data) const override { return "Object 0x" + String::toHexString ((int) (pointer_sized_int) data.objectValue); } | |||
bool toBool (const ValueUnion& data) const noexcept override { return data.objectValue != 0; } | |||
bool toBool (const ValueUnion& data) const noexcept override { return data.objectValue != nullptr; } | |||
ReferenceCountedObject* toObject (const ValueUnion& data) const noexcept override { return data.objectValue; } | |||
bool isObject() const noexcept override { return true; } | |||
@@ -992,7 +992,8 @@ double Expression::evaluate() const | |||
double Expression::evaluate (const Expression::Scope& scope) const | |||
{ | |||
return term->resolve (scope, 0)->toDouble(); | |||
String err; | |||
return evaluate (scope, err); | |||
} | |||
double Expression::evaluate (const Scope& scope, String& evaluationError) const | |||
@@ -1038,20 +1039,16 @@ Expression Expression::adjustedToGiveNewResult (const double targetValue, const | |||
jassert (termToAdjust != nullptr); | |||
const Term* const parent = Helpers::findDestinationFor (newTerm, termToAdjust); | |||
if (parent == nullptr) | |||
if (const Term* parent = Helpers::findDestinationFor (newTerm, termToAdjust)) | |||
{ | |||
termToAdjust->value = targetValue; | |||
if (const Helpers::TermPtr reverseTerm = parent->createTermToEvaluateInput (scope, termToAdjust, targetValue, newTerm)) | |||
termToAdjust->value = Expression (reverseTerm).evaluate (scope); | |||
else | |||
return Expression (targetValue); | |||
} | |||
else | |||
{ | |||
const Helpers::TermPtr reverseTerm (parent->createTermToEvaluateInput (scope, termToAdjust, targetValue, newTerm)); | |||
if (reverseTerm == nullptr) | |||
return Expression (targetValue); | |||
termToAdjust->value = reverseTerm->resolve (scope, 0)->toDouble(); | |||
termToAdjust->value = targetValue; | |||
} | |||
return Expression (newTerm.release()); | |||
@@ -429,7 +429,7 @@ String SystemStats::getFullUserName() | |||
String SystemStats::getComputerName() | |||
{ | |||
TCHAR text [MAX_COMPUTERNAME_LENGTH + 1] = { 0 }; | |||
TCHAR text[128] = { 0 }; | |||
DWORD len = (DWORD) numElementsInArray (text) - 1; | |||
GetComputerName (text, &len); | |||
return String (text, len); | |||
@@ -26,28 +26,44 @@ | |||
============================================================================== | |||
*/ | |||
MACAddress::MACAddress() | |||
MACAddress::MACAddress() noexcept | |||
{ | |||
zeromem (address, sizeof (address)); | |||
} | |||
MACAddress::MACAddress (const MACAddress& other) | |||
MACAddress::MACAddress (const MACAddress& other) noexcept | |||
{ | |||
memcpy (address, other.address, sizeof (address)); | |||
} | |||
MACAddress& MACAddress::operator= (const MACAddress& other) | |||
MACAddress& MACAddress::operator= (const MACAddress& other) noexcept | |||
{ | |||
memcpy (address, other.address, sizeof (address)); | |||
return *this; | |||
} | |||
MACAddress::MACAddress (const uint8 bytes[6]) | |||
MACAddress::MACAddress (const uint8 bytes[6]) noexcept | |||
{ | |||
memcpy (address, bytes, sizeof (address)); | |||
} | |||
MACAddress::MACAddress (StringRef addressString) | |||
{ | |||
MemoryBlock hex; | |||
hex.loadFromHexString (addressString); | |||
if (hex.getSize() == sizeof (address)) | |||
memcpy (address, hex.getData(), sizeof (address)); | |||
else | |||
zeromem (address, sizeof (address)); | |||
} | |||
String MACAddress::toString() const | |||
{ | |||
return toString ("-"); | |||
} | |||
String MACAddress::toString (StringRef separator) const | |||
{ | |||
String s; | |||
@@ -56,7 +72,7 @@ String MACAddress::toString() const | |||
s << String::toHexString ((int) address[i]).paddedLeft ('0', 2); | |||
if (i < sizeof (address) - 1) | |||
s << '-'; | |||
s << separator; | |||
} | |||
return s; | |||
@@ -43,16 +43,22 @@ public: | |||
//============================================================================== | |||
/** Creates a null address (00-00-00-00-00-00). */ | |||
MACAddress(); | |||
MACAddress() noexcept; | |||
/** Creates a copy of another address. */ | |||
MACAddress (const MACAddress&); | |||
MACAddress (const MACAddress&) noexcept; | |||
/** Creates a copy of another address. */ | |||
MACAddress& operator= (const MACAddress&); | |||
MACAddress& operator= (const MACAddress&) noexcept; | |||
/** Creates an address from 6 bytes. */ | |||
explicit MACAddress (const uint8 bytes[6]); | |||
explicit MACAddress (const uint8 bytes[6]) noexcept; | |||
/** Creates an address from a hex string. | |||
If the string isn't a 6-byte hex value, this will just default-initialise | |||
the object. | |||
*/ | |||
explicit MACAddress (StringRef address); | |||
/** Returns a pointer to the 6 bytes that make up this address. */ | |||
const uint8* getBytes() const noexcept { return address; } | |||
@@ -60,6 +66,9 @@ public: | |||
/** Returns a dash-separated string in the form "11-22-33-44-55-66" */ | |||
String toString() const; | |||
/** Returns a hex string of this address, using a custom separator between each byte. */ | |||
String toString (StringRef separator) const; | |||
/** Returns the address in the lower 6 bytes of an int64. | |||
This uses a little-endian arrangement, with the first byte of the address being | |||
@@ -67,13 +67,18 @@ int MemoryInputStream::read (void* const buffer, const int howMany) | |||
{ | |||
jassert (buffer != nullptr && howMany >= 0); | |||
const int num = jmin (howMany, (int) (dataSize - position)); | |||
if (num <= 0) | |||
if (howMany <= 0 || position >= dataSize) | |||
return 0; | |||
memcpy (buffer, addBytesToPointer (data, position), (size_t) num); | |||
position += (unsigned int) num; | |||
return num; | |||
const size_t num = jmin ((size_t) howMany, dataSize - position); | |||
if (num > 0) | |||
{ | |||
memcpy (buffer, addBytesToPointer (data, position), num); | |||
position += num; | |||
} | |||
return (int) num; | |||
} | |||
bool MemoryInputStream::isExhausted() | |||
@@ -40,6 +40,10 @@ | |||
When you create a Value with its default constructor, it acts as a wrapper around a | |||
simple var object, but by creating a Value that refers to a custom subclass of ValueSource, | |||
you can map the Value onto any kind of underlying data. | |||
Important note! The Value class is not thread-safe! If you're accessing one from | |||
multiple threads, then you'll need to use your own synchronisation around any code | |||
that accesses it. | |||
*/ | |||
class JUCE_API Value | |||
{ | |||
@@ -222,20 +222,21 @@ namespace CoreTextTypeLayout | |||
CFStringRef cfText = text.getText().toCFString(); | |||
CFMutableAttributedStringRef attribString = CFAttributedStringCreateMutable (kCFAllocatorDefault, 0); | |||
CFAttributedStringReplaceString (attribString, CFRangeMake(0, 0), cfText); | |||
CFAttributedStringReplaceString (attribString, CFRangeMake (0, 0), cfText); | |||
CFRelease (cfText); | |||
const int numCharacterAttributes = text.getNumAttributes(); | |||
const CFIndex attribStringLen = CFAttributedStringGetLength (attribString); | |||
for (int i = 0; i < numCharacterAttributes; ++i) | |||
{ | |||
const AttributedString::Attribute& attr = *text.getAttribute (i); | |||
const int rangeStart = attr.range.getStart(); | |||
if (attr.range.getStart() > CFAttributedStringGetLength (attribString)) | |||
if (rangeStart >= attribStringLen) | |||
continue; | |||
Range<int> range (attr.range); | |||
range.setEnd (jmin (range.getEnd(), (int) CFAttributedStringGetLength (attribString))); | |||
CFRange range = CFRangeMake (rangeStart, jmin (attr.range.getEnd(), (int) attribStringLen) - rangeStart); | |||
if (const Font* const f = attr.getFont()) | |||
{ | |||
@@ -243,8 +244,19 @@ namespace CoreTextTypeLayout | |||
{ | |||
ctFontRef = getFontWithPointSize (ctFontRef, f->getHeight() * getHeightToPointsFactor (ctFontRef)); | |||
CFAttributedStringSetAttribute (attribString, CFRangeMake (range.getStart(), range.getLength()), | |||
kCTFontAttributeName, ctFontRef); | |||
CFAttributedStringSetAttribute (attribString, range, kCTFontAttributeName, ctFontRef); | |||
float extraKerning = f->getExtraKerningFactor(); | |||
if (extraKerning != 0.0f) | |||
{ | |||
extraKerning *= f->getHeight(); | |||
CFNumberRef numberRef = CFNumberCreate (0, kCFNumberFloatType, &extraKerning); | |||
CFAttributedStringSetAttribute (attribString, range, kCTKernAttributeName, numberRef); | |||
CFRelease (numberRef); | |||
} | |||
CFRelease (ctFontRef); | |||
} | |||
} | |||
@@ -264,9 +276,7 @@ namespace CoreTextTypeLayout | |||
col->getFloatAlpha()); | |||
#endif | |||
CFAttributedStringSetAttribute (attribString, | |||
CFRangeMake (range.getStart(), range.getLength()), | |||
kCTForegroundColorAttributeName, colour); | |||
CFAttributedStringSetAttribute (attribString, range, kCTForegroundColorAttributeName, colour); | |||
CGColorRelease (colour); | |||
} | |||
} | |||
@@ -51,10 +51,10 @@ public: | |||
Remember that when the target component is resized, it'll need to move and | |||
resize this component to keep it in place, as this won't happen automatically. | |||
If the constrainer parameter is non-zero, then this object will be used to enforce | |||
If a constrainer object is provided, then this object will be used to enforce | |||
limits on the size and position that the component can be stretched to. Make sure | |||
that the constrainer isn't deleted while still in use by this object. If you | |||
pass a zero in here, no limits will be put on the sizes it can be stretched to. | |||
pass a nullptr in here, no limits will be put on the sizes it can be stretched to. | |||
@see ComponentBoundsConstrainer | |||
*/ | |||
@@ -131,7 +131,7 @@ public: | |||
/** OSX ONLY - Sets the model that is currently being shown as the main | |||
menu bar at the top of the screen on the Mac. | |||
You can pass 0 to stop the current model being displayed. Be careful | |||
You can pass nullptr to stop the current model being displayed. Be careful | |||
not to delete a model while it is being used. | |||
An optional extra menu can be specified, containing items to add to the top of | |||
@@ -39,6 +39,14 @@ | |||
#define WM_APPCOMMAND 0x0319 | |||
#endif | |||
#ifndef MI_WP_SIGNATURE | |||
#define MI_WP_SIGNATURE 0xFF515700 | |||
#endif | |||
#ifndef SIGNATURE_MASK | |||
#define SIGNATURE_MASK 0xFFFFFF00 | |||
#endif | |||
extern void juce_repeatLastProcessPriority(); | |||
extern void juce_checkCurrentlyFocusedTopLevelWindow(); // in juce_TopLevelWindow.cpp | |||
extern bool juce_isRunningInWine(); | |||
@@ -1706,8 +1714,22 @@ private: | |||
return 1000 / 60; // Throttling the incoming mouse-events seems to still be needed in XP.. | |||
} | |||
bool isTouchEvent() noexcept | |||
{ | |||
if (registerTouchWindow == nullptr) | |||
return false; | |||
LPARAM dw = GetMessageExtraInfo(); | |||
// see https://msdn.microsoft.com/en-us/library/windows/desktop/ms703320(v=vs.85).aspx | |||
return (dw & SIGNATURE_MASK) == MI_WP_SIGNATURE; | |||
} | |||
void doMouseMove (Point<float> position) | |||
{ | |||
// this will be handled by WM_TOUCH | |||
if (isTouchEvent()) | |||
return; | |||
if (! isMouseOver) | |||
{ | |||
isMouseOver = true; | |||
@@ -1744,6 +1766,10 @@ private: | |||
void doMouseDown (Point<float> position, const WPARAM wParam) | |||
{ | |||
// this will be handled by WM_TOUCH | |||
if (isTouchEvent()) | |||
return; | |||
if (GetCapture() != hwnd) | |||
SetCapture (hwnd); | |||
@@ -1760,6 +1786,10 @@ private: | |||
void doMouseUp (Point<float> position, const WPARAM wParam) | |||
{ | |||
// this will be handled by WM_TOUCH | |||
if (isTouchEvent()) | |||
return; | |||
updateModifiersFromWParam (wParam); | |||
const bool wasDragging = isDragging; | |||
isDragging = false; | |||
@@ -1879,8 +1909,7 @@ private: | |||
const DWORD flags = inputInfo[i].dwFlags; | |||
if ((flags & (TOUCHEVENTF_DOWN | TOUCHEVENTF_MOVE | TOUCHEVENTF_UP)) != 0) | |||
if (! handleTouchInput (inputInfo[i], (flags & TOUCHEVENTF_PRIMARY) != 0, | |||
(flags & TOUCHEVENTF_DOWN) != 0, (flags & TOUCHEVENTF_UP) != 0)) | |||
if (! handleTouchInput (inputInfo[i], (flags & TOUCHEVENTF_DOWN) != 0, (flags & TOUCHEVENTF_UP) != 0)) | |||
return 0; // abandon method if this window was deleted by the callback | |||
} | |||
} | |||
@@ -1889,7 +1918,7 @@ private: | |||
return 0; | |||
} | |||
bool handleTouchInput (const TOUCHINPUT& touch, const bool isPrimary, const bool isDown, const bool isUp) | |||
bool handleTouchInput (const TOUCHINPUT& touch, const bool isDown, const bool isUp) | |||
{ | |||
bool isCancel = false; | |||
const int touchIndex = currentTouches.getIndexOfTouch (touch.dwID); | |||
@@ -1903,13 +1932,10 @@ private: | |||
currentModifiers = currentModifiers.withoutMouseButtons().withFlags (ModifierKeys::leftButtonModifier); | |||
modsToSend = currentModifiers; | |||
if (! isPrimary) | |||
{ | |||
// this forces a mouse-enter/up event, in case for some reason we didn't get a mouse-up before. | |||
handleMouseEvent (touchIndex, pos.toFloat(), modsToSend.withoutMouseButtons(), time); | |||
if (! isValidPeer (this)) // (in case this component was deleted by the event) | |||
return false; | |||
} | |||
// this forces a mouse-enter/up event, in case for some reason we didn't get a mouse-up before. | |||
handleMouseEvent (touchIndex, pos.toFloat(), modsToSend.withoutMouseButtons(), time); | |||
if (! isValidPeer (this)) // (in case this component was deleted by the event) | |||
return false; | |||
} | |||
else if (isUp) | |||
{ | |||
@@ -1930,14 +1956,11 @@ private: | |||
currentModifiers = currentModifiers.withoutMouseButtons(); | |||
} | |||
if (! isPrimary) | |||
{ | |||
handleMouseEvent (touchIndex, pos.toFloat(), modsToSend, time); | |||
if (! isValidPeer (this)) // (in case this component was deleted by the event) | |||
return false; | |||
} | |||
handleMouseEvent (touchIndex, pos.toFloat(), modsToSend, time); | |||
if (! isValidPeer (this)) // (in case this component was deleted by the event) | |||
return false; | |||
if ((isUp || isCancel) && ! isPrimary) | |||
if (isUp || isCancel) | |||
{ | |||
handleMouseEvent (touchIndex, Point<float> (-10.0f, -10.0f), currentModifiers, time); | |||
if (! isValidPeer (this)) | |||
@@ -309,7 +309,7 @@ TextEditor* Label::createEditorComponent() | |||
copyColourIfSpecified (*this, *ed, textWhenEditingColourId, TextEditor::textColourId); | |||
copyColourIfSpecified (*this, *ed, backgroundWhenEditingColourId, TextEditor::backgroundColourId); | |||
copyColourIfSpecified (*this, *ed, outlineWhenEditingColourId, TextEditor::outlineColourId); | |||
copyColourIfSpecified (*this, *ed, outlineWhenEditingColourId, TextEditor::focusedOutlineColourId); | |||
return ed; | |||
} | |||
@@ -89,7 +89,7 @@ void AlertWindow::addButton (const String& name, | |||
const KeyPress& shortcutKey1, | |||
const KeyPress& shortcutKey2) | |||
{ | |||
TextButton* const b = new TextButton (name, String::empty); | |||
TextButton* const b = new TextButton (name, String()); | |||
buttons.add (b); | |||
b->setWantsKeyboardFocus (true); | |||
@@ -143,9 +143,9 @@ void AlertWindow::addTextEditor (const String& name, | |||
ed->setColour (TextEditor::outlineColourId, findColour (ComboBox::outlineColourId)); | |||
ed->setFont (getLookAndFeel().getAlertWindowMessageFont()); | |||
addAndMakeVisible (ed); | |||
ed->setText (initialContents); | |||
ed->setCaretPosition (initialContents.length()); | |||
addAndMakeVisible (ed); | |||
textboxNames.add (onScreenLabel); | |||
updateLayout (false); | |||
@@ -165,7 +165,7 @@ String AlertWindow::getTextEditorContents (const String& nameOfTextEditor) const | |||
if (TextEditor* const t = getTextEditor (nameOfTextEditor)) | |||
return t->getText(); | |||
return String::empty; | |||
return String(); | |||
} | |||
@@ -66,14 +66,14 @@ struct CppTokeniserFunctions | |||
static const char* const keywords7Char[] = | |||
{ "nullptr", "alignas", "alignof", "default", "mutable", "private", | |||
"typedef", "virtual", "wchar_t", nullptr }; | |||
"typedef", "virtual", "wchar_t", "__cdecl", "_Pragma", "uint8_t", nullptr }; | |||
static const char* const keywordsOther[] = | |||
{ "char16_t", "char32_t", "const_cast", "constexpr", "continue", "decltype", "dynamic_cast", | |||
"explicit", "namespace", "noexcept", "operator", "protected", "register", "reinterpret_cast", | |||
"static_assert", "static_cast", "template", "thread_local", "typename", "unsigned", "volatile", | |||
"@class", "@dynamic", "@end", "@implementation", "@interface", "@public", "@private", | |||
"@protected", "@property", "@synthesize", nullptr }; | |||
"@protected", "@property", "@synthesize", "__fastcall", "__stdcall", nullptr }; | |||
const char* const* k; | |||