Return clicked word

I’m a newbie in applescript studio but i’ve writed in the past hypercard stacks. I want to get a word clicked (in a text view) to play a sound. For example if i click on the word “mouse”, the sound “mouse” is played. It was possible with hypercard but i can’t found with applescript studio

sorry for my english (im french !)

yvo

Salut Yvo,

unfortunately handling mouse clicks on single words/characters in a text view is not a standard feature. I don’t think it’s possible with AppleScript.
Here’s a solution using some Objective-C - implemented as a subclass of NSTextView. Since you wrote you were a ‘newbie’ here a step by step guide:

  1. in Interface Builder:
  • click the ‘Classes’ tab of the Nib’s document window
  • select your Text View (not it’s enclosing scroll view)
  • in the Classes tab you should now see the object hierarchy to NSTextView selected
  • Ctrl-Click or Right-Mousebutton-Click (Context Menu) on the class NSTextView and choose ‘Subclass NSTextView’
  • Name the new Subclass - for example MyTextView
  • Choose ‘Create files for …’ from the new subclasses context menu
  • select your text view again and choose ‘Custom Class’ from the Inspector window (or activate it by pressing Apple + 5)
  • choose the new subclass for your text view
  • in the Instances Tab of the nib’s document window: connect File’s Owner to at least one of the handlers in your script
  1. in Xcode:
  • add a handler like this in your script:
on clickedWord(theWord)
	say theWord -- for example
end clickedWord

edit the subclass file MyTextView.m:

#import "MyTextView.h"

@implementation MyTextView

- (void)awakeFromNib {
	[[self window] setAcceptsMouseMovedEvents:YES];
}

- (void)mouseDown:(NSEvent *)theEvent{

    NSLayoutManager *layoutManager = [self layoutManager];
    NSTextContainer *textContainer = [self textContainer];
    unsigned glyphIndex, charIndex;
    NSPoint point = [self convertPoint:[theEvent locationInWindow] fromView:nil];
    NSRange lineGlyphRange, lineCharRange, wordCharRange;
	NSRect glyphRect;
    
    // Convert view coordinates to container coordinates
    point.x -= [self textContainerOrigin].x;
    point.y -= [self textContainerOrigin].y;
    
    // Convert those coordinates to the nearest glyph index
    glyphIndex = [layoutManager glyphIndexForPoint:point inTextContainer:textContainer];
    
    // Check to see whether the mouse actually lies over the glyph it is nearest to
    glyphRect = [layoutManager boundingRectForGlyphRange:NSMakeRange(glyphIndex, 1) inTextContainer:textContainer];
    if (NSPointInRect(point, glyphRect)) {
        // Convert the glyph index to a character index
        charIndex = [layoutManager characterIndexForGlyphAtIndex:glyphIndex];

        // Determine the range of glyphs, and of characters, in the corresponding line
        (void)[layoutManager lineFragmentRectForGlyphAtIndex:glyphIndex effectiveRange:&lineGlyphRange];        
        lineCharRange = [layoutManager characterRangeForGlyphRange:lineGlyphRange actualGlyphRange:NULL];
        
        // Determine the word containing that character
        wordCharRange = NSIntersectionRange(lineCharRange, [self selectionRangeForProposedRange:NSMakeRange(charIndex, 0) granularity:NSSelectByWord]);
 		NSString *clickedWord = [[self string] substringWithRange:wordCharRange];
		NSAppleScript *callASHandler = [[NSAppleScript alloc] initWithSource:
			[NSString stringWithFormat:@"(get my script)'s clickedWord(\"%@\")",clickedWord]];
       [callASHandler executeAndReturnError:nil];
	   [callASHandler release];
    }
	[super mouseDown];
}

@end

Note: the biggest part of the subclass is ©Apple - ‘stolen’ from the example LayoutManagerDemo …

hope that helps …

Dominik

thank you very much
i will try it

(sorry for my english !)

yvo

yvo,
You don’t need to apologize for your english, yours is fine. It’s the people who SPEAK english that usually have the worst! :stuck_out_tongue:

Take care,
j

You could put a button over the text view and then make it invisible.

Hi yvo, Dominik.

You can also use NSTextStorage’s -doubleClickAtIndex: to find the range of a word.
i.e. Following on from what you had:

[code]- (void)mouseDown:(NSEvent *)theEvent
{
NSLayoutManager *lm = [self layoutManager];
NSTextContainer *tc = [self textContainer];
NSPoint mousePoint = [self convertPoint:[theEvent locationInWindow] fromView:nil];
NSPoint tcOrigin = [self textContainerOrigin];
mousePoint.x -= tcOrigin.x;
mousePoint.y -= tcOrigin.y;

unsigned int glyphIndex = [lm glyphIndexForPoint:mousePoint inTextContainer:tc fractionOfDistanceThroughGlyph:NULL];
NSRect glyphBounds = [lm boundingRectForGlyphRange:NSMakeRange(glyphIndex, 1) inTextContainer:tc];
if (NSPointInRect(mousePoint, glyphBounds)) {
	NSTextStorage *ts = [self textStorage];
	unsigned int charIndex = [lm characterIndexForGlyphAtIndex:glyphIndex];
	/*** Apple's documentation of -doubleClickAtIndex: ***
	 Returns the range of characters that form a word (or other linguistic unit) surrounding the given index, taking language characteristics into account.
	 */
	NSRange stringRange = [ts doubleClickAtIndex:charIndex];
	NSString *clickedString = [[ts string] substringWithRange:stringRange];
	
	// Reject if string is only whitespace
	NSCharacterSet *charSet = [NSCharacterSet whitespaceAndNewlineCharacterSet];
	clickedString = [clickedString stringByTrimmingCharactersInSet:charSet];
	if (![clickedString isEqualToString:@""]) {
		// Do something with string
		NSLog(clickedString);
	}
}

}[/code]
Additions have also been included to reject whitespace-only strings.

The problem is getting the required word under the mouse, not receiving mouse events.

Hi Qwerty,

many thx for the improved code - cool solution!

D.

Hello !
It’s Yvo again.
I’m trying to apply the contents of these messages.
I can’t understand how connect Files’s Owner (an icon with the A of application in the instances tab) with the handler.
What Handler ? the applescript file?

Thanxs 4 your replies

quote

  • in the Instances Tab of the nib’s document window: connect File’s Owner to at least one of the handlers in your script
    /quote

Yvo

Hi Yvo,

sorry, I should have been more precise …

  • select the File’s Owner Icon in the instances tab and open the AppleScript Tab of the Inspector for it (hit Apple+8)
  • then check one of the Applescript handlers - for example Application → open
  • it’s not necessary to add any script command in the handler - it might look like this:

on open theObject

end open

This part is necessary for being able to address the clickedWord-handler in my example as “(get my script)'s clickedWord” from the objective-c part …

D.

Thanxxxxxxs you Dominik !
It’s run !
Like it, i can continue to write a small program for the schoolchilds of my class : a program that show images with the word and play the sound of the word (also with the syllabes, phonèmes and the name of the letters).
I’m a teacher !
If i can write this program with the images drawn by schoolchild (for the moment i can use image copyrighted from a schoolbook) and maybe their voices, i will publish it freely and i will post here the link for the download. I will acknowledge strongly Dominik and the MacScripter (bbs.applescript.net).

Bye

Yvo

P.S. Sorry for my english again.