 |
 |
KeyDown events
|
 |
|
 |
|
Forum Regular
Join Date: Jan 2001
Location: San Luis Obispo, California, USA
Status:
Offline
|
|
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
|
|
Your function is fine, but where are you sticking the code?
|
|
"Against stupidity, the gods themselves contend in vain" (Schiller)
|
| |
|
|
|
 |
|
 |
|
Forum Regular
Join Date: Jan 2001
Location: San Luis Obispo, California, USA
Status:
Offline
|
|
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
|
|
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)
|
| |
|
|
|
 |
|
 |
|
Forum Regular
Join Date: Jan 2001
Location: San Luis Obispo, California, USA
Status:
Offline
|
|
So I have to do a custom class of the imageView?
-Nathaniel
|
|
|
| |
|
|
|
 |
|
 |
|
Forum Regular
Join Date: Jan 2001
Location: San Luis Obispo, California, USA
Status:
Offline
|
|
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
|
|
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.
|
|
|
| |
|
|
|
 |
|
 |
|
Forum Regular
Join Date: Jan 2001
Location: San Luis Obispo, California, USA
Status:
Offline
|
|
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:
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
|
|
-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.
|
|
|
| |
|
|
|
 |
 |
|
 |
|
|
|
|
|

|
|
 |
Forum Rules
|
 |
 |
|
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
|
HTML code is Off
|
|
|
|
|
|
 |
 |
 |
 |
|
 |
|