Welcome to the MacNN Forums.

If this is your first visit, be sure to check out the FAQ by clicking the link above. You may have to register before you can post: click the register link above to proceed. To start viewing messages, select the forum that you want to visit from the selection below.

You are here: MacNN Forums > Software - Troubleshooting and Discussion > Developer Center > KeyDown events

KeyDown events
Thread Tools
Forum Regular
Join Date: Jan 2001
Location: San Luis Obispo, California, USA
Status: Offline
Reply With Quote
May 7, 2001, 11:56 AM
 
How do I find out which key was pressed when I keyDown even gets called?
Basically, I want to increment a variable when one key gets pressed, and decrement it when another one gets pressed. I can't find any examples that use keyboard events though.... every example either uses mousedown events, or just has buttons.

Here's the code I have right now:
Code:
- (void)keyDown: (NSEvent *)aEvent { [imageView keyDown:aEvent]; if([[aEvent charactersIgnoringModifiers] characterAtIndex:0]==13) { vel+=1; } if([[aEvent charactersIgnoringModifiers] characterAtIndex:0]==11) { vel-=1; } }

All that this does is beep at me whenever I press a character What am I doing wrong?

-Nathaniel
     
Admin Emeritus
Join Date: Oct 2000
Location: Boston, MA
Status: Offline
Reply With Quote
May 7, 2001, 12:41 PM
 
Your function is fine, but where are you sticking the code?
"Against stupidity, the gods themselves contend in vain" (Schiller)
     
robotic  (op)
Forum Regular
Join Date: Jan 2001
Location: San Luis Obispo, California, USA
Status: Offline
Reply With Quote
May 7, 2001, 03:31 PM
 
