Python implementa controle de projeção de tela em tempo real do Android

cliente scrcpy

        Existe uma biblioteca scrcpy-client em python, que pode realizar screencasting e controle em tempo real de dispositivos Android. É o mesmo que scrcpy para implementar o screencasting do Android. Ambos enviam um arquivo scrcpy-server.jar para o dispositivo Android por meio do adb e usam instruções do adb para executar scrcpy-server.jar para iniciar o screencasting e controlar o servidor. O lado do computador usa python Crie um cliente para receber dados de fluxo de vídeo e enviar dados de fluxo de controle. Os dados do fluxo de vídeo são dados da tela do Android em tempo real, e os dados do fluxo de controle são as ações de controle que realizamos no dispositivo Android no lado do computador. Na biblioteca scrcpy-client, o autor fornece uma interface UI de controle de projeção de tela construída usando PySide6, que pode completar o controle de projeção de tela de um único dispositivo Android. Podemos fazer nossa própria interface de controle de projeção de tela para completar o controle de projeção de tela de vários Dispositivos Android.

Instruções de instalação: pip3 install scrcpy-client

Usar diretamente

        Depois de instalar a biblioteca scrcpy-client, podemos usar diretamente a interface UI fornecida pelo autor para espelhar o dispositivo Android.

import scrcpy_ui


scrcpy_ui.main()

Certifique-se de que um dispositivo Android esteja conectado ao nosso computador via USB e que a função de depuração USB do dispositivo Android esteja ativada e que o computador possa ser depurado. Neste momento, podemos obter a interface UI do screencasting do dispositivo Android executando o código acima, conforme mostrado na figura a seguir:

​​​​​​​

Nesta interface, podemos usar o mouse para clicar e deslizar na interface de projeção da tela para controlar a tela do dispositivo Android. Você pode trocar de dispositivo por meio da caixa suspensa do número de série do dispositivo. Depois de marcar Flip, você pode obter uma tela espelhada. Clique no botão HOME abaixo para retornar à tela inicial, o que equivale a pressionar o botão home do dispositivo. Após clicar no botão VOLTAR, ele retornará à interface anterior, o que equivale a pressionar a tecla Voltar do aparelho. Ele também suporta entrada de teclado. Podemos permitir que o Android gere eventos importantes por meio do teclado do computador.

Uso personalizado

        Se você acha que a interface UI fornecida pelo autor não atende às suas necessidades, também podemos personalizar a interface UI para implementar mais métodos de operação. A premissa é que você deve ser capaz de usar uma estrutura de UI como PySide 6. Você deve saber como usar elementos dinâmicos na interface de UI, como implementar eventos de clique e movimentação do mouse, eventos de rolagem da roda do mouse e eventos de entrada do teclado. Se você não sabe como usar estruturas relacionadas à interface de IU, você pode aprender primeiro. Se você conhece frameworks relacionados à UI, continue lendo abaixo.

Crie um serviço de screencasting

        Use a classe Client no scrcpy para estabelecer um serviço de controle de projeção de tela. O método de instanciação na classe Client é o seguinte:

class Client:
    def __init__(
        self,
        device: Optional[Union[AdbDevice, str, any]] = None,
        max_width: int = 0,
        bitrate: int = 8000000,
        max_fps: int = 0,
        flip: bool = False,
        block_frame: bool = False,
        stay_awake: bool = False,
        lock_screen_orientation: int = LOCK_SCREEN_ORIENTATION_UNLOCKED,
        connection_timeout: int = 3000,
        encoder_name: Optional[str] = None,
    ):

dispositivo: O número de série do dispositivo Android (pode ser visualizado usando o comando adb devices).

max_width: A largura máxima do quadro da imagem. Por padrão, a largura do quadro nas informações de transmissão do Android é usada.

taxa de bits: taxa de bits, padrão 8000000 bits.

max_fps: O número máximo de quadros, o número de quadros não é limitado por padrão.

flip: inverte a imagem (imagem espelhada), não espelhada por padrão.

block_frame: Retorna um quadro não vazio. Ele não é retornado por padrão. Retornar um quadro não vazio pode bloquear o thread de renderização openCv2.

stay_awake: A tela do dispositivo Android permanece sempre ligada quando conectado ao USB. A tela não permanece sempre ligada por padrão.

lock_screen_orientation: Bloqueia a orientação da tela (desativa a rotação automática da tela), não bloqueada por padrão.

connection_timeout: Tempo limite para conexão com o serviço de controle de projeção de tela (serviço de soquete). Se a conexão não for bem-sucedida dentro do tempo definido, a inicialização falhará. O padrão é 3.000 milissegundos.

