I want to enable keyboard shortcuts like Cmd+c , Cmd+v to work on webpages loaded inside WKWebView, but cannot find a solution.
Webview on the other hand has methods like Copy/Paste/Cut which could be leveraged by overriding (void)keyDown:(NSEvent *)event method. But WKWebView does not seem to have any similar funtion.
In WebView i could do something like
- (void)keyDown:(NSEvent *)event {
NSString *s = [event charactersIgnoringModifiers];
if (s == nil)
return;
if (([event modifierFlags] & NSDeviceIndependentModifierFlagsMask) == NSCommandKeyMask)
{
if ([s caseInsensitiveCompare:#"a"] == NSOrderedSame)
{
if ([[self firstResponder] respondsToSelector:#selector(selectAll:)])
[self.contentView selectAll:self];
}
else if ([s caseInsensitiveCompare:#"c"] == NSOrderedSame)
{
if ([[self firstResponder] respondsToSelector:#selector(copy:)])
[self.contentView copy:self];
}
else if ([s caseInsensitiveCompare:#"v"] == NSOrderedSame)
{
if ([[self firstResponder] respondsToSelector:#selector(paste:)])
[self.contentView paste:self];
}
else if ([s caseInsensitiveCompare:#"x"] == NSOrderedSame)
{
if ([[self firstResponder] respondsToSelector:#selector(cut:)])
[self.contentView cut:self];
}
else if ([s caseInsensitiveCompare:#"z"] == NSOrderedSame)
{
[self.contentView undo];
}
}
else
{
[super keyDown:event];
} }
In the above code self.contentView points to a WebView object
Related
I need to allow two-finger pinch/rotate/panning and deny single-finger panning.
I've tried some ways to achieve this:
for (UIPanGestureRecognizer *pan in mapView.gestureRecognizers) {
if ([pan isKindOfClass:[UIPanGestureRecognizer class]]) {
if ([pan minimumNumberOfTouches] < 2) {
[pan setMinimumNumberOfTouches:2];
}
}
}
But this not works. Maybe some kind of UIGestureRecognizer failing dependency?
Just found nice solution:
self.twoFingerPan = [[UIPanGestureRecognizer alloc] init];
self.twoFingerPan.maximumNumberOfTouches = 1;
self.twoFingerPan.delegate = self;
[self addGestureRecognizer:self.twoFingerPan];
...
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
if (gestureRecognizer == self.twoFingerPan &&
[otherGestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]] &&
(otherGestureRecognizer.view == self.mapView ||
otherGestureRecognizer.view.superview == self.mapView)) {
return YES;
}
return NO;
}
And addition to allow any outer scrolling:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
if (gestureRecognizer == self.twoFingerPan &&
[otherGestureRecognizer.view isKindOfClass:[UIScrollView class]]) {
return YES;
}
return NO;
}
I'm trying to implement an async voice recording feature. There's a button that has a UILongPressGestureRecognizer and this starts the recording. Right now, when they let go, the recording is saved and sent.
#pragma mark - Actions
- (void) recordButtonPressed:(UILongPressGestureRecognizer *)gesture
{
if (gesture.state == UIGestureRecognizerStateBegan) {
[self.voiceRecorderView.recordButton setImage:[UIImage imageNamed:kWSGreyDotXLarge] forState:UIControlStateNormal];
[self startRecording];
}
if (gesture.state == UIGestureRecognizerStateEnded) {
[self stopRecording];
[self.voiceRecorderView.recordButton setImage:[UIImage imageNamed:kWSPinkDotXLarge] forState:UIControlStateNormal];
}
}
This works, but now I need to copy the now standard feature of allowing the user to drag their finger off the button while it's pressed to cancel the recording.
How to add a gestureRecognizer to tell if a user drags outside the control but is still pressing it?
I hope it will work for you....
BOOL cancelflag;
UIButton *recordBtn;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(handleLongPress:)];
[longPress setDelegate:self];
[recordBtn addGestureRecognizer:longPress];
}
-(void)handleLongPress:(UILongPressGestureRecognizer *)longPressRecognizer
{
if(longPressRecognizer.state == UIGestureRecognizerStateBegan)
{
if (!stopBtnFlag)
{
if (!audioRecorder.recording)
{
[self performSelectorOnMainThread:#selector(setUpAudioRecorder) withObject:nil waitUntilDone:YES];
[audioRecorder record];
NSLog(#"Recording...");
}
stopBtnFlag = YES;
cancelflag =YES;
}
}
else if (longPressRecognizer.state == UIGestureRecognizerStateChanged)
{
[audioRecorder stop];
stopBtnFlag = NO;
NSLog(#"moved");
}
else if (longPressRecognizer.state == UIGestureRecognizerStateEnded)
{
if(cancelflag)
{
[audioRecorder stop];
[self playmusic];
}
}
}
#Jaleel's answer gave me a start. Here's a complete working version:
- (void) recordButtonPressed:(UILongPressGestureRecognizer *)gesture
{
if (gesture.state == UIGestureRecognizerStateBegan) {
[self.voiceRecorderView setCancelText:WSCancelLabelTextStart];
if (!audioRecorder.recording)
{
[self startRecording];
}
cancelflag = NO;
}
else if (gesture.state == UIGestureRecognizerStateChanged)
{
CGPoint touchPoint = [gesture locationInView:self.voiceRecorderView];
if (!CGRectContainsPoint(self.voiceRecorderView.recordButton.frame, touchPoint )) {
cancelflag = YES;
[self.voiceRecorderView.recordButton setImage:[UIImage imageNamed:kWSGreyDotXLarge] forState:UIControlStateNormal];
[self.voiceRecorderView setCancelText:WSCancelLabelTextCancelling];
}
else {
cancelflag = NO;
[self.voiceRecorderView.recordButton setImage:[UIImage imageNamed:kWSPinkDotXLarge] forState:UIControlStateNormal];
[self.voiceRecorderView setCancelText:WSCancelLabelTextStart];
}
}
else if (gesture.state == UIGestureRecognizerStateEnded) {
[self stopRecording];
if(!cancelflag)
{
[self sendRecording:self.recordingURL];
}
else {
[self.voiceRecorderView setCancelText:WSCancelLabelTextCancelled];
}
[self.voiceRecorderView resetView];
}
}
i had displayed some images in collectionview. now i want to select the image and press space button. If i pressed Space button , the image should quicklook in a seperate window. any idea?
On your view, do this:
- (void)keyDown:(NSEvent *)event
{
unichar firstChar = 0;
if ([[event charactersIgnoringModifiers] length] > 0)
firstChar = [[event charactersIgnoringModifiers] characterAtIndex:0];
if (firstChar == ' ')
{
if ([QLPreviewPanel sharedPreviewPanelExists]
&& [[QLPreviewPanel sharedPreviewPanel] isVisible])
{
[[QLPreviewPanel sharedPreviewPanel] orderOut:nil];
}
else
{
[[QLPreviewPanel sharedPreviewPanel] makeKeyAndOrderFront:nil];
[[NSApp mainWindow] makeKeyWindow];
}
}
else if (firstChar == NSRightArrowFunctionKey)
{
if ([QLPreviewPanel sharedPreviewPanelExists]
&& [[QLPreviewPanel sharedPreviewPanel] isVisible])
{
[[QLPreviewPanel sharedPreviewPanel] selectNextItem];
return;
}
}
else if (firstChar == NSLeftArrowFunctionKey)
{
if ([QLPreviewPanel sharedPreviewPanelExists]
&& [[QLPreviewPanel sharedPreviewPanel] isVisible])
{
[[QLPreviewPanel sharedPreviewPanel] selectPreviousItem];
return;
}
}
else
[super keyDown:event];
}
Then, I do this in my app's delegate (AppDelegate.m):
- (BOOL)acceptsPreviewPanelControl:(QLPreviewPanel *)panel
{
//note that this methods indeed gets called because NSApp's
//delegate is in the responder chain.
return YES;
}
- (void)beginPreviewPanelControl:(QLPreviewPanel *)panel
{
previewPanel = panel; //set an ivar
[panel setDataSource:self];
}
- (void)endPreviewPanelControl:(QLPreviewPanel *)panel
{
previewPanel = nil;
}
- (NSInteger)numberOfPreviewItemsInPreviewPanel:(QLPreviewPanel *)panel
{
//return a number of your choice (depends on your own app)
}
- (id <QLPreviewItem>)previewPanel:(QLPreviewPanel *)panel
previewItemAtIndex:(NSInteger)index
{
//return an object of your choice (depends on your app)
}
- (void)handleCurrentFileItemsSelectionChange:(NSNotification *)note
{
[previewPanel reloadData]; //referring to the ivar
}
i finally got. i just replaced imageViewes and put NSButton and setted spacebutton as keyequivalent as
- (BOOL)isOneOfMyKeyEquivs:(NSString *)keyChar
{
if (([keyChar isEqualToString:#" "])||([keyChar isEqualToString:#"\r"])) {
return YES;
} else {
return NO;
}
}
- (BOOL)performKeyEquivalent:(NSEvent *)theEvent
{
//NSLog(#"OK");
NSString* keyChar = [theEvent characters];
if ([self isOneOfMyKeyEquivs:keyChar])
{
[[self cell] setKeyEquivalent:keyChar];
}
return [super performKeyEquivalent:theEvent];
return NO;
}
and performed button action.
I want to stop bounce in webview. can my app get rejected in appstore if I use following statement in my code?
self.viewController.webView.scrollView.bounces = NO;
Thanks!
if ([[[UIDeice currentDevice] SystemVersion] floatValue] >= 5.0)//iOS>=5.0
{
webView.scrollView.bounces = NO;
}
else//iOS<5.0
{
for (id subview in webView.subviews)
{
if ([[subview class] isSubclassOfClass: [UIScrollView class]])
((UIScrollView *)subview).bounces = NO;
}
}
if (webView respondsToSelector:#selector(scrollView)]) {
webView.scrollView.bounces = NO;
} else {
for (id subview in webView.subviews) {
if ([[subview class] isSubclassOfClass:[UIScrollView class]]) {
((UIScrollView*)subview).bounces = NO;
}
}
}
I got a big problem with NSInvocationOperation. When I run on my iPod 4, firmware 5.0.1, it's OK. But on my iPhone 4, iOS 4.1, it crashed. This is my code:
CustomAnnotation *annotation = [[[ModelManager defaultModelManager] getAnnotationDictionaryInMemory] objectForKey:joltId];
if (annotation == nil)
annotation = [[[ModelManager defaultModelManager] getAnnotationDictionaryInMemory] annotationWithInstagramId:eID];
if (annotation == nil)
continue;
//THIS ONE CRASH ON IPHONE 4 OS 4.1
NSDictionary *param = [[NSDictionary alloc] initWithObjectsAndKeys: #"aKey", #"aValue", nil];
NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:annotation selector:#selector(updateAnnotation:) object:param];
[_queue addOperation:op];
[op autorelease];
updateAnnotation function was defined in CustomAnnotation class:
- (void)updateAnnotation:(id)sender {
//NSLog(#"UPDATE ANNOTATION ID: %#", self.annoID);
NSDictionary *senderDic = (NSDictionary *)sender;
UzooltAppDelegate* appDelegate = (UzooltAppDelegate*) [UIApplication sharedApplication].delegate;
if ([senderDic objectForKey:#"nb_rejolt"] != nil) {
NSInteger new_nb_rejolts = [[senderDic objectForKey:#"nb_rejolt"] intValue];
//if (new_nb_rejolts != rejolts) {
//NSLog(#"update nb rejolts: %d", new_nb_rejolts);
if (self.rejolts != new_nb_rejolts) {
self.rejolts = new_nb_rejolts;
//if (self.isGrouped)
// [self.masterAnnotation.annotationView performSelectorOnMainThread:#selector(updateAnnotationViewWithRejolts:) withObject:[NSString stringWithFormat:#"%d", rejolts] waitUntilDone:NO];
//else
if ([senderDic objectForKey:#"rejolt_fbid"] != nil) {
NSString *fbRejoltsString = [senderDic objectForKey:#"rejolt_fbid"];
self.fbRejolts = [[fbRejoltsString componentsSeparatedByString:#","] mutableCopy];
[self.fbRejolts removeLastObject];
[self updateNumberOfRejoltsFromFBFrds];
}
[self.annotationView performSelectorOnMainThread:#selector(updateAnnotationViewWithRejolts:) withObject:[NSString stringWithFormat:#"%d", rejolts] waitUntilDone:NO];
}
if (self.isGrouped) {
if (self.masterAnnotation.isShowingRadius == NO && appDelegate.uMainViewController.isInGroup == NO && ( new_nb_rejolts > self.masterAnnotation.rejolts || (new_nb_rejolts == self.masterAnnotation.rejolts && self.getAge < self.masterAnnotation.getAge))) {
[self.masterAnnotation removeFromGroupedAnnotations:self];
self.annotationView.hidden = NO;
[self.annotationView performSelectorOnMainThread:#selector(showWithAlpha:) withObject:[NSNumber numberWithFloat:annotationAlpha] waitUntilDone:NO];
[[NSNotificationCenter defaultCenter] postNotificationName:#"need_group_annotations" object:nil];
}
}
//}
}
if ([senderDic objectForKey:#"lifetime"] != nil) {
float new_lifetime = [[senderDic objectForKey:#"lifetime"] floatValue]*3600;
//NSLog(#"new lifetime: %.f", new_lifetime);
if (new_lifetime != lifetime) {
//NSLog(#"update lifetime");
self.lifetime = new_lifetime;
}
}
[self updateViewAlpha];
if ([senderDic objectForKey:#"radius"] != nil) {
float new_radius = [[senderDic objectForKey:#"radius"] floatValue];
if (new_radius != radius) {
//NSLog(#"update lifetime");
self.radius = new_radius;
}
}
/*
if ([appDelegate.uMainViewController isMaximumZoomIn])
[[self annotationView] performSelectorOnMainThread:#selector(setGroupNumberIndicatorVisible:) withObject:[NSNumber numberWithBool:YES] waitUntilDone:NO];
else
[[self annotationView] performSelectorOnMainThread:#selector(setGroupNumberIndicatorVisible:) withObject:[NSNumber numberWithBool:NO] waitUntilDone:NO];
*/
if (isSelected == YES && isShowingRadius == NO ) {
//NSLog(#"update details");
[self performSelectorOnMainThread:#selector(updateDetailsView) withObject:nil waitUntilDone:NO];
UzooltAppDelegate* appDelegate = (UzooltAppDelegate*) [UIApplication sharedApplication].delegate;
if (isGrouped == YES && appDelegate.uMainViewController.isInGroup) {
NSLog(#"grouped jolt rejolted");
[self performSelectorOnMainThread:#selector(updateInGroupAnnotationView) withObject:nil waitUntilDone:NO];
}
}
}
I don't know where it wrong? Please help me. Thanks all !!!
Try running with NSZombies enabled. It should at least give you a hint as to what object you are trying to access after it has been deallocated.
NSZombies enabled, debug information