Inside my Contoller.m file (it's the same project I was doing all that image stuff with)

-Nathaniel
     
Admin Emeritus
Join Date: Oct 2000
Location: Boston, MA
Status: Offline
Reply With Quote
May 7, 2001, 04:01 PM
 
That's the problem :-)

You see, events aren't passed to everything: that would be a _huge_ waste of processor time. So events are only passed to things like windows, views, &c.
"Against stupidity, the gods themselves contend in vain" (Schiller)
     
robotic  (op)
Forum Regular
Join Date: Jan 2001
Location: San Luis Obispo, California, USA
Status: Offline
Reply With Quote
May 7, 2001, 04:07 PM
 
So I have to do a custom class of the imageView?

-Nathaniel
     
robotic  (op)
Forum Regular
Join Date: Jan 2001
Location: San Luis Obispo, California, USA
Status: Offline
Reply With Quote
May 7, 2001, 04:35 PM
 
Hmmmm... Still doesn't work.

Here's my code right now:

MyImageView.h :
Code:
#import <Cocoa/Cocoa.h> @interface MyImageView : NSImageView { } - (void)keyDown: (NSEvent *)aEvent; @end
MyImageView.m:
Code:
#import "MyImageView.h" #import "Controller.h" @implementation MyImageView - (void)keyDown: (NSEvent *)aEvent { [self keyDown:aEvent]; if([[aEvent charactersIgnoringModifiers] characterAtIndex:0]==13) { [Controller increaseVel]; } if([[aEvent charactersIgnoringModifiers] characterAtIndex:0]==11) { [Controller decreaseVel]; } } @end
Controller.h:
Code:
#import <Cocoa/Cocoa.h> #import "MyImageView.h" @interface Controller : NSObject { IBOutlet id imageView; NSTimer *timer; int y; int vel; NSImageRep *rep; NSSize size; } + (void)increaseVel; + (void)decreaseVel; - (void)initImage; - (void)triggerImage:(NSTimer)arg; - (void)displayImage; @end
Controller.m:
Code:
#import "Controller.h" @implementation Controller - (void)applicationDidFinishLaunching: (NSNotification *)notification { [self initImage]; timer= [[NSTimer scheduledTimerWithTimeInterval: 0.01 target:self selector:@selector(triggerImage:) userInfo:nil repeats:YES ] retain]; } - (void)triggerImage:(NSTimer)arg { [self displayImage]; } - (void)initImage { y=0; vel=0; [imageView lockFocus]; [[NSColor blackColor] set]; NSRectFill(NSMakeRect(0, 0, 450, 350)); [imageView unlockFocus]; rep = [[NSImage imageNamed:@"Planet.gif"] bestRepresentationForDevice:nil]; size = NSMakeSize(100, 100); [rep setSize:size]; } - (void)displayImage { [imageView lockFocus]; [[NSColor blackColor] set]; NSRectFill(NSMakeRect(0, y, 100, 100)); if(y<350) {y+=vel; } else { y=-100; } [rep drawAtPoint:NSMakePoint(0, y)]; [[imageView window] flushWindow]; [imageView unlockFocus]; } + (void)increaseVel { vel+=1; } + (void)decreaseVel { vel-=1; } @end
It compiles, but it still just beeps when I press any key.

What's going wrong?

-Nathaniel
     
Dedicated MacNNer
Join Date: Jan 2001
Location: Virginia, US
Status: Offline
Reply With Quote
May 7, 2001, 05:32 PM
 
If the app is beeping, that means a responder wasn't found for the event. For keystrokes, this means that there isn't a firstResponder set on the active NSWindow, the one that is receiving the keystrokes.

You could add a call like [[imageView window] makeFirstResponder:imageView] in the app startup stuff so that your view is the first responder (i.e. the view that receives events first). You could also connect the "initialFirstResponder" outlet for the window to your view in InterfaceBuilder.

For more info on the responder chain, you can see my posts in a previous thread. http://forums.macnn.com/cgi-bin/Foru...ML/000444.html

For what you're doing though, you shouldn't be using an NSImageView subclass. That class is for displaying a static NSImage, which you're not doing. You're doing your own drawing, so you just need a custom NSView subclass.

Something more like (100% untested):
Code:
@interface MyView : NSView { int vel; int currentY; int lastY; } - (void)incrementPosition; @end @implementation MyView static NSImageRep *planetRep = nil; + (void)initialize { if (planetRep == nil) { NSImage *planetImage = [NSImage imageNamed:@"Planet.gif"]; planetRep = [planetImage bestRepresentationForDevice:nil]; [planetRep setSize:NSMakeSize(100.0, 100.0)]; [planetRep retain]; } } - initWithFrame:(NSRect)frame { [super initWithFrame:frame]; lastY = -1; return self; } - (void)drawRect:(NSRect)rect { NSRect eraseRect; if (lastY < 0) // first time through eraseRect = [self frame]; else eraseRect = NSMakeRect(0, lastY, 100, 100); [[NSColor blackColorSet]; NSRectFill(eraseRect); [planetRep drawAtPoint:NSMakePoint(0, currentY)]; // You could just use an NSImage directly with // compositeAtPoint:operation:; that is far more // commonly done than using image reps directly, // but whatever lastY = currentY; } - (void)incrementPosition { if (currentY < NSWidth([self frame])) currentY += vel; else currentY -= 100; [self setNeedsDisplay:YES]; } - (void)keyDown: (NSEvent *)aEvent { if([[aEvent charactersIgnoringModifiers] characterAtIndex:0]==13) { vel++; } else if([[aEvent charactersIgnoringModifiers] characterAtIndex:0]==11) { vel--; } else { [super keyDown:aEvent]; } } @end
In IB, use the "CustomView" widget and use its attributes inspector to change the class to MyView (you'll have to parse the MyView header into IB first). You'll want to make it the window's initialFirstResponder too.

Now, your displayImage method should just call -incrementPosition on the view, and the regular view machinery should do the rest. If you need to force it (I don't think it should be necessary but...), you could call [myView display]; [[myView window] flushWindow]; in the displayImage implementation as well.
     
robotic  (op)
Forum Regular
Join Date: Jan 2001
Location: San Luis Obispo, California, USA
Status: Offline
Reply With Quote
May 7, 2001, 08:10 PM
 
Hmmm. Now it doesn't move the image at all (I even set it to +=1 instead of += vel to see if it moved at all)
here's my code:

Code:
#import <Cocoa/Cocoa.h> @interface MyView : NSView { int vel; int currentY; int lastY; NSTimer *timer; } - (void)incrementPosition; - (void)triggerImage NSTimer)arg; @end #import "MyView.h" @implementation MyView static NSImageRep *planetRep = nil; - (void)applicationDidFinishLaunching: (NSNotification *)notification { timer= [[NSTimer scheduledTimerWithTimeInterval: 0.01 target:self selector:@selector(triggerImage userInfo:nil repeats:YES ] retain]; } - (void)triggerImage NSTimer)arg { [self incrementPosition]; [self display]; [[self window] flushWindow]; } + (void)initialize { if (planetRep == nil) { NSImage *planetImage = [NSImage imageNamed:@"Planet.gif"]; planetRep = [planetImage bestRepresentationForDevice:nil]; [planetRep setSize:NSMakeSize(100.0, 100.0)]; [planetRep retain]; } } - initWithFrame NSRect)frame { [super initWithFrame:frame]; lastY = -1; return self; } - (void)drawRect NSRect)rect { NSRect eraseRect; if (lastY < 0) eraseRect = [self frame]; else eraseRect = NSMakeRect(0, lastY, 100, 100); //[NSColor blackColorSet]; NSRectFill(eraseRect); [planetRep drawAtPoint:NSMakePoint(0, currentY)]; lastY = currentY; } - (void)incrementPosition { if (currentY < NSWidth([self frame])) currentY +=1; //vel; else currentY = -100; [self setNeedsDisplay:YES]; } - (void)keyDown: (NSEvent *)aEvent { if([[aEvent charactersIgnoringModifiers] characterAtIndex:0]==1) { vel++; } else if([[aEvent charactersIgnoringModifiers] characterAtIndex:0]==26) { vel--; } else { [super keyDown:aEvent]; } } @end
Do I need to do the timer parts in a different class? Does applicationDidFinishLaunching not get called from MyView?

Thank you very much for all your help,
-Nathaniel
     
Dedicated MacNNer
Join Date: Jan 2001
Location: Virginia, US
Status: Offline
Reply With Quote
May 7, 2001, 08:23 PM
 
-applicationDidFinishLaunching: is not called on your view class. It is an application delegate method, meaning it will be called on whichever object is set up as the delegate of the NSApplication instance in the main nib. Presumably for you, this was your Controller class. You can keep your timing code in that class, and have Controller have an outlet to your view, and just call the view's increment position from there.

Alternatively, you could start up the timer from the view's -initWithFrame: method.
     
   
Thread Tools
Forum Links
Forum Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On
Top
Privacy Policy
All times are GMT -5. The time now is 10:00 PM.
All contents of these forums © 1995-2011 MacNN. All rights reserved.
Branding + Design: www.gesamtbild.com
vBulletin v.3.8.7 © 2000-2011, Jelsoft Enterprises Ltd., Content Relevant URLs by vBSEO 3.3.2