encoder_name: nome do codificador, opcional OMX.google.h264.encoder, OMX.qcom.video.encoder.avc, c2.qti.avc.encoder, c2.android.avc.encoder, selecionado automaticamente por padrão.

        Instanciamos a classe Client para obter um objeto de serviço de controle de espelhamento de tela de um dispositivo Android. Se o número de série do dispositivo Android for 123456789, podemos criar um objeto de instância de serviço de controle de espelhamento de tela por meio do seguinte código:

import scrcpy


server = scrcpy.Client(device='123456789', bitrate=100000000)

método inicial

        start é um método de instância do Client usado para iniciar o serviço de controle de projeção de tela. start pode receber dois parâmetros. Um é threaded, cujo padrão é False. Quando é True, significa que o serviço de controle de projeção de tela está habilitado no thread filho ; o outro é daemon_threaded, cujo padrão é False. False, quando True, significa habilitar o daemon de processo para o thread filho. Quando threaded ou daemon_threaded for True, o serviço de controle de projeção de tela será habilitado no thread filho. Quando ambos forem False, o serviço de controle de projeção de tela será habilitado no thread principal. Quando você deseja habilitar vários serviços de controle de projeção de tela ao mesmo tempo, você precisa habilitar o serviço de controle de projeção de tela em um subthread. Você também pode criar um subthread você mesmo.

server.start()

método add_listener

        add_listener é um método de instância do Cliente usado para definir os ouvintes do dicionário de ouvinte. Existem dois elementos no dicionário de ouvintes. A chave do primeiro elemento é frame, que representa o elemento do quadro da imagem, e o segundo elemento é init, que representa o elemento de inicialização. O valor de ambos os elementos é uma lista vazia, usada para armazenar funções. Se você deseja colocar a imagem da tela do dispositivo Android em um elemento da interface da IU, você precisa escrever um método na estrutura da IU que possa receber a imagem e exibi-la e, em seguida, adicionar esse método à primeira lista de elementos do dicionário de ouvintes. Se você quiser realizar algumas operações ao estabelecer um serviço de controle de projeção de tela, escreva um método relacionado à operação na estrutura da UI e coloque esse método na segunda lista de elementos do dicionário de ouvintes.

    def on_frame(self, frame):  # 在使用PySide6的UI框架中定义了一个用于显示图像的方法
        app.processEvents()
        if frame is not None:
            ratio = self.max_width / max(self.client.resolution)
            image = QImage(
                frame,
                frame.shape[1],
                frame.shape[0],
                frame.shape[1] * 3,
                QImage.Format_BGR888,
            )
            pix = QPixmap(image)  # 处理图像
            pix.setDevicePixelRatio(1 / ratio)  # 设置图像大小
            self.ui.label.setPixmap(pix)  # 在UI界面显示图像
            self.resize(1, 1)

Ao inicializar a interface UI, adicione o método de exibição de imagens ao primeiro elemento do dicionário ouvinte (key='frame').

    def __init__(self):
        super().__init()
        self.server = scrcpy.Client(device='123456789', bitrate=100000000)
        self.server.add_listener(scrcpy.EVENT_FRAME, self.on_frame)

Estes são apenas exemplos, o método real precisa ser escrito de acordo com suas necessidades. Se você deseja exibir a imagem do dispositivo Android em um determinado elemento da interface UI, você deve escrever um método para exibir a imagem e, em seguida, adicionar esse método ao primeiro elemento do dicionário ouvinte (key='frame') .

método remove_listener

        O método remove_listener é um método de instância do Cliente e é usado para remover um método no dicionário do ouvinte.Se não quisermos mais exibir a imagem, podemos remover o método que exibe a imagem dos ouvintes.

    def no_display(self):
        self.server.remove_listener(scrcpy.EVENT_FRAME, self.on_frame)

método de parada

        O método stop é um método de instância do Cliente usado para encerrar o serviço de controle de projeção de tela.Quando fechamos a interface UI de projeção de tela, precisamos encerrar o serviço de controle de projeção de tela e liberar recursos de memória a tempo.

    def closeEvent(self, _):
        self.server.stop()

Método de controle

        Projetamos a tela do dispositivo Android no computador e agora precisamos operar o dispositivo Android por meio de alguns métodos de controle do dispositivo Android. Existe um atributo de controle nos atributos de instância do Cliente, que é obtido instanciando a classe ControlSender.A classe ControlSender é uma classe de operação especialmente usada para controlar dispositivos Android.

    self.control = ControlSender(self)

Portanto, se quisermos controlar o Android, precisamos controlar o atributo de controle do objeto de projeção da tela.

