MacOS accessibility API change value of selected range location - objective-c

i am using Cocoa with Accessibility API system wide to obtain some info like text value, selected text value but is there a way to change any of that? As you can see on my picture, you can edit the location of the keyboard cursor (Loc) and the length (Len) of the selected text so there must be a way to do this programmatically. Also, I am looking how to get the keyboard cursor position (blinking caret) inside the screen even if nothing is selected. (I have seen applications doing it)
EDIT :
This is my code so far to get the attribute :
AXValueRef textValue = NULL;
//Get the location string inside the selectedtextrange
AXError gettextvalueError = AXUIElementCopyAttributeValue(focussedElement, kAXSelectedTextRangeAttribute , (CFTypeRef *)&textValue); //get the text value of focussedElement in object textValue
if(gettextvalueError != kAXErrorSuccess){
NSLog(#"error");
}else{
NSString* textStr = (__bridge NSString*)textValue; // Convert textValue to NSString
}
This is getting me a string containing bounds object of the selected text and location + length. Is it possible to only change the location.
<AXValue 0x7f8dda3c4340> {value = location:3 length:0 type = kAXValueCFRangeType}

First, the value you get is not a string object. Casting it to NSString* doesn't "convert" it, it just lies to the compiler. The reason that logging it works is that %# asks the object for its description and the AXValue object describes itself as you're seeing in the output.
To decode the value, use code like this:
CFRange range;
if (AXValueGetValue(textValue, kAXValueTypeCFRange, &range))
{
// use the range
}
else
/* the value isn't of the type that the attribute is supposed to have; abort */;
If you want to change it:
range.location = /* some new value */;
AXValueRef newValue = AXValueCreate(kAXValueTypeCFRange, &range);
if (newValue)
{
AXError setError = AXUIElementSetAttributeValue(focussedElement, kAXSelectedTextRangeAttribute, newValue);
/* check setError and handle as appropriate */
CFRelease(newValue);
}
else
/* handle failure */;

Related

Expected method to read dictionary element not found on object of type 'id<NSCopying>'

I am using Cocos2d-ObjC in my app and recently upgraded Xcode to v9.3. Now I have an error in "CCRendererBasicTypes.m" which says
"Expected method to read dictionary element not found on object of type 'id<NSCopying>'"
Everything else is working fine. This is the part of CCRendererBasicTypes
-(id)objectForKey:(id<NSCopying>)options
{
CCBlendMode *blendMode = [self rawObjectForKey:options];
if(blendMode) return blendMode;
// Normalize the blending mode to use for the key.
id src = (options[CCBlendFuncSrcColor] ?: #(GL_ONE));
id dst = (options[CCBlendFuncDstColor] ?: #(GL_ZERO));
id equation = (options[CCBlendEquationColor] ?: #(GL_FUNC_ADD));
NSDictionary *normalized = #{
CCBlendFuncSrcColor: src,
CCBlendFuncDstColor: dst,
CCBlendEquationColor: equation,
// Assume they meant non-separate blending if they didn't fill in the keys.
CCBlendFuncSrcAlpha: (options[CCBlendFuncSrcAlpha] ?: src),
CCBlendFuncDstAlpha: (options[CCBlendFuncDstAlpha] ?: dst),
CCBlendEquationAlpha: (options[CCBlendEquationAlpha] ?: equation),
};
// Create the key using the normalized blending mode.
blendMode = [super objectForKey:normalized];
// Make an alias for the unnormalized version
[self makeAlias:options forKey:normalized];
return blendMode;
}
The error appears in every line with
options[...]
Change the first line to
-(id)objectForKey:(NSDictionary*)options

Check the class of an object from Box2d's user data

I am trying to determine the type of object when detecting collision with Box2d. I want to be able to assign the user data to an object and check to see if its of the correct class type
id object = b->GerUserData():
Then
if([object isKindOfClass:[MyClassObject class]])
However i just get the error "Cannot initialize a variable of type'id' with an rvalue of type 'void*'
Can anyone help me out.
Thanks
Your problem is you are trying to assign an object of type 'id' to a void * type
The method call body->GetUserData(); returns a void pointer. Here it is as defined in the header file of b2Body.h
/// Get the user data pointer that was provided in the body definition.
void* GetUserData() const;
Now, if you are using ARC (Automatic Reference Counting), you need to perform an additional step to cast it back.
id object = (__bridge id) b->GetUserData();
If you are not using ARC, then...
id object = (id) b->GetUserData();
As for checking the type, there are many ways to do this. I personally prefer having an enum called GameObjectType. I can then assign the type in the appropriate constructor of the object. Here is an example of how I do it in my games
for (b2Body * b = world->GetBodyList(); b != NULL; b = b->GetNext()) {
Box2DSprite * sprite = (__bridge Box2DSprite*) b->GetUserData();
id obj = (__bridge id) b->GetUserData();
if (sprite.gameObjectType == kGroundTypeStatic
|| sprite.gameObjectType == kWallType
|| sprite.gameObjectType == kGroundTypeDynamic) {
// Insert Logic here
} // end if
sprite.position = ccp(b->GetPosition().x * PTM_RATIO, b->GetPosition().y * PTM_RATIO);
sprite.rotation = CC_RADIANS_TO_DEGREES(b->GetAngle() * -1);
} // end for
Here is how I would go about creating the sprite (Using ARC)
b2BodyDef bodyDef;
bodyDef.type = b2_dynamicBody;
bodyDef.position = b2Vec2(location.x/PTM_RATIO,
location.y/PTM_RATIO);
// Setting the enum value
self.gameObjectType = kTankType;
self->body = self->world->CreateBody(&bodyDef);
self->body->SetUserData((__bridge void*) self); // Obtain sprite object later
GB2ShapeCache * shapeCache = [GB2ShapeCache sharedShapeCache];
[shapeCache addFixturesToBody:self->body forShapeName:#"Earth_Tank"];
self.anchorPoint = [shapeCache anchorPointForShape:#"Earth_Tank"];
Hope this helps
I'm guessing the error is on this line:
id object = b->GetUserData();
That might be because the return type is void pointer. Try to cast it like that:
id object = (id)b->GetUserData();

Modify pdf metadata color space using CoreGraphics

I m trying to change color space for image objects of a pdf file, but first problem is that I cannot find ICC color profile inside pdf metadata.
All I have in Metadata is one array with 2 components:
ColorSpace :
Name value: ICCBased
Stream value (null)
And when I get the Stream parsed into a dictionary:
Color Space Name ICCBased
Filter :
Name value: FlateDecode
Length :
integer value: 389757
N :
integer value: 4
Range :
ARRAY with value:
integer value: 0
integer value: 1
integer value: 0
integer value: 1
integer value: 0
integer value: 1
integer value: 0
integer value: 1
But I am unable to find in metadata the ICC profile data used on the color space of the image, the one you can see with acrobat:
By the way, if you are interested on how to get metadata form pdf file with coreGraphics here I put some code:
...
CGPDFDocumentRef pdfDocument = CGPDFDocumentCreateWithURL(pdfURL);
CGPDFPageRef page = CGPDFDocumentGetPage(pdfDocument, pageNumber);
CGPDFContentStreamRef contentStream =
CGPDFContentStreamCreateWithPage(page); CGPDFOperatorTableRef
operatorTable = CGPDFOperatorTableCreate();
CGPDFOperatorTableSetCallback(operatorTable, "Do", &op_Do);
CGPDFScannerRef contentStreamScanner =
CGPDFScannerCreate(contentStream, operatorTable, NULL);
CGPDFScannerScan(contentStreamScanner);
....
And then on the callback:
static void op_Do(CGPDFScannerRef s, void *info) {
CGPDFObjectRef imageObject = CGPDFContentStreamGetResource(cs, "XObject", imageLabel);
CGPDFStreamRef xObjectStream;
if (CGPDFObjectGetValue(imageObject, kCGPDFObjectTypeStream, &xObjectStream)) {
CGPDFDictionaryRef xObjectDictionary = CGPDFStreamGetDictionary(xObjectStream);
const char *subtype;
CGPDFDictionaryGetName(xObjectDictionary, "Subtype", &subtype);
if (strcmp(subtype, "Image") == 0) {
NSString *imageID = [NSString stringWithCString: imageLabel encoding: NSASCIIStringEncoding];
CGPDFDictionaryApplyFunction(xObjectDictionary, ListDictionaryObjects, NULL);
if (CGPDFDictionaryGetName(xObjectDictionary, "ColorSpace", &colorSpaceName)){
fprintf(stdout,"Color Space Name %s\n", colorSpaceName);
}else{
//Getting Color space array
CGPDFArrayRef objectArray;
CGPDFDictionaryGetArray(xObjectDictionary, "ColorSpace", &objectArray);
//getting each array position
CGPDFStreamRef colorsSpaceStream;
CGPDFArrayGetName(objectArray, 0, &colorSpaceName);
fprintf(stdout,"Color Space Name %s\n", colorSpaceName);
CGPDFArrayGetStream(objectArray, 1, &colorsSpaceStream);
CGPDFDictionaryRef dictionary = CGPDFStreamGetDictionary(colorsSpaceStream);
CGPDFDictionaryApplyFunction(dictionary, ListDictionaryObjectsLow, NULL);
}
...
And finally in ListDictionaryObjects functions I go through dictionary objects:
void ListDictionaryObjects (const char *key, CGPDFObjectRef object, void *info) {
fprintf(stdout, "%s :\n", key);
CGPDFObjectType type = CGPDFObjectGetType(object);
switch (type) {
case kCGPDFObjectTypeDictionary: {
CGPDFDictionaryRef objectDictionary;
if (CGPDFObjectGetValue(object, kCGPDFObjectTypeDictionary, &objectDictionary)) {
fprintf(stdout," Dictionary value with: %zd elements\n", CGPDFDictionaryGetCount(objectDictionary));
CGPDFDictionaryApplyFunction(objectDictionary, ListDictionaryObjectsLow, NULL);
}
}
break;
case kCGPDFObjectTypeInteger: {
CGPDFInteger objectInteger;
if (CGPDFObjectGetValue(object, kCGPDFObjectTypeInteger, &objectInteger)) {
fprintf(stdout," integer value: %ld \n", (long int)objectInteger);
}
}
break;
case kCGPDFObjectTypeReal:{
CGPDFReal objectReal;
if (CGPDFObjectGetValue(object, kCGPDFObjectTypeReal, &objectReal)){
fprintf(stdout," real value: %5.2f\n", objectReal);
}
} ...
Assigning a new color profile (i.e. without altering values in the object) to all objects of a certain color space can be done by creating a Quartz Filter with ColorSync Utility.
A technical note from the Mac Developer Library from 2005 about "ColorSync on Mac OS X" stated:
Quartz filters are currently available only through the various Mac OS X system-built utilities and applications. However, a new set of API's will be forthcoming.
But I could not find any other mention to Quartz Filters in Apple's documentation for developers.
I know this is not terribly helpful, but maybe it gives you a hint of were to look.
Edit: See this answer to "Apply a Quartz filter while saving PDF under Mac OS X 10.6.3"
What you're seeing is described in the PDF specification:
http://www.adobe.com/content/dam/Adobe/en/devnet/acrobat/pdfs/PDF32000_2008.pdf
Look for section 8.6.5.5 which defines ICC-based color spaces - the data that you are looking for is contained in the stream you paste at the top of your message. It's not readily recognisable because it has been Flate encoded (ZIP encoded).
The question is what exactly you want to accomplish? If you just want to throw away this ICC based color space and create a new one, you don't need to find this data, just create a new color space object and make the image refer to your new object.
To change the existing ICC profile (which would be a bad idea in general), you'd have to decompress the stream data, adjust what you want to adjust and recompress it again.
These are followed steps:
1- Create your Quartz filter with ColorSync utility and save it as .qfilter file
2- apply this filter to your pdf file with this code:
PDFDocument *pdf = [[PDFDocument alloc]initWithURL:[NSURL fileURLWithPath:#"_pdfURL_"]];
NSDictionary *dict = [[NSDictionary alloc]initWithObjectsAndKeys:[QuartzFilter quartzFilterWithURL:[NSURL fileURLWithPath:#"_myFilter.qfilter_"]], #"QuartzFilter", nil];
[pdf writeToFile:#"_pdfFilePath_" withOptions:dict];

Get the list of available characters from the keyboard

Hi,
I would like to get the list of all available characters from the keyboard (Digital Alphabetical) in order to create a NSArray.
TISInputSourceRef source = TISCopyCurrentKeyboardInputSource();
NSLog(#"languages: %#", TISGetInputSourceProperty(source, kTISPropertyInputSourceLanguages));
NSLog(#"localized name: %#", TISGetInputSourceProperty(source, kTISPropertyLocalizedName));
I use these lines, but I can't find the right function to list the characters.
I also tried this line :
NSLog(#"List: %#", TISGetInputSourceProperty(source, kTISPropertyUnicodeKeyLayoutData));
Would you be able to get it from calling:
TISGetInputSourceProperty(source, kTISPropertyUnicodeKeyLayoutData);
That will return the 'uchr' data for the keyboard layout (if it exists), as a CFDataRef. You can read about the layout of the 'uchr' data here. You'll need to get the bytes from the CFDataRef, probably by calling something like CFDataGetBytes() or CFDataGetBytePtr().
TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource();
CFDataRef uchr = (CFDataRef)TISGetInputSourceProperty(currentKeyboard, kTISPropertyUnicodeKeyLayoutData);
const UCKeyboardLayout *keyboardLayout = (const UCKeyboardLayout*)CFDataGetBytePtr(uchr);
Byte* buffer =
(Byte*) malloc (sizeof(Byte) * CFDataGetLength(uchr));
CFDataGetBytes(
uchr,
CFRangeMake(0,CFDataGetLength(uchr)),
buffer
);
How to read the information contained in the CFDataRef ?

Expected expression before 'unsigned' ->Objective C

m_cAppIdMap is an object of a dictionary.
I want to iterate through the dictionary and to ind and remove the value pEvent.wTimerId is an unsigned short integer that is stored as key in the dictionary.
if(unsigned short* key in m_cAppIdMap) //error:Expected expression before 'unsigned'
{
(void)[self findAndRemoveEvent:pEvent];
(void)CFDictionaryRemoveValue(m_cAppIdMap,&wTimerId);
free(pEvent);
bReturn = YES;
}
I am getting an error when i try to iterate through the loop.
EDITED
-(BOOL)KillTimer:(unsigned short)wTimerId
{
stRs232Timer* pEvent;
BOOL bReturn=FALSE;
theLock = [[NSLock alloc]init];
if ([theLock tryLock]) {
// if ( m_cAppIdMap.Lookup(wTimerId,pEvent) )
// {
// (void)findAndRemoveEvent(pEvent); // remove from event queue
// (void)m_cAppIdMap.RemoveKey(wTimerId); // remove from app map
for(wTimerId in m_cAppIdMap)
{
(void)[self findAndRemoveEvent:pEvent];
(void)CFDictionaryRemoveValue(m_cAppIdMap,&wTimerId);
free(pEvent);
bReturn = YES;
}
[theLock unlock];
}
return bReturn;
}
I am getting error in this code 'selector element does not have a valid object type' . I need to search for wTimerId(key) in the m_cAppIdMap. Is it what i'm doing is correct.The commented lines above the for loop is the implementation of the same code in cpp. I coud not make the same logic over here in Objective C.
I think you meant to use for rather than if. Additionally, the fast enumeration syntax
for (x in y) can only be used on objects that implement the NSFastEnumeration protocol—typically NSArray. It looks like you're using C arrays, so this syntax won't work anyway.
you meant to write for (VARIABLE in CONTAINER) {...} -- but your sample uses if, not for.
side note: it is an error to mutate the collections you iterate over during the iteration.