Pergunta

O iTunes mini-jogador (para dar apenas um exemplo) suportes click-through, onde a aplicação não é trazido para a frente quando os controles de play / pause e volume são usados.

Como isso é feito?

Eu tenho procurado através de documentação da Apple e ter um pouco de continuar, em Cocoa Guia de manipulação de eventos, Despacho Evento ele afirma:

Alguns eventos, muitos dos quais são definidos pelo Kit Aplicação (tipo NSAppKitDefined), tem a ver com ações controladas por uma janela ou o próprio objeto do aplicativo. Exemplos desses eventos são os relacionados com a activação, desactivação, escondendo, e mostrando a aplicação. NSApp filtra esses eventos no início de sua rotina de distribuição e manipula-los em si.

Assim, a partir de minha compreensão limitada ( Como um evento Insere um Cocoa, Aplicação) subclassificação NSApplication e substituindo - (void)sendEvent:(NSEvent *)theEvent deve armadilha cada mouse e teclado evento, mas ainda assim, a janela é gerado em clique. Assim, ou a janela é levantada antes do evento é visto por NSApplication ou estou faltando alguma coisa.

Eu olhei de Matt Gallagher Desmistificando NSApplication recriando-lo , infelizmente Matt não cobrir a fila de eventos, de modo diferente do que, eu estou perplexo.

Qualquer ajuda seria apreciada, obrigado.

Editado para adicionar: Encontrado um post em Salão de Lloyd em que ele fala sobre o mesmo problema e links para um posto em CocoaBuilder, rato captura de primeira à direita para baixo . Atualmente estou tentando o código fornecido lá, depois de algum brincar e reativando o NSLog para [tipo TheEvent], a atividade botão esquerdo do mouse está sendo capturado.

Agora, o botão esquerdo na janela para trazê-lo para a frente produz uma seqüência de tipos de eventos, 13, 1, 13, estes são NSAppKitDefined, NSLeftMouseDown e NSAppKitDefined novamente. Posso filtrar estes para fora ou encontrar onde eles estão indo?

Foi útil?

Solução 2

Esta não é a resposta que eu estava procurando, mas por enquanto ele funciona suficientemente bem. Por subclasse NSView e implementação dos seguintes métodos, essa visão pode atuar como um botão.

- (void)mouseDown:(NSEvent *)theEvent {
    [NSApp preventWindowOrdering];
//  [self setNeedsDisplay:YES];
}

- (BOOL)acceptsFirstMouse:(NSEvent *)theEvent {
    return YES;
}

- (BOOL)shouldDelayWindowOrderingForEvent:(NSEvent *)theEvent {
    return YES;
}

Nada mais é necessário, é isso. Claro que isso ignora toda a bondade NSButton que eu queria manter, eu tenho que projetar e em seguida, tomar o cuidado de desenhar e atualizar os estados de botão, mas eu estou feliz de ter uma resposta.

Outras dicas

Isso pode ser feito com um NSPanel que tem sido definido para não esconder em desativar e tornar-se única chave conforme necessário. Isso também pressupõe que os controles que você estará usando retorno YES para -acceptsFirstMouse:; NSButtons fazê-lo por padrão.

Você pode desativar o couro na bandeira desativar por meio IB para o painel, mas você vai precisar para emitir a mensagem -setBecomesKeyOnlyIfNeeded:YES para o painel para mantê-lo eo app de vir para a frente em cliques de botão.

É possível fazer uma respondem NSButton de click-through eventos sem alterar seu comportamento quando o aplicativo está ativo:

Interface (ClickThroughButton.h):

#import <AppKit/AppKit.h>

@interface ClickThroughButton : NSButton

@end

Implementação (ClickThroughButton.m):

#import "ClickThroughButton.h"

@implementation ClickThroughButton

- (BOOL)shouldDelayWindowOrderingForEvent:(NSEvent *)theEvent {
    return ![NSApp isActive];    
}

- (void)mouseDown:(NSEvent *)theEvent {    
    if (![NSApp isActive]) {
        [NSApp preventWindowOrdering];        

        [self highlight:YES];

        NSEvent *mouseUpEvent = [[self window] nextEventMatchingMask:NSLeftMouseUpMask
                                                  untilDate:[NSDate distantFuture]
                                                     inMode:NSEventTrackingRunLoopMode
                                                    dequeue:YES];
        NSPoint mouseLocation = [self convertPoint:[mouseUpEvent locationInWindow] fromView:nil];
        BOOL mouseUpInside = [self mouse:mouseLocation inRect:[self bounds]];

        if (mouseUpInside) {
            if ([self target])
                [[self target] performSelector:[self action] withObject:self]; 
        }

        [self highlight:NO];            

    } else {
        [super mouseDown:theEvent];        
    }
}

@end

Você verificou para fora acceptsFirstMouse:? Qualquer NSView pode retornar YES a este evento para dizer que a vista deve manipular o evento em vez de trazer a janela para o primeiro plano. Presumivelmente, interceptando o evento, ele não será usado para trazer a janela para o primeiro plano, mas não posso confirmar isso.

Você, obviamente, precisa subclasse qualquer controle que você quer ter esse comportamento para acceptsFirstMouse: substituição.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top