método de código-chave

    @inject(const.TYPE_INJECT_KEYCODE)
    def keycode(
        self, keycode: int, action: int = const.ACTION_DOWN, repeat: int = 0
    ) -> bytes:

        O método keycode é um método de instância da classe ControlSender usado para enviar eventos importantes para dispositivos Android. O método keycode pode receber três parâmetros. O primeiro parâmetro keycode representa o valor da chave (você precisa entender o valor da chave adb); o segundo parâmetro action representa se deve pressionar ou levantar, o padrão é pressionar; o terceiro parâmetro repetir representa repetido operações.vezes, quantas vezes você deseja pressioná-lo repetidamente.

    def click_home(self):
        self.server.control.keycode(scrcpy.KEYCODE_HOME, scrcpy.ACTION_DOWN)
        self.server.control.keycode(scrcpy.KEYCODE_HOME, scrcpy.ACTION_UP)

Clique no botão home, pressione-o primeiro e depois levante-o para completar o pressionamento de um botão.

método de texto

    @inject(const.TYPE_INJECT_TEXT)
    def text(self, text: str) -> bytes:

        O método text é um método de instância da classe ControlSender e é usado para inserir texto no Android, desde que uma caixa de entrada no dispositivo Android esteja ativada. O método text recebe um parâmetro, que é o conteúdo do texto que queremos inserir no dispositivo Android.

    def input_text(self, text):
        self.server.control.text(text)

método de toque

    def touch(
        self, x: int, y: int, action: int = const.ACTION_DOWN, touch_id: int = -1
    ) -> bytes:

        O método touch é um método de instância da classe ControlSender usado para controle multitoque da tela do dispositivo Android. O método touch pode receber quatro parâmetros. Os dois primeiros parâmetros são as coordenadas x e y do ponto de contato; o terceiro parâmetro action é pressionar, mover e levantar; o quarto parâmetro é o ID do evento de toque, e o padrão é - 1, você pode definir IDs diferentes para executar vários eventos de toque ao mesmo tempo para atingir finalidades multitoque.

    def mouse_move(self, evt: QMouseEvent):
        focused_widget = QApplication.focusWidget()
        if focused_widget is not None:
            focused_widget.clearFocus()
        ratio = self.max_width / max(self.one_client.resolution)
        self.server.control.touch(evt.position().x() / ratio, evt.position().y() / ratio, scrcpy.ACTION_MOVE)

método de rolagem

    @inject(const.TYPE_INJECT_SCROLL_EVENT)
    def scroll(self, x: int, y: int, h: int, v: int) -> bytes:

        O método scroll é um método de instância da classe ControlSender usado para rolar eventos na tela do dispositivo Android. O método de rolagem pode receber 4 parâmetros, os dois primeiros são a posição coordenada do ponto de rolagem; o terceiro parâmetro é a distância de rolagem horizontal; o quarto parâmetro é a distância de rolagem vertical.

    def on_wheel(self):
        """鼠标滚轮滚动事件"""

        def wheel(evt: QWheelEvent):
            ratio = self.max_width / max(self.one_client.resolution)
            position_x = evt.position().x() / ratio
            position_y = evt.position().y() / ratio
            angle_x = evt.angleDelta().x()
            angle_y = evt.angleDelta().y()
            if angle_y > 0:
                angle_y = 1
            else:
                angle_y = -1
            self.server.control.scroll(position_x, position_y, angle_x, angle_y)

        return wheel

Depois de escrever este método, podemos usar a roda do mouse para controlar a tela do dispositivo Android para rolar para cima e para baixo.

Método back_or_turn_screen_on

    @inject(const.TYPE_BACK_OR_SCREEN_ON)
    def back_or_turn_screen_on(self, action: int = const.ACTION_DOWN) -> bytes:

        O método back_or_turn_screen_on é um método de instância da classe ControlSender para pressionar a tecla Enter e ativará a tela se ela estiver desligada. Apenas uma ação de parâmetro é recebida, que é pressionar ou levantar.

    def click_back(self):
        self.server.control.back_or_turn_screen_on(scrcpy.ACTION_DOWN)
        self.server.control.back_or_turn_screen_on(scrcpy.ACTION_UP)

método expand_notification_panel

    @inject(const.TYPE_EXPAND_NOTIFICATION_PANEL)
    def expand_notification_panel(self) -> bytes:

        O método expand_notification_panel é um método de instância da classe ControlSender e é usado para abrir a barra suspensa de notificação de dispositivos Android.

    def open_notification(self):
        self.server.control.expand_notification_panel()

método expand_settings_panel

    @inject(const.TYPE_EXPAND_SETTINGS_PANEL)
    def expand_settings_panel(self) -> bytes:

        O método expand_settings_panel é um método de instância da classe ControlSender usado para abrir a barra de menu suspensa de dispositivos Android.

    def open_settings(self):
        self.server.control.expand_settings_panel()

Método colapso_panels

    @inject(const.TYPE_COLLAPSE_PANELS)
    def collapse_panels(self) -> bytes:

        O método colapso_panels é um método de instância da classe ControlSender e é usado para recolher a barra de notificação suspensa ou a barra de menu de dispositivos Android.

    def close_panel(self):
        self.server.control.collapse_panelsl()

método get_clipboard

    def get_clipboard(self) -> str:

        O método get_clipboard é um método de instância da classe ControlSender usado para obter o conteúdo da área de transferência do dispositivo Android. Podemos copiar o texto no dispositivo Android através deste método.

    def get_android_clipboard(self):
        return self.server.control.get_clipboard()

método set_clipboard

    @inject(const.TYPE_SET_CLIPBOARD)
    def set_clipboard(self, text: str, paste: bool = False) -> bytes:

        O método set_clipboard é um método de instância da classe ControlSender usado para definir o conteúdo da área de transferência do dispositivo Android. O método set_clipboard pode receber dois parâmetros. O primeiro parâmetro text é o conteúdo do texto a ser definido na área de transferência; o segundo parâmetro paste é o estado de colagem. O padrão é False. Quando for True, o texto será colado na entrada imediatamente (quando o cursor do dispositivo Android estiver em uma caixa de entrada).

    def set_android_clipboard(self, text: str, paste=False):
        self.server.control.set_clipboard(text, paste)

Método set_screen_power_mode

    @inject(const.TYPE_SET_SCREEN_POWER_MODE)
    def set_screen_power_mode(self, mode: int = scrcpy.POWER_MODE_NORMAL) -> bytes:

        O método set_screen_power_mode é um método de instância da classe ControlSender usado para o modo de energia da tela de dispositivos Android. O estado padrão é normal, o que significa ligar a tela do dispositivo Android. Neste momento, a tela do dispositivo Android está em um estado normal. Também pode ser definido para o estado desligado (scrcpy.POWER_MODE_OFF).Neste momento, a tela do dispositivo Android está desligada, mas não está no estado de tela desligada (a tela está desligada e a tela está desligada). duas coisas diferentes), e a tela ainda pode ser vista na interface de projeção da tela. Desta forma, o consumo de energia do dispositivo Android pode ser reduzido ao espelhar e controlar o dispositivo Android.

    def set_screen_power_mode(self, mode=2):
        self.server.control.set_screen_power_mode(mode)

Método total_device

    @inject(const.TYPE_ROTATE_DEVICE)
    def rotate_device(self) -> bytes:

        O método totate_device é um método de instância da classe ControlSender usado para girar a tela do dispositivo Android.

    def totate_screen(self):
        self.server.control.totate_device()

método de deslizar

    def swipe(
        self,
        start_x: int,
        start_y: int,
        end_x: int,
        end_y: int,
        move_step_length: int = 5,
        move_steps_delay: float = 0.005,
    ) -> None:

        O método swipe é um método de instância da classe ControlSender usado para deslizar a tela de um dispositivo Android. Este método é um encapsulamento do método touch, que equivale ao toque de um ponto. O método swipe pode receber 6 parâmetros. Os primeiros 4 parâmetros são as coordenadas inicial e final do deslizamento; o 5º parâmetro é o tamanho do passo (a distância de cada deslizamento), cujo padrão é 5 unidades de coordenadas; o 6º parâmetro é o tempo de pausa para deslizar uma etapa, o padrão é 0,005 segundos.

    def swipe_event(self, start_x: int, start_y: int, end_x: int, end_y: int, step: int, delay: float):
        self.server.control.swipe(start_x, start_y, end_x, end_y, step, delay)

Conclusão

        Usando os métodos acima na estrutura de UI do python, podemos realizar o controle de screencasting de dispositivos Android.A aparência desse aplicativo de controle de screencasting é completamente determinada por suas próprias necessidades e estética. Se quiser operar vários dispositivos Android ao mesmo tempo, você pode criar vários serviços de controle de projeção de tela e, em seguida, colocar esses serviços em uma lista ou dicionário (de preferência um dicionário) para alternar dispositivos de controle e controlar um dispositivo individualmente ou ao mesmo tempo tempo. Finalidade de operar vários dispositivos.

Acho que você gosta

Origin blog.csdn.net/qq_40148262/article/details/132274342
Recomendado
Clasificación