示例#1
0
class GlobalHotkey(QObject):
    pressed = Signal()

    def __init__(self, parent: Optional[QObject]):
        super().__init__(parent)

        self._hk = SystemHotkey()

    def is_registered(self, key):
        key = set(key)
        return any(set(k) == key for k in self._hk.keybinds)

    def register(self, key_sequence: Optional[QKeySequence]):
        key = self.convert_key_sequence(key_sequence)

        if key and self.is_registered(key):
            logger.debug("Already registered: %s", key)
            return

        self.unregister()
        if key_sequence and not key_sequence.isEmpty():
            logger.info("Registering hotkey: %s", key)
            # If this fails, we get a system_hotkey.SystemRegisterError
            # exception, but in a different thread - so we can neither catch it
            # here nor is it logged.
            self._hk.register(key, callback=self._callback)

    @staticmethod
    def convert_key_sequence(key_sequence: QKeySequence):
        if not key_sequence or key_sequence.isEmpty():
            return None

        # Restrict to the first key
        key_sequence = QKeySequence(key_sequence[0])

        # Convert to format for SystemHotkey - simple approach, may not be
        # sufficient.
        key = key_sequence.toString(QKeySequence.PortableText).split("+")
        key = [part.lower() for part in key]

        if "meta" in key:
            key.remove("meta")
            key = ["super"] + key

        return key

    def unregister(self):
        for key in self._hk.keybinds:
            logger.info("Unregistering hotkey: %s", (key, ))
            self._hk.unregister(key)

    def _callback(self, *_, **__):
        self.pressed.emit()
def test_errors_raised_in_main():
    hk = SystemHotkey()
    key = ('5',)
    cb = lambda e: print('hi')

    hk.register(key, callback=cb)
    try:
        hk.register(key, callback=cb)
    except SystemRegisterError:
        pass
    else:
        raise Exception('fail')

    hk.unregister(key)
    try:
        hk.unregister(key)
    except UnregisterError:
        pass
    else:
        raise Exception('fail')

    bad_key = ('badkey ..',)
    try:
        hk.register(bad_key, callback=cb)
    except InvalidKeyError:
        pass
    else:
        raise Exception('fail')

    try:
        hk.unregister(bad_key)
    except:
        pass
    else:
        raise Exception('fail')
def test_errors_raised_in_main():
    hk = SystemHotkey()
    key = ('5', )
    cb = lambda e: print('hi')

    hk.register(key, callback=cb)
    try:
        hk.register(key, callback=cb)
    except SystemRegisterError:
        pass
    else:
        raise Exception('fail')

    hk.unregister(key)
    try:
        hk.unregister(key)
    except UnregisterError:
        pass
    else:
        raise Exception('fail')

    bad_key = ('badkey ..', )
    try:
        hk.register(bad_key, callback=cb)
    except InvalidKeyError:
        pass
    else:
        raise Exception('fail')

    try:
        hk.unregister(bad_key)
    except:
        pass
    else:
        raise Exception('fail')
示例#4
0
class TaskBarIcon(wx.adv.TaskBarIcon):
    """Taskbar icon and menu class."""
    def __init__(self, frame):
        self.g_settings = GeneralSettingsData()

        self.frame = frame
        super(TaskBarIcon, self).__init__()
        self.set_icon(TRAY_ICON)
        self.Bind(wx.adv.EVT_TASKBAR_LEFT_DOWN, self.on_left_down)
        # profile initialization
        self.job_lock = Lock()
        get_display_data()
        self.repeating_timer = None
        self.pause_item = None
        self.is_paused = False
        if sp_logging.DEBUG:
            sp_logging.G_LOGGER.info("START Listing profiles for menu.")
        self.list_of_profiles = list_profiles()
        if sp_logging.DEBUG:
            sp_logging.G_LOGGER.info("END Listing profiles for menu.")
        # Should now return an object if a previous profile was written or
        # None if no previous data was found
        self.active_profile = read_active_profile()
        self.start_prev_profile(self.active_profile)
        # if self.active_profile is None:
        #     sp_logging.G_LOGGER.info("Starting up the first profile found.")
        #     self.start_profile(wx.EVT_MENU, self.list_of_profiles[0])

        # self.hk = None
        # self.hk2 = None
        if self.g_settings.use_hotkeys is True:
            try:
                # import keyboard # https://github.com/boppreh/keyboard
                # This import is here to have the module in the class scope
                from system_hotkey import SystemHotkey
                self.hk = SystemHotkey(check_queue_interval=0.05)
                self.hk2 = SystemHotkey(consumer=self.profile_consumer,
                                        check_queue_interval=0.05)
                self.seen_binding = set()
                self.register_hotkeys()
            except ImportError as excep:
                sp_logging.G_LOGGER.info(
                    "WARNING: Could not import keyboard hotkey hook library, \
hotkeys will not work. Exception: %s", excep)
        if self.g_settings.show_help is True:
            config_frame = ConfigFrame(self)
            help_frame = HelpFrame()

    def register_hotkeys(self):
        """Registers system-wide hotkeys for profiles and application interaction."""
        if self.g_settings.use_hotkeys is True:
            try:
                # import keyboard # https://github.com/boppreh/keyboard
                # This import allows access to the specific errors in this method.
                from system_hotkey import (SystemHotkey, SystemHotkeyError,
                                           SystemRegisterError,
                                           UnregisterError, InvalidKeyError)
            except ImportError as import_e:
                sp_logging.G_LOGGER.info(
                    "WARNING: Could not import keyboard hotkey hook library, \
hotkeys will not work. Exception: %s", import_e)
            if "system_hotkey" in sys.modules:
                try:
                    # Keyboard bindings: https://github.com/boppreh/keyboard
                    #
                    # Alternative KB bindings for X11 systems and Windows:
                    # system_hotkey https://github.com/timeyyy/system_hotkey
                    # seen_binding = set()
                    # self.hk = SystemHotkey(check_queue_interval=0.05)
                    # self.hk2 = SystemHotkey(
                    #     consumer=self.profile_consumer,
                    #     check_queue_interval=0.05)

                    # Unregister previous hotkeys
                    if self.seen_binding:
                        for binding in self.seen_binding:
                            try:
                                self.hk.unregister(binding)
                                if sp_logging.DEBUG:
                                    sp_logging.G_LOGGER.info(
                                        "Unreg hotkey %s", binding)
                            except (SystemHotkeyError, UnregisterError,
                                    InvalidKeyError):
                                try:
                                    self.hk2.unregister(binding)
                                    if sp_logging.DEBUG:
                                        sp_logging.G_LOGGER.info(
                                            "Unreg hotkey %s", binding)
                                except (SystemHotkeyError, UnregisterError,
                                        InvalidKeyError):
                                    if sp_logging.DEBUG:
                                        sp_logging.G_LOGGER.info(
                                            "Could not unreg hotkey '%s'",
                                            binding)
                        self.seen_binding = set()

                    # register general bindings
                    if self.g_settings.hk_binding_next not in self.seen_binding:
                        try:
                            self.hk.register(self.g_settings.hk_binding_next,
                                             callback=lambda x: self.
                                             next_wallpaper(wx.EVT_MENU),
                                             overwrite=False)
                            self.seen_binding.add(
                                self.g_settings.hk_binding_next)
                        except (SystemHotkeyError, SystemRegisterError,
                                InvalidKeyError):
                            msg = "Error: could not register hotkey {}. \
Check that it is formatted properly and valid keys.".format(
                                self.g_settings.hk_binding_next)
                            sp_logging.G_LOGGER.info(msg)
                            sp_logging.G_LOGGER.info(sys.exc_info()[0])
                            show_message_dialog(msg, "Error")
                    if self.g_settings.hk_binding_pause not in self.seen_binding:
                        try:
                            self.hk.register(self.g_settings.hk_binding_pause,
                                             callback=lambda x: self.
                                             pause_timer(wx.EVT_MENU),
                                             overwrite=False)
                            self.seen_binding.add(
                                self.g_settings.hk_binding_pause)
                        except (SystemHotkeyError, SystemRegisterError,
                                InvalidKeyError):
                            msg = "Error: could not register hotkey {}. \
Check that it is formatted properly and valid keys.".format(
                                self.g_settings.hk_binding_pause)
                            sp_logging.G_LOGGER.info(msg)
                            sp_logging.G_LOGGER.info(sys.exc_info()[0])
                            show_message_dialog(msg, "Error")
                    # try:
                    # self.hk.register(('control', 'super', 'shift', 'q'),
                    #  callback=lambda x: self.on_exit(wx.EVT_MENU))
                    # except (SystemHotkeyError, SystemRegisterError, InvalidKeyError):
                    # pass

                    # register profile specific bindings
                    self.list_of_profiles = list_profiles()
                    for profile in self.list_of_profiles:
                        if sp_logging.DEBUG:
                            sp_logging.G_LOGGER.info(
                                "Registering binding: \
                                %s for profile: %s", profile.hk_binding,
                                profile.name)
                        if (profile.hk_binding is not None and
                                profile.hk_binding not in self.seen_binding):
                            try:
                                self.hk2.register(profile.hk_binding,
                                                  profile,
                                                  overwrite=False)
                                self.seen_binding.add(profile.hk_binding)
                            except (SystemHotkeyError, SystemRegisterError,
                                    InvalidKeyError):
                                msg = "Error: could not register hotkey {}. \
Check that it is formatted properly and valid keys.".format(profile.hk_binding)
                                sp_logging.G_LOGGER.info(msg)
                                sp_logging.G_LOGGER.info(sys.exc_info()[0])
                                show_message_dialog(msg, "Error")
                        elif profile.hk_binding in self.seen_binding:
                            msg = "Could not register hotkey: '{}' for profile: '{}'.\n\
It is already registered for another action.".format(profile.hk_binding,
                                                     profile.name)
                            sp_logging.G_LOGGER.info(msg)
                            show_message_dialog(msg, "Error")
                except (SystemHotkeyError, SystemRegisterError,
                        UnregisterError, InvalidKeyError):
                    if sp_logging.DEBUG:
                        sp_logging.G_LOGGER.info(
                            "Coulnd't register hotkeys, exception:")
                        sp_logging.G_LOGGER.info(sys.exc_info()[0])

    def profile_consumer(self, event, hotkey, profile):
        """Hotkey bindable method that starts up a profile."""
        if sp_logging.DEBUG:
            sp_logging.G_LOGGER.info("Profile object is: %s", profile)
        self.start_profile(wx.EVT_MENU, profile[0][0])

    def read_general_settings(self):
        """Refreshes general settings from file and applies hotkey bindings."""
        self.g_settings = GeneralSettingsData()
        self.register_hotkeys()
        msg = "New settings are applied after an application restart. \
New hotkeys are registered."

        show_message_dialog(msg, "Info")

    def CreatePopupMenu(self):
        """Method called by WX library when user right clicks tray icon. Opens tray menu."""
        menu = wx.Menu()
        create_menu_item(menu, "Open Config Folder", self.open_config)
        create_menu_item(menu, "Profile Configuration",
                         self.configure_profiles)
        create_menu_item(menu, "Settings", self.configure_settings)
        create_menu_item(menu, "Reload Profiles", self.reload_profiles)
        menu.AppendSeparator()
        for item in self.list_of_profiles:
            create_menu_item(menu, item.name, self.start_profile, item)
        menu.AppendSeparator()
        create_menu_item(menu, "Next Wallpaper", self.next_wallpaper)
        self.pause_item = create_menu_item(menu,
                                           "Pause Timer",
                                           self.pause_timer,
                                           kind=wx.ITEM_CHECK)
        self.pause_item.Check(self.is_paused)
        menu.AppendSeparator()
        create_menu_item(menu, 'About', self.on_about)
        create_menu_item(menu, 'Exit', self.on_exit)
        return menu

    def set_icon(self, path):
        """Sets tray icon."""
        icon = wx.Icon(path)
        self.SetIcon(icon, TRAY_TOOLTIP)

    def on_left_down(self, *event):
        """Allows binding left click event."""
        sp_logging.G_LOGGER.info('Tray icon was left-clicked.')

    def open_config(self, event):
        """Opens Superpaper config folder, CONFIG_PATH."""
        if platform.system() == "Windows":
            try:
                os.startfile(sp_paths.CONFIG_PATH)
            except BaseException:
                show_message_dialog(
                    "There was an error trying to open the config folder.")
        elif platform.system() == "Darwin":
            try:
                subprocess.check_call(["open", sp_paths.CONFIG_PATH])
            except subprocess.CalledProcessError:
                show_message_dialog(
                    "There was an error trying to open the config folder.")
        else:
            try:
                subprocess.check_call(['xdg-open', sp_paths.CONFIG_PATH])
            except subprocess.CalledProcessError:
                show_message_dialog(
                    "There was an error trying to open the config folder.")

    def configure_profiles(self, event):
        """Opens profile configuration panel."""
        config_frame = ConfigFrame(self)

    def configure_settings(self, event):
        """Opens general settings panel."""
        setting_frame = SettingsFrame(self)

    def reload_profiles(self, event):
        """Reloads profiles from disk."""
        self.list_of_profiles = list_profiles()

    def start_prev_profile(self, profile):
        """Checks if a previously running profile has been recorded and starts it."""
        with self.job_lock:
            if profile is None:
                sp_logging.G_LOGGER.info("No previous profile was found.")
            else:
                self.repeating_timer = run_profile_job(profile)

    def start_profile(self, event, profile):
        """
        Starts a profile job, i.e. runs a slideshow or a one time wallpaper change.

        If the input profile is the currently active profile, initiate a wallpaper change.
        """
        if sp_logging.DEBUG:
            sp_logging.G_LOGGER.info("Start profile: %s", profile.name)
        if profile is None:
            sp_logging.G_LOGGER.info("start_profile: profile is None. \
                Do you have any profiles in /profiles?")
        elif self.active_profile is not None:
            if sp_logging.DEBUG:
                sp_logging.G_LOGGER.info(
                    "Check if the starting profile is already running: %s",
                    profile.name)
                sp_logging.G_LOGGER.info("name check: %s, %s", profile.name,
                                         self.active_profile.name)
            if profile.name == self.active_profile.name:
                self.next_wallpaper(event)
                return 0
            else:
                with self.job_lock:
                    if (self.repeating_timer is not None
                            and self.repeating_timer.is_running):
                        self.repeating_timer.stop()
                    if sp_logging.DEBUG:
                        sp_logging.G_LOGGER.info(
                            "Running quick profile job with profile: %s",
                            profile.name)
                    quick_profile_job(profile)
                    if sp_logging.DEBUG:
                        sp_logging.G_LOGGER.info(
                            "Starting timed profile job with profile: %s",
                            profile.name)
                    self.repeating_timer = run_profile_job(profile)
                    self.active_profile = profile
                    write_active_profile(profile.name)
                    if sp_logging.DEBUG:
                        sp_logging.G_LOGGER.info("Wrote active profile: %s",
                                                 profile.name)
                    return 0
        else:
            with self.job_lock:
                if (self.repeating_timer is not None
                        and self.repeating_timer.is_running):
                    self.repeating_timer.stop()
                if sp_logging.DEBUG:
                    sp_logging.G_LOGGER.info(
                        "Running quick profile job with profile: %s",
                        profile.name)
                quick_profile_job(profile)
                if sp_logging.DEBUG:
                    sp_logging.G_LOGGER.info(
                        "Starting timed profile job with profile: %s",
                        profile.name)
                self.repeating_timer = run_profile_job(profile)
                self.active_profile = profile
                write_active_profile(profile.name)
                if sp_logging.DEBUG:
                    sp_logging.G_LOGGER.info("Wrote active profile: %s",
                                             profile.name)
                return 0

    def next_wallpaper(self, event):
        """Calls the next wallpaper changer method of the running profile."""
        with self.job_lock:
            if (self.repeating_timer is not None
                    and self.repeating_timer.is_running):
                self.repeating_timer.stop()
                change_wallpaper_job(self.active_profile)
                self.repeating_timer.start()
            else:
                change_wallpaper_job(self.active_profile)

    def rt_stop(self):
        """Stops running slideshow timer if one is active."""
        if (self.repeating_timer is not None
                and self.repeating_timer.is_running):
            self.repeating_timer.stop()

    def pause_timer(self, event):
        """Check if a slideshow timer is running and if it is, then try to stop/start."""
        if (self.repeating_timer is not None
                and self.repeating_timer.is_running):
            self.repeating_timer.stop()
            self.is_paused = True
            if sp_logging.DEBUG:
                sp_logging.G_LOGGER.info("Paused timer")
        elif (self.repeating_timer is not None
              and not self.repeating_timer.is_running):
            self.repeating_timer.start()
            self.is_paused = False
            if sp_logging.DEBUG:
                sp_logging.G_LOGGER.info("Resumed timer")
        else:
            sp_logging.G_LOGGER.info("Current profile isn't using a timer.")

    def on_about(self, event):
        """Opens About dialog."""
        # Credit for AboutDiaglog example to Jan Bodnar of
        # http://zetcode.com/wxpython/dialogs/
        description = (
            "Superpaper is an advanced multi monitor wallpaper\n" +
            "manager for Unix and Windows operating systems.\n" +
            "Features include setting a single or multiple image\n" +
            "wallpaper, pixel per inch and bezel corrections,\n" +
            "manual pixel offsets for tuning, slideshow with\n" +
            "configurable file order, multiple path support and more.")
        licence = ("Superpaper is free software; you can redistribute\n" +
                   "it and/or modify it under the terms of the MIT" +
                   " License.\n\n" +
                   "Superpaper is distributed in the hope that it will" +
                   " be useful,\n" +
                   "but WITHOUT ANY WARRANTY; without even the implied" +
                   " warranty of\n" +
                   "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n" +
                   "See the MIT License for more details.")
        artists = "Icons kindly provided by Icons8 https://icons8.com"

        info = wx.adv.AboutDialogInfo()
        info.SetIcon(wx.Icon(TRAY_ICON, wx.BITMAP_TYPE_PNG))
        info.SetName('Superpaper')
        info.SetVersion(__version__)
        info.SetDescription(description)
        info.SetCopyright('(C) 2019 Henri Hänninen')
        info.SetWebSite('https://github.com/hhannine/Superpaper/')
        info.SetLicence(licence)
        info.AddDeveloper('Henri Hänninen')
        info.AddArtist(artists)
        # info.AddDocWriter('Doc Writer')
        # info.AddTranslator('Tran Slator')
        wx.adv.AboutBox(info)

    def on_exit(self, event):
        """Exits Superpaper."""
        self.rt_stop()
        wx.CallAfter(self.Destroy)
        self.frame.Close()
示例#5
0
    class ShkAdapterMixin(QObject):
        ''' Minimal interface adapter for global hotkeys '''

        # This class may seem confusing at first. The complexity is due to Qt.
        # Qt's system doesn't like it when qt functions are preformed on anything
        # other than the main thread. This is a problem for system hotkey, which
        # always invokes callbacks on a different thread. So, this class sets up
        # a Qt signal and slot, and uses this to marshal the SHK callback onto
        # the main Qt thread, which then invokes the command bound to the hotkey.

        # Key points: _hotkeyPressed receives callback from SHK. It emits
        # _commandInvoked with the name of the command. _invokeCommand is
        # connected to this signal. It receives the command name, looks up
        # the *actual* command callback in the dictionary and invokes it.

        # Signal that indicates when a command-invoking hotkey was pressed
        _commandInvoked = pyqtSignal(str)

        def __init__(self):
            super().__init__()
            self.hk = SystemHotkey(consumer=self._hotkeyPressed)
            self._commandInvoked.connect(self.invokeCommand)

        #enddef

        def _hotkeyPressed(self, event, hotkey, args):
            ''' Adapts the global callback from system hotkey into a signal '''
            self._commandInvoked.emit(args[0][0])

        #enddef

        def load(self):
            super().load()

            self.applyHotkeys()

        #enddef

        def _bind(self, seq, cmd):
            ''' Binds a hotkey to a command name.

			seq can either be a QKeySequence or a string parseable by QKeySequence
			eg "ctrl+shift+k" '''
            try:
                seq = QKeySequence(seq)
            except:
                pass

            t = seqToTuple(seq)
            log.debug('Binding hotkey "{hotkey}" => "{command}"',
                      hotkey=seq.toString(),
                      command=cmd)

            try:
                self.hk.register(t, cmd)
            except SystemRegisterError:
                log.exception('Failed to bind hotkey "{hotkey}"',
                              hotkey=seq.toString())
            else:
                return True
            #endtry

            return False

        #enddef

        def _unbind(self, seq, quiet=False):
            ''' Removes a hotkey binding. If Quiet is true, will not warn if the binding doesn't exist '''
            try:
                seq = QKeySequence(seq)
            except:
                pass

            t = seqToTuple(seq)
            log.debug('Unbinding hotkey "{hotkey}"', hotkey=seq.toString())

            try:
                self.hk.unregister(t)
            except UnregisterError:
                if not quiet:
                    log.warn('Tried to unbind nonexistent hotkey "{hotkey}"',
                             hotkey=seq.toString())
            else:
                return True
            #endtry

            return False

        #enddef

        # TODO: These should directly use QKeySequence in the config
        def commandHasHotkey(self, command):
            ''' Checks if the given command has a hotkey registered for it '''
            return not self.hotkeyForCommand(command).isEmpty()

        #enddef

        def hotkeyForCommand(self, command):
            for seq, cmd in config.default.get('hotkeys', {}).items():
                if cmd == command: return QKeySequence(seq)
            #endfor

            return QKeySequence()

        #enddef

        def hasHotkey(self, seq):
            try:
                seq = QKeySequence(seq)
            except:
                pass

            return seq.toString() in config.default.get('hotkeys', {})

        #enddef

        def add(self, seq, command):
            ''' Add a new hotkey with with a command name intended to be saved to the config '''
            try:
                seq = QKeySequence(seq)
            except:
                pass

            seq = seq.toString(
            )  # TODO: Removed this (use kyseq directly). UPDATE LOGS when you do (toString)

            hks = config.default.get('hotkeys', {})
            if seq in hks:
                log.warning('Reassigning existing sequence "{hotkey}"',
                            hotkey=seq)
            #endif

            hks[seq] = command
            config.default.set('hotkeys', hks)
            config.default.save()  # TODO: Move this to settings UI?

            log.debug('Attempting to bind "{sequence}"', sequence=seq)

            if command not in self.commands:
                log.warning(
                    'Saved hotkey "{hotkey}" to unknown command "{command}"',
                    hotkey=seq,
                    command=command)
            #endif

            return True

        #enddef

        def remove(self, seq):
            ''' Remove a hotkey from the config '''
            hks = config.default.get('hotkeys', {})
            try:
                del hks[seq]
            except KeyError:
                pass
            else:
                return self._unbind(seq)

            return False
            #endtry

        #enddef

        def applyHotkeys(self):
            ''' Apply all hotkeys defined in the config '''
            log.info('Applying hotkeys')
            toRemove = []
            for hotkey, command in config.default.get('hotkeys', {}).items():
                if command in self.commands:
                    self._bind(hotkey, command)
                else:
                    toRemove.append(hotkey)
                    log.error(
                        'Tried to bind hotkey "{hotkey}" to unknown command "{command}"',
                        hotkey=hotkey,
                        command=command)
                #endif
            #endfor

            for hotkey in toRemove:
                self.remove(hotkey)

        #enddef

        def removeHotkeys(self):
            ''' Remove all hotkeys defined in the config '''
            log.info('Removing all hotkeys')

            for hotkey, command in config.default.get('hotkeys', {}).items():
                self._unbind(hotkey)
示例#6
0
class CMainApplication(Ui_MainWindow, QtWidgets.QMainWindow):
    def __init__(self):
        super(CMainApplication, self).__init__()

        self.setupUi(self)

        # Tray Menu
        self.tray = TrayIcon(self)
        self.tray.show()
        self.tray.switchTrigger.connect(self.__bSwitchTransactionOn)
        self.tray.quitTrigger.connect(self.__bQuit)

        # IS transaction on
        self.__switch = True

        # Hotkey listener
        self.__initHotkeys()

        # Attribute relates on transaction
        self.__descriptionSwitch = False
        self.__word = ''
        self.__transaction = ''

        # Transaction widget
        self.__transactionWidget = CTransaction()
        self.__transactionWidget.cancelSignal.connect(self.__bCancelTransaction)

        # Database widget showed?
        self.databaseShowed = True

        # Init the database
        self.__initDatabase()

        self.initUI()

    def __initHotkeys(self):
        # self.__globalHotKCListener = CGlobalHotKCListener()
        # self.__globalHotKCListener.start()
        # self.__globalHotKCListener.addTrigger.connect(self.__bStartDescription)
        # self.__globalHotKCListener.cancelTrigger.connect(self.__bCancelDescription)

        self.__GlobalHotkeyListener = SystemHotkey()
        self.__GlobalHotkeyListener.register(('control', 'd'), callback=self.__bStartDescription)
        self.__GlobalHotkeyListener.register(('control', 's'), callback=self.__bCancelDescription)

    def closeEvent(self, vEvent):
        vEvent.ignore()
        self.hide()

    def hideEvent(self, vEvent):
        self.tray.showMessage("title", "hide in tray icon")
        self.hide()
        vEvent.ignore()

    def initUI(self):
        # self.setGeometry(300, 300, 300, 220)
        self.setWindowTitle('Dict')

        # AX
        self.__transactionWidget.transactionAx.setControl(u"{8856F961-340A-11D0-A96B-00C04FD705A2}")
        # self.transactionAx.setFocusPolicy(Qt::StrongFocus);//设置控件接收键盘焦点的方式:鼠标单击、Tab键
        self.__transactionWidget.transactionAx.setProperty("DisplayAlerts", False)  # 不显示任何警告信息。
        self.__transactionWidget.transactionAx.setProperty("DisplayScrollBars", True)  # 显示滚动条

        # self.setMouseTracking(True)
        self.addClipbordListener()
        self.show()

        # self.__transactionWidget.show()
        # self.hide()

    def addClipbordListener(self):
        self.clipboard = QApplication.clipboard()
        self.clipboard.dataChanged.connect(self.onClipboradChanged)

    def onClipboradChanged(self):
        # Add description of the word
        if self.__descriptionSwitch:
            try:
                self.__globalHotKCListener.quit()
                hld = win32gui.FindWindow("Qt5QWindowIcon", "Form")
                shell = win32com.client.Dispatch("WScript.Shell")
                shell.SendKeys('%')
                win32gui.SetForegroundWindow(hld)
            except Exception as MyException:
                print(MyException)

            reply = QMessageBox.information(self,
                                            "Tips",
                                            "Sure you want to add this words?",
                                            QMessageBox.Yes | QMessageBox.No)

            if reply == QMessageBox.No:
                return
            win32api.keybd_event(18, 0, 0, 0)  # Alt
            win32api.keybd_event(27, 0, 0, 0)  # F
            win32api.keybd_event(27, 0, win32con.KEYEVENTF_KEYUP, 0)  # 释放按键
            win32api.keybd_event(18, 0, win32con.KEYEVENTF_KEYUP, 0)
            clipboard = QApplication.clipboard()
            description = clipboard.text()

            # Save the word and description
            self.__saveData(self.__word, self.__transaction, description)

            # Tip to window
            self.tray.showMessage("Tips", "Insert Successful", self.tray.icon)
            self.incrementLine.setText(str(int(self.incrementLine.text()) + 1))
            self.todayLine.setText(str(int(self.todayLine.text()) + 1))
            self.totalLine.setText(str(int(self.totalLine.text()) + 1))
            self.__bCancelDescription(None)

            self.__initDatabase()
        else:
            try:
                # Get the text in clipboard
                clipboard = QApplication.clipboard()
                text = clipboard.text()
                if len(text) < 2:
                    return
                # text = re.search(r' ?[a-zA-Z ]+ ?', text).group()
                text = text.strip()
                text = str.lower(text)

                # Find the transaction
                Transaction = self.__transact(text)

                self.__transaction = Transaction
                self.__word = text

                File = codecs.open('resources/index.html', 'w', 'utf-8')
                if Transaction[0] != '<':
                    File.write(HTMLSTATIC1 + Transaction + HTMLSTATIC2)
                else:
                    File.write(Transaction)
                File.close()

                # Show the transaction window
                # self.__transactionWidget.transactionBrowser.setText(self.__transaction)
                self.__transactionWidget.transactionAx.dynamicCall("Navigate(str)", BASEDIR + "/resources/index.html")
                self.__transactionWidget.statusLabel.setText("Search Mode")
                CursurPoint = QCursor.pos()
                desktopWidget = QApplication.desktop();
                DesktopPoint = desktopWidget.availableGeometry()
                if CursurPoint.x() + 620 > DesktopPoint.width():
                    CursurPoint.setX(DesktopPoint.width() - 620)
                if CursurPoint.y() + 400 > DesktopPoint.height():
                    CursurPoint.setY(DesktopPoint.height() - 400)
                self.__transactionWidget.move(CursurPoint)
                # self.__transactionWidget.setWindowFlags(self.__transactionWidget.windowFlags() |QtCore.Qt.WindowStaysOnTopHint)
                # self.__transactionWidget.show()
                # self.__transactionWidget.setWindowFlags(QtCore.Qt.Widget)
                self.__transactionWidget.activateWindow()
                self.__transactionWidget.show()
            except Exception as e:
                print(e)

    def incrementButtonPushed(self):
        cn = sqlite3.connect(WORDRECORD)
        cu = cn.cursor()
        cu.execute("SELECT word,wordTransaction,description "
                   "FROM record WHERE alreadyOut='false'")
        with open(EXPORTPATH + "increment.txt", "w+", encoding='utf-8') as f:
            for res in cu.fetchall():
                f.write(res[0])
                f.write(",")
                f.write(res[1])
                f.write('\n')
                f.write(res[2])
                f.write('@\n')
            f.close()
        cu.execute("UPDATE record SET alreadyOut='true' WHERE alreadyOut='false'")
        cn.commit()
        cn.close()
        self.statusbar.showMessage("Successful!")

    def todayButtonPushed(self):
        NowTime = time.time()
        Midnight = NowTime - NowTime % 86400
        cn = sqlite3.connect(WORDRECORD)
        cu = cn.cursor()
        cu.execute("SELECT word,wordTransaction,description "
                   "FROM record WHERE insertTime>?", (Midnight,))
        with open(EXPORTPATH + "today.txt", "w+", encoding='utf-8') as f:
            for res in cu.fetchall():
                f.write(res[0])
                f.write(",")
                f.write(res[1])
                f.write('\n')
                f.write(res[2])
                f.write('@\n')
            f.close()
        cu.execute("UPDATE record SET alreadyOut='true' WHERE insertTime>?", (Midnight,))
        cn.commit()
        cn.close()
        self.statusbar.showMessage("Successful!")

    def totalButtonPushed(self):
        cn = sqlite3.connect(WORDRECORD)
        cu = cn.cursor()
        cu.execute("SELECT word,wordTransaction,description "
                   "FROM record")
        with open(EXPORTPATH + "total.txt", "w+", encoding='utf-8') as f:
            for res in cu.fetchall():
                f.write(res[0])
                f.write(",")
                f.write(res[1])
                f.write('\n')
                f.write(res[2])
                f.write('@\n')
            f.close()
        cu.execute("UPDATE record SET alreadyOut='true'")
        cn.commit()
        cn.close()
        self.statusbar.showMessage("Successful!")

    def displayButtonPushed(self):
        if self.databaseShowed:
            self.databaseWidget.hide()
            self.databaseShowed = not self.databaseShowed
            self.displayButton.setText(">>")
            self.resize(500, 650)
        else:
            self.databaseWidget.show()
            self.databaseShowed = not self.databaseShowed
            self.displayButton.setText("<<")
            self.resize(1200, 650)

    def removeButtonPushed(self):
        if self.databaseWidget.currentRow() == -1:
            pass
        RemoveLists = []
        for SelectedRange in self.databaseWidget.selectedRanges():
            for SelectIndex in range(SelectedRange.rowCount()):
                Word = self.databaseWidget.item(SelectedRange.topRow() + SelectIndex, 2).text()
                try:
                    requests.post(HOST + "/remove", data={'word': Word})
                except:
                    self.statusbar.showMessage("No network!")
                # Remove
                cn = sqlite3.connect(WORDRECORD)
                cu = cn.cursor()
                cu.execute('delete from record where word=?', (Word,))
                cn.commit()
                cn.close()
                RemoveLists.append(SelectedRange.topRow() + SelectIndex)
        RemoveLists.sort(reverse=True)
        for RowIndex in RemoveLists:
            self.databaseWidget.removeRow(RowIndex)

        self.__initCounts()

    def addWordsButtonPushed(self):
        FileName = QFileDialog.getOpenFileName(self, "select your words file", "", "Txt files(*.txt)")
        Results = self.__parseImportWords(FileName[0])

        # Add words to database
        cn = sqlite3.connect(WORDRECORD)
        cu = cn.cursor()
        for Result in Results:
            Word = Result.get('word')
            Transaction = Result.get('transaction')
            Description = ""

            # Find if it is exist
            cu.execute('select proficiency from record where word=?', (Word,))
            res = cu.fetchone()
            if res is None:
                cu.execute("INSERT INTO record (word, wordTransaction, description, insertTime) "
                           "VALUES (?,?,?,?)", (Word, Transaction, Description, time.time()))
            else:
                ProficiencyIncreament = 100 if res[0] + 25 > 100 else 100
                cu.execute("update record set proficiency=? where word = ?", (ProficiencyIncreament, Word))

        cn.commit()
        cn.close()

        self.__initDatabase()

    def synchronizeButtonPushed(self):
        self.__initDatabase()

    def __parseImportWords(self, vFileName):
        File = open(vFileName, 'r', encoding='UTF-16 LE', errors='ignore')
        lines = File.readlines()
        tempList = []
        temp = ""
        flag = 0

        final = []
        word = ""
        transaction = ""

        for line in lines:
            line.encode("utf8")
            if flag == 0:
                pattern0 = re.compile(r'\ufeff(.*\n)')
                match0 = pattern0.match(line)
                temp += match0.group(1)
            else:
                pattern = re.compile(r'\d,')
                match = pattern.match(line)
                if match:
                    tempList.append(temp)
                    temp = ""
                    temp += line
                else:
                    temp += line
            flag += 1
        tempList.append(temp)

        for temp in tempList:
            transaction = ""
            pattern = re.compile(r'\d, (.*?)  (.*)\n')
            match = pattern.match(temp)
            word = match.group(1)
            transction0 = match.group(2)
            transaction += transction0 + "\n"

            end = match.end()
            translationLine = temp[end:]
            translations = translationLine.split("\n\n")
            length = len(translations)
            for i in range(length):
                tmp = translations[i].partition(".")
                transaction += str(i + 1) + ". [" + tmp[0] + "]" + tmp[2] + "\n"

            element = {"word": word, "transaction": transaction}
            final.append(element)
        return final

    def __transact(self, vWord):
        try:
            # Dict Parser
            builder = IndexBuilder('MDXData/Oxford.mdx')
            ResultWord = builder.mdx_lookup(vWord)

            # Internet Based Transaction
            if len(ResultWord) == 0:
                TransactionRequest = requests.post(HOST + "/transaction"
                                                   , data={'word': vWord})
                return json.loads(TransactionRequest.text)
            # Using local dictionary
            else:
                parser = MyHTMLParser(ResultWord[0])
                return parser.getData()

        except Exception as e:
            print(e)

    def __synchronize(self):
        try:
            response = requests.get(HOST + "/sychronize", timeout=10, data={"LocalTime": os.stat(WORDRECORD).st_mtime})
            if response.status_code == 200:
                with open(WORDRECORD, 'wb') as TargetFile:
                    TargetFile.write(response.content)
                self.statusbar.showMessage("Download Successful")
            elif response.status_code == 302:
                with open(WORDRECORD, "rb") as File:
                    data = File.read()
                if requests.post(HOST + "/sychronize", data=data).status_code == 200:
                    self.statusbar.showMessage("Upload successful")
                else:
                    self.statusbar.showMessage("Upload Error")
            else:
                QMessageBox.information(self,
                                        "Warning",
                                        "Can't synchronize with remote database, using local mode",
                                        QMessageBox.Yes)
        except:
            QMessageBox.information(self,
                                    "Warning",
                                    "Can't synchronize with remote database, using local mode",
                                    QMessageBox.Yes)

        self.__initCounts()

    def __initCounts(self):
        NowTime = time.time()
        Midnight = NowTime - NowTime % 86400
        cn = sqlite3.connect(WORDRECORD)
        cu = cn.cursor()
        cu.execute('SELECT * FROM record')
        res = cu.fetchall()
        TotalCount = len(res)
        cu.execute('SELECT * FROM record WHERE insertTime>?', (Midnight,))
        res = cu.fetchall()
        TodayCount = len(res)
        cu.execute("SELECT * FROM record WHERE alreadyOut='false' ")
        res = cu.fetchall()
        IncrementCount = len(res)
        cn.close()
        self.incrementLine.setText(str(IncrementCount))
        self.todayLine.setText(str(TodayCount))
        self.totalLine.setText(str(TotalCount))

    def __initDatabase(self):
        self.databaseWidget.clear()
        self.databaseWidget.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.databaseWidget.setSelectionBehavior(QAbstractItemView.SelectRows)

        # Synchronize
        self.__synchronize()

        cn = sqlite3.connect(WORDRECORD)
        cu = cn.cursor()

        # Get the record
        cu.execute("select insertTime,proficiency,word,description,wordTransaction from record")
        reses = cu.fetchall()
        self.databaseWidget.setRowCount(len(reses))
        self.databaseWidget.setColumnCount(5)
        self.databaseWidget.setHorizontalHeaderItem(0, QTableWidgetItem("Date"))
        self.databaseWidget.setHorizontalHeaderItem(1, QTableWidgetItem("P"))
        self.databaseWidget.setHorizontalHeaderItem(2, QTableWidgetItem("Word"))
        self.databaseWidget.setHorizontalHeaderItem(3, QTableWidgetItem("D"))
        self.databaseWidget.setHorizontalHeaderItem(4, QTableWidgetItem("Transaction"))
        Header = self.databaseWidget.horizontalHeader()
        Header.setSectionResizeMode(0, QtWidgets.QHeaderView.ResizeToContents)
        Header.setSectionResizeMode(1, QtWidgets.QHeaderView.ResizeToContents)
        Header.setSectionResizeMode(2, QtWidgets.QHeaderView.ResizeToContents)
        Header.setSectionResizeMode(4, QtWidgets.QHeaderView.ResizeToContents)
        index = 0
        for res in reses:
            self.databaseWidget.setItem(index, 0, QTableWidgetItem(
                time.strftime("%m-%d", time.localtime(res[0]))))  # Date
            self.databaseWidget.setItem(index, 1, QTableWidgetItem(str(res[1])))  # Proficiency
            self.databaseWidget.setItem(index, 2, QTableWidgetItem(res[2]))  # Word
            self.databaseWidget.setItem(index, 3, QTableWidgetItem(res[3]))  # wordTransaction
            self.databaseWidget.setItem(index, 4, QTableWidgetItem(res[4]))  # description

            index += 1
        cn.close()

        # Display details signals
        for x in range(self.databaseWidget.rowCount()):
            self.databaseWidget.item(x, 3).setToolTip(self.databaseWidget.item(x, 3).text())
            self.databaseWidget.item(x, 4).setToolTip(self.databaseWidget.item(x, 4).text())

    def __saveData(self, vWord, vTransaction, vDescription):
        try:
            cn = sqlite3.connect(WORDRECORD)
            cu = cn.cursor()

            # Find if it is exist
            cu.execute('select proficiency from record where word=?', (vWord,))
            res = cu.fetchone()
            if res is None:
                cu.execute("INSERT INTO record (word, wordTransaction, description, insertTime) "
                           "VALUES (?,?,?,?)", (vWord, vTransaction, vDescription, time.time()))
            else:
                ProficiencyIncreament = 100 if res[0] + 5 > 100 else 100
                cu.execute("update record set proficiency=? where word = ?", (ProficiencyIncreament, vWord))
            cn.commit()
            cn.close()

            return True
        except Exception as e:
            return False

    def __bCancelTransaction(self):
        self.__transactionWidget.close()

    def __bSwitchTransactionOn(self):
        if self.__switch:
            self.__descriptionSwitch = False
            # self.__globalHotKCListener.addTrigger.disconnect()
            # self.__globalHotKCListener.cancelTrigger.disconnect()
            # self.__globalHotKCListener.cancelHotKey()
            # self.__globalHotKCListener.quit()
            self.__GlobalHotkeyListener.unregister(('control', 'd'))
            self.__GlobalHotkeyListener.unregister(('control', 's'))
            self.__switch = not self.__switch
            self.clipboard.dataChanged.disconnect()
        else:
            self.__descriptionSwitch = False
            # self.__globalHotKCListener.start()
            # self.__globalHotKCListener.addTrigger.connect(self.__bStartDescription)
            # self.__globalHotKCListener.cancelTrigger.connect(self.__bCancelDescription)
            self.__GlobalHotkeyListener.register(('control', 'd'), callback=self.__bStartDescription)
            self.__GlobalHotkeyListener.register(('control', 's'), callback=self.__bCancelDescription)

            self.__switch = not self.__switch
            self.clipboard.dataChanged.connect(self.onClipboradChanged)

    def __bStartDescription(self, event):
        self.__descriptionSwitch = True
        self.__transactionWidget.statusLabel.setText("Insert Mode")
        return event

    def __bCancelDescription(self, event):
        self.__descriptionSwitch = False
        self.__transactionWidget.statusLabel.setText("Search Mode")
        return False

    def __bQuit(self):
        self.__transactionWidget.close()
        self.__initDatabase()
        # self.p.terminate()
        self.tray.setVisible(False)
        # self.tray.close()
        self.close()
        # qApp.__bQuit()
        sys.exit()
示例#7
0
class Keybindings(object):
    def __init__(self, settings: ApplicationSettings,
                 mappings: Dict[str, Dict[str, Tuple[str, Callable]]]):
        """
        Creates keybindings for shortcuts stores in GSettings.
        The list of settings cannot be changed after created.

        Pass a map of (setting_id -> callback)
        """
        super().__init__()

        self._mappings = mappings
        self._settings = settings
        self._active_shortcuts = dict()

        # see https://github.com/timeyyy/system_hotkey
        from system_hotkey import SystemHotkey
        self._keybinder = SystemHotkey()
        self.rebind_all()

    def rebind_all(self):
        for category, shortcuts in self._mappings.items():

            if not shortcuts:
                continue

            for title, info in shortcuts.items():
                shortcut_id, callback = info
                shortcut = self._settings.get_keybinding(shortcut_id)

                parsed = parse_keystroke(shortcut)

                if not callback:
                    logging.warning(
                        f"Empty callback for shortcut '{shortcut_id}': ignored"
                    )
                    continue

                if not shortcut:
                    logging.warning(
                        f"Empty shortcut for settings '{shortcut_id}': ignored"
                    )
                    continue

                logging.info(
                    f"Binding '{shortcut_id}' -> '{callback.__name__}'")

                if shortcut and shortcut in self._active_shortcuts and self._active_shortcuts[
                        shortcut] != callback:
                    logging.debug(f"Removing current binding '{shortcut}'")
                    try:
                        self._keybinder.unregister(parsed)
                        del self._active_shortcuts[shortcut]
                    except Exception as e:
                        logging.error(f"Could not unbind '{shortcut}': {e}")
                        continue

                if shortcut and shortcut not in self._active_shortcuts:
                    logging.info(
                        f"Binding '{shortcut}' ({parsed}) to '{callback.__name__}'"
                    )
                    try:
                        self._keybinder.register(parsed, callback=callback)
                        self._active_shortcuts[shortcut] = callback
                    except Exception as e:
                        logging.error(
                            f"Could not bind {shortcut} to {callback.__name__}: {e}"
                        )
                        continue

                    self._settings.connect(f"changed::{shortcut_id}",
                                           lambda k, s: self.rebind_all())
示例#8
0
class myapp(tk.Tk):
    def __init__(self, ScriptPath=None):
        super().__init__()

        self.Cfg = Configuration()

        self.attributes('-type', 'dock')
        self.geometry("0x0+0+0")

        self.hk = SystemHotkey()
        self.hk.register(('control', 'shift', 'h'), callback=self.showhide)
        self.doingInput = False
        self.allDirs = None

        self.readAllDirsFromFile()

        dirFindThread = threading.Thread(target=self.updateAllDirs)
        dirFindThread.daemon = True
        dirFindThread.start()

    def exitProgram(self, *args):
        self.quit()

    def showhide(self, *args):
        if self.allDirs is None:
            return
        if not self.doingInput:
            self.update_idletasks()
            self.doingInput = True
            self.hk.unregister(('control', 'shift', 'h'))
            inputResult = inputDialog(self, self.allDirs).result
            self.hk.register(('control', 'shift', 'h'), callback=self.showhide)
            self.doingInput = False
        if not inputResult:
            return
        if inputResult == "###I###WANT###YOU###TO###GO###KILL###YOURSELF###":
            self.exitProgram()
            return
        #subprocess.run("/usr/bin/konsole &", shell=True, cwd=inputResult)
        subprocess.run('xdg-open "%s" &' % (inputResult), shell=True)

    def writeAllDirsToFile(self):
        if not os.path.isdir(self.Cfg.get('csvdir')):
            os.mkdir(self.Cfg.get('csvdir'))
        self.allDirs.to_csv(
            os.path.join(self.Cfg.get('csvdir'), self.Cfg.get('csvname')),
            columns=['Name'],
        )

    def readAllDirsFromFile(self):
        csvfile = os.path.join(self.Cfg.get('csvdir'), self.Cfg.get('csvname'))
        if os.path.isfile(csvfile):
            self.allDirs = pd.read_csv(csvfile)

    def updateAllDirs(self):
        dirl = []
        for root, dirs, files in os.walk(self.Cfg.get('topdir')):
            dirs[:] = [d for d in dirs if not d.startswith('.')]
            dirl.extend([os.path.join(root, dir) for dir in dirs])
        #dirl = [x for x, _, _ in os.walk()]
        self.allDirs = pd.DataFrame(columns=['Name'], data=dirl)
        self.writeAllDirsToFile()
示例#9
0
class MainWindow(QMainWindow):
    iconPath = "image/send.png"

    def __init__(self, parent=None):
        super().__init__(parent)
        self.w = Win32Window.from_qwindow(self)

        self.mwidget = QMainWindow(self)
        self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint)
        self.setWindowTitle("MTwit")

        # window size
        self.setFixedSize(480, 120)
        self.center()

        # TrayIcon
        self.createActions()
        self.createTrayIcon()
        self.trayIcon.show()
        self.trayIcon.activated.connect(self.iconActivated)

        # Textwindow
        self.textWindow = QPlainTextEdit('', self)
        self.textWindow.resize(400, 100)
        self.textWindow.move(10, 10)
        self.textWindow.setStyleSheet("background-color: rgba(0,0,0,50);"
                                      "border: 1px solid gray;"
                                      "font: 14pt 'Meiryo UI' ;"
                                      "color: #FFFFFF;")
        self.textWindow.setPlaceholderText("What's Happening?")

        # Quit Button
        self.qbtn = QuitButton(self)
        self.qbtn.setButtonPosition(self.size())

        # Tweet Button
        self.tbtn = HoverButton(self)
        self.tbtn.resize(48, 48)
        self.tbtn.move(420, 62)
        self.tbtn.setObjectName('tButton')
        self.tbtn.setIcon(QIcon("image/send.png"))
        self.tbtn.setIconSize(QSize(32, 32))
        self.tbtn.setStyleSheet("background-color: rgba(200, 200, 200, 0);")
        self.tbtn.clicked.connect(self.tweetEvent)

        # tweet Shortcut
        self.tShortcut = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_Return), self)
        self.tShortcut.activated.connect(self.tweetEvent)

        # window show Shortcut
        self.hk = SystemHotkey(consumer=self.ShowOrHide)
        self.hk.register(('alt', 'shift', 'f1'))

        # label
        """self.lbl = QLabel(self)
    self.lbl.setText("")
    self.lbl.setStyleSheet("background-color: rgb(0,0,0);"
                 "border: 0px solid red;"
                 "color: rgb(255,255,255);"
                 "font: bold italic 20pt 'Times New Roman';")
    self.lbl.setGeometry(5,5,60,40)
    """

        self.oldPos = self.pos()

        self.Firstshow()

    def Firstshow(self):  # check user data and init api

        pass

    # windowMove --
    def center(self):
        qr = self.frameGeometry()
        cp = QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())

    def mousePressEvent(self, event):
        self.oldPos = event.globalPos()

    def mouseMoveEvent(self, event):
        delta = QPoint(event.globalPos() - self.oldPos)
        self.move(self.x() + delta.x(), self.y() + delta.y())
        self.oldPos = event.globalPos()

    # windowMove End --
    def tweetEvent(self):
        print("tweetActivated")
        self.hide()
        text = self.textWindow.document().toPlainText()
        self.textWindow.setPlainText("")
        try:
            print(self.api.update_status(text))
            # print(self.api.mentions_timeline(count=200))
        except tweepy.error.TweepError as e:
            tb = sys.exc_info()[2]
            print("message:{0}".format(e.with_traceback(tb)))
            pass

    def quitEvent(self):
        self.trayIcon.hide()
        self.hk.unregister(('alt', 'shift', 'f1'))
        QCoreApplication.instance().quit()
        pass

    def templateTweetEvent(self):
        pass

    def iconActivated(self, reason):
        if reason == 3:
            self.ShowOrHide()

    def ShowOrHide(self, *args):
        if self.isHidden():
            self.showEvent_()
        else:
            self.hide()

    def createTrayIcon(self):
        self.trayIconMenu = QMenu(self)
        self.trayIconMenu.addAction(self.debugMakeWindowAction)
        self.trayIconMenu.addAction(self.debugMakeWindow2Action)
        self.trayIconMenu.addAction(self.debugMakeWindow3Action)
        self.trayIconMenu.addSeparator()
        self.trayIconMenu.addAction(self.minimizeAction)
        self.trayIconMenu.addAction(self.restoreAction)
        self.trayIconMenu.addSeparator()
        self.trayIconMenu.addAction(self.quitAction)
        self.trayIcon = QSystemTrayIcon(self)
        self.trayIcon.setContextMenu(self.trayIconMenu)
        self.trayIcon.setIcon(QIcon(self.iconPath))

    def createActions(self):
        self.minimizeAction = QAction("Mi&nimize", self, triggered=self.hide)
        self.restoreAction = QAction("&Restore",
                                     self,
                                     triggered=self.showNormal)
        self.quitAction = QAction("&Quit", self, triggered=self.quitEvent)
        self.debugMakeWindowAction = QAction("&DebugMakeAuth",
                                             self,
                                             triggered=self.makeAuthWindow)
        self.debugMakeWindow2Action = QAction("&DebugMake2Auth",
                                              self,
                                              triggered=self.makeAuthWindow2)
        self.debugMakeWindow3Action = QAction("&DebugMake3(Notification)",
                                              self,
                                              triggered=self.makeDebugwindow)

    def showEvent_(self):
        self.textWindow.setPlainText("")
        self.show()
        self.w.focus()
        self.textWindow.setFocus()

    # Auth Window

    def makeAuthWindow(self):
        from mTwit.Authwindow_Ui import AuthWindow
        authWindow = AuthWindow(self)
        authWindow.show("TwitterPIN")  # Debug

    def makeAuthWindow2(self):
        from mTwit.Authwindow_Ui import AuthWindow
        authWindow = AuthWindow(self)
        authWindow.show("Consumer")

    def makeNotificationWindow(self):
        pass

    def makeDebugwindow(self, *args):
        fav = NotificationWindow(self, message="Test Message.")
        fav.show(NotificationMode.ERROR)
        """
    try:
      raise MTwitError
    except:
      pass
    """

    def setParam(self, param):
        self.textWindow.setPlainText(param)
示例#10
0
	[sg.Text("Say manually")],
	[sg.Input(key="-MANUAL-"),sg.Button("Say")],
	[sg.Button('Ok'), sg.Button('Quit')]
]
# Create the window
window = sg.Window('sttttts', layout,icon="logos\\icon.ico")
hk = SystemHotkey()
hk.register(('control', 'q'), callback=lambda x:b.main(None,None,None))
hk.register(('alt', 'q'), callback=lambda x:b.repeat(None,None))

# Display and interact with the Window using an Event Loop
while True:
	event, values = window.read()
	# See if user wants to quit or window was closed
	if event == sg.WINDOW_CLOSED or event == 'Quit':
		break
	devices = b.get_io_devices()
	wanted_input = devices[0].index(values["-INPUT-"])
	wanted_output = devices[1].index(values["-OUTPUT-"]) + len(devices[0])
	if values["-OUTPUT2-"] == "Disabled":
		wanted_output2 = None
	else:
		wanted_output2 = devices[1].index(values["-OUTPUT2-"]) + len(devices[0])
	if event == 'Say':
		b.say(wanted_output,wanted_output2,values["-MANUAL-"])
	hk.unregister(('control', 'q'))
	hk.unregister(('alt', 'q'))
	hk.register(('control', 'q'), callback=lambda x:b.main(wanted_input,wanted_output,wanted_output2))
	hk.register(('alt', 'q'), callback=lambda x:b.repeat(wanted_output,wanted_output2))
# Finish up by removing from the screen
window.close()
示例#11
0
class Translation(QMainWindow):

    # 范围快捷键信号
    range_hotkey_sign = pyqtSignal(bool)
    # 自动翻译模式信号
    auto_open_sign = pyqtSignal(bool)
    # 隐藏范围框快捷键
    hide_range_sign = pyqtSignal(bool)

    def __init__(self, object):

        super(Translation, self).__init__()

        self.translater_yaml_map = {
            "youdao": "youdao",
            "baidu": "baiduweb",
            "tencent": "tencentweb",
            "caiyun": "caiyun",
            "google": "google",
            "deepl": "deepl"
        }
        self.object = object
        self.logger = object.logger
        self.getInitConfig()
        self.ui()

        # 开启朗读模块
        self.sound = translator.sound.Sound(self.object)
        utils.thread.createThread(self.sound.openWebdriver)
        # 开启翻译模块
        self.createWebdriverThread()
        # 自动翻译信号
        self.auto_open_sign.connect(
            lambda: utils.thread.createThread(self.startTranslater))

    def ui(self):

        # 窗口尺寸
        self.resize(int(800 * self.rate), int(130 * self.rate))

        # 窗口无标题栏、窗口置顶、窗口透明
        self.setWindowFlags(Qt.WindowStaysOnTopHint | Qt.FramelessWindowHint)
        self.setAttribute(Qt.WA_TranslucentBackground)
        self.setMouseTracking(True)

        # 窗口图标
        icon = QIcon()
        icon.addPixmap(QPixmap(LOGO_PATH), QIcon.Normal, QIcon.On)
        self.setWindowIcon(icon)

        # 鼠标样式
        pixmap = QPixmap(PIXMAP_PATH)
        pixmap = pixmap.scaled(int(20 * self.rate), int(20 * self.rate),
                               Qt.KeepAspectRatio, Qt.SmoothTransformation)
        cursor = QCursor(pixmap, 0, 0)
        self.setCursor(cursor)

        # 鼠标选中状态图标
        select_pixmap = QPixmap(PIXMAP2_PATH)
        select_pixmap = select_pixmap.scaled(int(20 * self.rate),
                                             int(20 * self.rate),
                                             Qt.KeepAspectRatio,
                                             Qt.SmoothTransformation)
        select_pixmap = QCursor(select_pixmap, 0, 0)

        # 工具栏标签
        label = QLabel(self)
        self.customSetGeometry(label, 0, 0, 800, 30)
        label.setStyleSheet("background-color: rgba(62, 62, 62, 0.01)")

        # 翻译框字体
        self.font = QFont()
        self.font.setFamily(self.font_type)
        self.font.setPointSize(self.font_size)

        # 翻译框
        self.translate_text = QTextBrowser(self)
        self.customSetGeometry(self.translate_text, 0, 30, 1500, 110)
        self.translate_text.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.translate_text.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.translate_text.setFont(self.font)
        self.translate_text.setStyleSheet("border-width: 0;\
                                           border-style: outset;\
                                           border-top: 0px solid #e8f3f9;\
                                           color: white;\
                                           font-weight: bold;\
                                           background-color: rgba(62, 62, 62, %s)"
                                          % (self.horizontal / 100))

        # 翻译框加入描边文字
        self.format = QTextCharFormat()
        # 翻译界面显示通知信息
        thread = utils.thread.createShowTranslateTextQThread(self.object)
        thread.signal.connect(self.showTranslateText)
        utils.thread.runQThread(thread)

        # 重叠提示消息框
        self.temp_text = QTextBrowser(self)
        self.customSetGeometry(self.temp_text, 0, 30, 1500, 110)
        self.temp_text.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.temp_text.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.temp_text.setFont(self.font)
        self.temp_text.setStyleSheet("border-width: 0;\
                                     border-style: outset;\
                                     border-top: 0px solid #e8f3f9;\
                                     color: white;\
                                     font-weight: bold;\
                                     background-color: rgba(62, 62, 62, %s)" %
                                     (self.horizontal / 100))
        self.format.setTextOutline(
            QPen(QColor(self.font_color_1), 0.7, Qt.SolidLine, Qt.RoundCap,
                 Qt.RoundJoin))
        self.temp_text.mergeCurrentCharFormat(self.format)
        self.temp_text.append("翻译框和范围区域重叠, 请挪开翻译框!!!")
        self.temp_text.hide()

        # 翻译框根据内容自适应大小
        self.document = self.translate_text.document()
        self.document.contentsChanged.connect(self.textAreaChanged)

        # 此Label用于当鼠标进入界面时给出颜色反应
        self.drag_label = QLabel(self)
        self.drag_label.setObjectName("drag_label")
        self.customSetGeometry(self.drag_label, 0, 0, 4000, 2000)
        self.drag_label.setMouseTracking(True)

        # 翻译按钮
        self.start_button = QPushButton(
            qtawesome.icon("fa.play", color=self.icon_color), "", self)
        self.customSetIconSize(self.start_button, 20, 20)
        self.customSetGeometry(self.start_button, 173, 5, 20, 20)
        self.start_button.setToolTip("<b>翻译键 Translate</b><br>点击后翻译(手动模式)")
        self.start_button.setStyleSheet("background: transparent;")
        self.start_button.clicked.connect(
            lambda: utils.thread.createThread(self.startTranslater))
        self.start_button.setCursor(select_pixmap)
        self.start_button.hide()

        # 设置按钮
        self.settin_button = QPushButton(
            qtawesome.icon("fa.cog", color=self.icon_color), "", self)
        self.customSetIconSize(self.settin_button, 20, 20)
        self.customSetGeometry(self.settin_button, 213, 5, 20, 20)
        self.settin_button.setToolTip("<b>设置键 Settin</b><br>翻译器的详细设置")
        self.settin_button.setStyleSheet("background: transparent;")
        self.settin_button.setCursor(select_pixmap)
        self.settin_button.hide()

        # 范围按钮
        self.range_button = QPushButton(
            qtawesome.icon("fa.crop", color=self.icon_color), "", self)
        self.customSetIconSize(self.range_button, 20, 20)
        self.customSetGeometry(self.range_button, 253, 5, 20, 20)
        self.range_button.setToolTip(
            "<b>范围 Range</b><br>框选要翻译的区域<br>需从左上到右下拖动")
        self.range_button.setStyleSheet("background: transparent;")
        self.range_button.setCursor(select_pixmap)
        self.range_button.clicked.connect(self.clickRange)
        self.range_button.hide()

        # 复制按钮
        self.copy_button = QPushButton(
            qtawesome.icon("fa.copy", color=self.icon_color), "", self)
        self.customSetIconSize(self.copy_button, 20, 20)
        self.customSetGeometry(self.copy_button, 293, 5, 20, 20)
        self.copy_button.setToolTip("<b>复制 Copy</b><br>将当前识别到的文本<br>复制至剪贴板")
        self.copy_button.setStyleSheet("background: transparent;")
        self.copy_button.setCursor(select_pixmap)
        self.copy_button.clicked.connect(lambda: pyperclip.copy(self.original))
        self.copy_button.hide()

        # 屏蔽词按钮
        self.filter_word_button = QPushButton(
            qtawesome.icon("fa.ban", color=self.icon_color), "", self)
        self.customSetIconSize(self.filter_word_button, 20, 20)
        self.customSetGeometry(self.filter_word_button, 333, 5, 20, 20)
        self.filter_word_button.setToolTip(
            "<b>屏蔽字符 Filter</b><br>将特定翻译错误的词<br>屏蔽不显示")
        self.filter_word_button.setStyleSheet("background: transparent;")
        self.filter_word_button.setCursor(select_pixmap)
        self.filter_word_button.clicked.connect(self.clickFilter)
        self.filter_word_button.hide()

        # 翻译模式按钮
        self.switch_button = ui.switch.SwitchButton(self,
                                                    sign=self.translate_mode,
                                                    startX=(50 - 20) *
                                                    self.rate)
        self.customSetGeometry(self.switch_button, 373, 5, 50, 20)
        self.switch_button.setToolTip("<b>模式 Mode</b><br>手动翻译/自动翻译")
        self.switch_button.checkedChanged.connect(self.changeTranslateMode)
        self.switch_button.setCursor(select_pixmap)
        self.switch_button.hide()

        # 朗读原文按钮
        self.play_voice_button = QPushButton(
            qtawesome.icon("fa.music", color=self.icon_color), "", self)
        self.customSetIconSize(self.play_voice_button, 20, 20)
        self.customSetGeometry(self.play_voice_button, 443, 5, 20, 20)
        self.play_voice_button.setToolTip("<b>朗读原文 Play Voice</b><br>朗读识别到的原文")
        self.play_voice_button.setStyleSheet("background: transparent;")
        self.play_voice_button.clicked.connect(
            lambda: utils.thread.createThread(self.sound.playSound, self.
                                              original))
        self.play_voice_button.setCursor(select_pixmap)
        self.play_voice_button.hide()

        # 充电按钮
        self.battery_button = QPushButton(
            qtawesome.icon("fa.battery-half", color=self.icon_color), "", self)
        self.customSetIconSize(self.battery_button, 24, 20)
        self.customSetGeometry(self.battery_button, 483, 5, 24, 20)
        self.battery_button.setToolTip(
            "<b>充电入口 Support author</b><br>我要给团子充电支持!")
        self.battery_button.setStyleSheet("background: transparent;")
        self.battery_button.setCursor(select_pixmap)
        self.battery_button.hide()

        # 锁按钮
        self.lock_button = QPushButton(
            qtawesome.icon("fa.lock", color=self.icon_color), "", self)
        self.customSetIconSize(self.lock_button, 20, 20)
        self.customSetGeometry(self.lock_button, 527, 5, 20, 20)
        self.lock_button.setToolTip("<b>锁定翻译界面 Lock</b>")
        self.lock_button.setStyleSheet("background: transparent;")
        self.lock_button.setCursor(select_pixmap)
        self.lock_button.clicked.connect(self.lock)
        self.lock_button.hide()

        # 最小化按钮
        self.minimize_button = QPushButton(
            qtawesome.icon("fa.minus", color=self.icon_color), "", self)
        self.customSetIconSize(self.minimize_button, 20, 20)
        self.customSetGeometry(self.minimize_button, 567, 5, 20, 20)
        self.minimize_button.setToolTip("<b>最小化 Minimize</b>")
        self.minimize_button.setStyleSheet("background: transparent;")
        self.minimize_button.setCursor(select_pixmap)
        self.minimize_button.clicked.connect(self.showMinimized)
        self.minimize_button.hide()

        # 退出按钮
        self.quit_button = QPushButton(
            qtawesome.icon("fa.times", color=self.icon_color), "", self)
        self.customSetIconSize(self.quit_button, 20, 20)
        self.customSetGeometry(self.quit_button, 607, 5, 20, 20)
        self.quit_button.setToolTip("<b>退出程序 Quit</b>")
        self.quit_button.setStyleSheet("background: transparent;")
        self.quit_button.setCursor(select_pixmap)
        self.quit_button.clicked.connect(self.showAppquitMessageBox)
        self.quit_button.hide()

        # 右下角用于拉伸界面的控件
        self.statusbar = QStatusBar(self)
        self.setStatusBar(self.statusbar)
        self.statusbar.setStyleSheet(
            "font: 10pt %s;"
            "color: %s;"
            "background-color: rgba(62, 62, 62, 0.1)" %
            (self.font_type, self.icon_color))
        if not self.statusbar_sign:
            self.statusbar.hide()

        # 注册翻译快捷键
        self.translate_hotkey = SystemHotkey()
        if self.object.config["showHotKey1"] == "True":
            self.translate_hotkey.register(
                (self.translate_hotkey_value1, self.translate_hotkey_value2),
                callback=lambda x: utils.thread.createThread(self.
                                                             startTranslater))

        # 注册范围快捷键
        self.range_hotkey = SystemHotkey()
        if self.object.config["showHotKey2"] == "True":
            self.range_hotkey.register(
                (self.range_hotkey_value1, self.range_hotkey_value2),
                callback=lambda x: self.range_hotkey_sign.emit(True))
        self.range_hotkey_sign.connect(self.clickRange)

        # 注册隐藏范围框快捷键
        self.hide_range_hotkey = SystemHotkey()
        if self.object.config["showHotKey3"]:
            self.hide_range_hotkey.register(
                (self.hide_range_hotkey_value1, self.hide_range_hotkey_value2),
                callback=lambda x: self.hide_range_sign.emit(True))

    # 窗口显示信号
    def showEvent(self, e):

        # 如果处于自动模式下则开始
        if self.translate_mode:
            self.stop_sign = False

    # 窗口隐藏信号
    def hideEvent(self, e):

        # 如果处于自动模式下则暂停
        if self.translate_mode and not self.object.config["drawImageUse"]:
            self.stop_sign = True

    # 初始化配置
    def getInitConfig(self):

        # 界面字体
        self.font_type = "华康方圆体W7"
        # 界面字体大小
        self.font_size = 15
        # 图标按键颜色
        self.icon_color = "white"
        # 字体颜色蓝色
        self.font_color_1 = "#1E90FF"
        self.font_color_2 = "#FF69B4"
        # 界面缩放比例
        self.rate = self.object.yaml["screen_scale_rate"]
        # 界面透明度
        self.horizontal = self.object.config["horizontal"]
        if self.horizontal == 0:
            self.horizontal = 1
        # 当前登录的用户
        self.user = self.object.yaml["user"]
        # 界面锁
        self.lock_sign = False
        # 翻译模式
        self.translate_mode = False
        # 自动翻译暂停标志
        self.stop_sign = False
        # 原文
        self.original = ""
        # 翻译线程1启动成功标志
        self.webdriver_1_sign = False
        # 翻译线程2启动成功标志
        self.webdriver_2_sign = False
        # 翻译线程1翻译类型
        self.webdriver_type1 = ""
        # 翻译线程2翻译类型
        self.webdriver_type2 = ""
        # 翻译线程3翻译类型
        self.webdriver_type3 = ""
        # 状态栏是否隐藏标志
        self.statusbar_sign = self.object.config["showStatusbarUse"]
        # 各翻译源线程状态标志
        self.thread_state = 0
        # 自动翻译线程存在标志
        self.auto_trans_exist = False
        # 按键转换映射关系
        hotkey_map = {"ctrl": "control", "win": "super"}
        # 翻译快捷键
        self.translate_hotkey_value1 = hotkey_map.get(
            self.object.config["translateHotkeyValue1"],
            self.object.config["translateHotkeyValue1"])
        self.translate_hotkey_value2 = hotkey_map.get(
            self.object.config["translateHotkeyValue2"],
            self.object.config["translateHotkeyValue2"])
        # 范围快捷键
        self.range_hotkey_value1 = hotkey_map.get(
            self.object.config["rangeHotkeyValue1"],
            self.object.config["rangeHotkeyValue1"])
        self.range_hotkey_value2 = hotkey_map.get(
            self.object.config["rangeHotkeyValue2"],
            self.object.config["rangeHotkeyValue2"])
        # 范围快捷键
        self.hide_range_hotkey_value1 = hotkey_map.get(
            self.object.config["hideRangeHotkeyValue1"],
            self.object.config["hideRangeHotkeyValue1"])
        self.hide_range_hotkey_value2 = hotkey_map.get(
            self.object.config["hideRangeHotkeyValue2"],
            self.object.config["hideRangeHotkeyValue2"])
        # 竖排翻译贴字
        self.object.ocr_result = None

    # 根据分辨率定义控件位置尺寸
    def customSetGeometry(self, object, x, y, w, h):

        object.setGeometry(
            QRect(int(x * self.rate), int(y * self.rate), int(w * self.rate),
                  int(h * self.rate)))

    # 根据分辨率定义图标位置尺寸
    def customSetIconSize(self, object, w, h):

        object.setIconSize(QSize(int(w * self.rate), int(h * self.rate)))

    # 鼠标移动事件
    def mouseMoveEvent(self, e: QMouseEvent):

        # 判断鼠标位置以适配特定位置可拉伸
        if self.width() - e.x() < 15 * self.rate and self.height() - e.y(
        ) < 15 * self.rate:
            self.statusbar.show()
        elif not self.object.config["showStatusbarUse"]:
            self.statusbar.hide()

        if self.lock_sign == True:
            return

        try:
            self._endPos = e.pos() - self._startPos
            self.move(self.pos() + self._endPos)
        except Exception:
            pass

        # 判断是否和范围框碰撞
        self.checkOverlap()

    # 鼠标按下事件
    def mousePressEvent(self, e: QMouseEvent):

        if self.lock_sign == True:
            return

        try:
            if e.button() == Qt.LeftButton:
                self._isTracking = True
                self._startPos = QPoint(e.x(), e.y())
        except Exception:
            pass

    # 鼠标松开事件
    def mouseReleaseEvent(self, e: QMouseEvent):

        if self.lock_sign == True:
            return

        try:
            if e.button() == Qt.LeftButton:
                self._isTracking = False
                self._startPos = None
                self._endPos = None
        except Exception:
            pass

    # 鼠标进入控件事件
    def enterEvent(self, QEvent):

        if self.lock_sign == True:
            self.lock_button.show()
            self.lock_button.setStyleSheet(
                "background-color:rgba(62, 62, 62, 0.1);")
            return

        # 显示所有顶部工具栏控件
        self.switch_button.show()
        self.start_button.show()
        self.settin_button.show()
        self.range_button.show()
        self.copy_button.show()
        self.quit_button.show()
        self.minimize_button.show()
        self.battery_button.show()
        self.play_voice_button.show()
        self.lock_button.show()
        self.filter_word_button.show()
        self.setStyleSheet(
            "QLabel#drag_label {background-color:rgba(62, 62, 62, 0.1)}")
        if self.statusbar_sign:
            self.statusbar.show()

    # 鼠标离开控件事件
    def leaveEvent(self, QEvent):

        if self.lock_sign == False and self.statusbar_sign:
            self.statusbar.show()

        width = round((self.width() - 454 * self.rate) / 2)
        height = self.height() - 30 * self.rate

        # 重置所有控件的位置和大小
        self.start_button.setGeometry(
            QRect(width, 5 * self.rate, 20 * self.rate, 20 * self.rate))
        self.settin_button.setGeometry(
            QRect(width + 40 * self.rate, 5 * self.rate, 20 * self.rate,
                  20 * self.rate))
        self.range_button.setGeometry(
            QRect(width + 80 * self.rate, 5 * self.rate, 20 * self.rate,
                  20 * self.rate))
        self.copy_button.setGeometry(
            QRect(width + 120 * self.rate, 5 * self.rate, 20 * self.rate,
                  20 * self.rate))
        self.filter_word_button.setGeometry(
            QRect(width + 160 * self.rate, 5 * self.rate, 20 * self.rate,
                  20 * self.rate))
        self.switch_button.setGeometry(
            QRect(width + 200 * self.rate, 5 * self.rate, 50 * self.rate,
                  20 * self.rate))
        self.play_voice_button.setGeometry(
            QRect(width + 270 * self.rate, 5 * self.rate, 20 * self.rate,
                  20 * self.rate))
        self.battery_button.setGeometry(
            QRect(width + 314 * self.rate, 5 * self.rate, 24 * self.rate,
                  20 * self.rate))
        self.lock_button.setGeometry(
            QRect(width + 358 * self.rate, 5 * self.rate, 24 * self.rate,
                  20 * self.rate))
        self.minimize_button.setGeometry(
            QRect(width + 398 * self.rate, 5 * self.rate, 20 * self.rate,
                  20 * self.rate))
        self.quit_button.setGeometry(
            QRect(width + 438 * self.rate, 5 * self.rate, 20 * self.rate,
                  20 * self.rate))
        self.translate_text.setGeometry(0, 30 * self.rate, self.width(),
                                        height * self.rate)

        # 隐藏所有顶部工具栏控件
        self.switch_button.hide()
        self.start_button.hide()
        self.settin_button.hide()
        self.range_button.hide()
        self.copy_button.hide()
        self.quit_button.hide()
        self.minimize_button.hide()
        self.battery_button.hide()
        self.play_voice_button.hide()
        self.lock_button.hide()
        self.filter_word_button.hide()

        self.setStyleSheet("QLabel#drag_label {background-color:none}")
        self.textAreaChanged()

    # 翻译框初始消息
    def showTranslateText(self, result):

        if result:
            for content in result.split(r"\n"):
                self.format.setTextOutline(
                    QPen(QColor(self.font_color_1), 0.7, Qt.SolidLine,
                         Qt.RoundCap, Qt.RoundJoin))
                self.translate_text.mergeCurrentCharFormat(self.format)
                self.translate_text.append(content)
        else:
            self.format.setTextOutline(
                QPen(QColor(self.font_color_1), 0.7, Qt.SolidLine, Qt.RoundCap,
                     Qt.RoundJoin))
            self.translate_text.mergeCurrentCharFormat(self.format)
            self.translate_text.append("欢迎你 ~ %s 么么哒 ~" % self.user)
            self.format.setTextOutline(
                QPen(QColor(self.font_color_2), 0.7, Qt.SolidLine, Qt.RoundCap,
                     Qt.RoundJoin))
            self.translate_text.mergeCurrentCharFormat(self.format)
            self.translate_text.append("b站关注[团子翻译器]查看动态可了解翻译器最新情况 ~")
            self.format.setTextOutline(
                QPen(QColor(self.font_color_1), 0.7, Qt.SolidLine, Qt.RoundCap,
                     Qt.RoundJoin))
            self.translate_text.mergeCurrentCharFormat(self.format)
            self.translate_text.append("团子一个人开发不易,这个软件真的花了很大很大的精力 _(:з」∠)_")
            self.format.setTextOutline(
                QPen(QColor(self.font_color_2), 0.7, Qt.SolidLine, Qt.RoundCap,
                     Qt.RoundJoin))
            self.translate_text.mergeCurrentCharFormat(self.format)
            self.translate_text.append("喜欢的话能不能在b站给团子一个关注,团子会很开心的~真心感谢你❤")

    # 当翻译内容改变时界面自适应窗口大小
    def textAreaChanged(self):

        newHeight = self.document.size().height()
        if self.statusbar_sign:
            newHeight += self.statusbar.height()

        width = self.width()
        self.resize(width, newHeight + 30 * self.rate)
        self.translate_text.setGeometry(0, 30 * self.rate, width, newHeight)

        # 判断是否和范围框碰撞
        try:
            self.checkOverlap()
        except Exception:
            pass

    # 锁定界面
    def lock(self):

        # 上锁
        if not self.lock_sign:
            self.lock_button.setIcon(
                qtawesome.icon("fa.unlock", color=self.icon_color))
            self.drag_label.hide()
            self.lock_sign = True

            if self.horizontal == 1:
                self.horizontal = 0
        # 解锁
        else:
            self.lock_button.setIcon(
                qtawesome.icon("fa.lock", color=self.icon_color))
            self.lock_button.setStyleSheet("background: transparent;")
            self.drag_label.show()
            self.lock_sign = False

            if self.horizontal == 0:
                self.horizontal = 1

        self.translate_text.setStyleSheet("border-width:0;\
                                          border-style:outset;\
                                          border-top:0px solid #e8f3f9;\
                                          color:white;\
                                          font-weight: bold;\
                                          background-color:rgba(62, 62, 62, %s)"
                                          % (self.horizontal / 100))

        self.temp_text.setStyleSheet("border-width:0;\
                                      border-style:outset;\
                                      border-top:0px solid #e8f3f9;\
                                      color:white;\
                                      font-weight: bold;\
                                      background-color:rgba(62, 62, 62, %s)" %
                                     (self.horizontal / 100))

    # 改变翻译模式
    def changeTranslateMode(self, checked):

        if checked:
            self.translate_mode = True
            self.auto_open_sign.emit(True)
        else:
            self.translate_mode = False

    # 按下翻译键
    def startTranslater(self):

        # 如果已处在自动翻译模式下则直接退出
        if self.auto_trans_exist:
            return

        thread = utils.translater.Translater(self.object)
        thread.clear_text_sign.connect(self.clearText)
        thread.hide_range_ui_sign.connect(self.object.range_ui.hideUI)
        thread.start()
        thread.wait()

    # 收到翻译信息清屏
    def clearText(self):

        # 记录翻译开始时间
        self.object.translation_ui.start_time = time.time()

        # 翻译界面清屏
        self.translate_text.clear()

        # 设定翻译时的字体类型和大小
        self.font.setFamily(self.object.config["fontType"])
        self.font.setPointSize(self.object.config["fontSize"])
        self.translate_text.setFont(self.font)

    # 注销快捷键
    def unregisterHotKey(self):

        if self.object.config["showHotKey1"] == "True":
            self.translate_hotkey.unregister(
                (self.translate_hotkey_value1, self.translate_hotkey_value2))

        if self.object.config["showHotKey2"] == "True":
            self.range_hotkey.unregister(
                (self.range_hotkey_value1, self.range_hotkey_value2))

        if self.object.config["showHotKey3"]:
            self.hide_range_hotkey.unregister(
                (self.hide_range_hotkey_value1, self.hide_range_hotkey_value2))

    # 将翻译结果打印
    def display_text(self, result, trans_type):

        # 公共翻译一
        if trans_type == "webdriver_1":
            color = self.object.config["fontColor"][self.translater_yaml_map[
                self.webdriver1.web_type]]
            trans_type = self.webdriver1.web_type
        # 公共翻译二
        elif trans_type == "webdriver_2":
            color = self.object.config["fontColor"][self.translater_yaml_map[
                self.webdriver2.web_type]]
            trans_type = self.webdriver2.web_type
        # 公共翻译三
        elif trans_type == "webdriver_3":
            color = self.object.config["fontColor"][self.translater_yaml_map[
                self.webdriver3.web_type]]
            trans_type = self.webdriver3.web_type
        # 私人百度
        elif trans_type == "baidu_private":
            color = self.object.config["fontColor"]["baidu"]
        # 私人腾讯
        elif trans_type == "tencent_private":
            color = self.object.config["fontColor"]["tencent"]
        # 私人彩云
        elif trans_type == "caiyun_private":
            color = self.object.config["fontColor"]["caiyunPrivate"]
        # 原文
        elif trans_type == "original":
            color = self.object.config.get("fontColor",
                                           {}).get("original",
                                                   self.font_color_1)
        else:
            return

        # 显示在文本框上
        if self.object.config["showColorType"] == "False":
            self.format.setTextOutline(
                QPen(QColor(color), 0.7, Qt.SolidLine, Qt.RoundCap,
                     Qt.RoundJoin))
            self.translate_text.mergeCurrentCharFormat(self.format)
            self.translate_text.append(result)
        else:
            result = result.replace("\n", "<br>")
            self.translate_text.append("<font color=%s>%s</font>" %
                                       (color, result))
        QApplication.processEvents()

        # 保存译文
        utils.config.saveTransHisTory(result, trans_type)

        # 线程结束,减少线程数
        self.thread_state -= 1
        if self.thread_state < 0:
            self.thread_state = 0

        if self.thread_state == 0:
            try:
                self.statusbar.showMessage(
                    "翻译结束, 耗时: {:.2f} s".format(time.time() - self.start_time +
                                                self.ocr_time))
            except Exception:
                self.statusbar.showMessage(
                    "翻译结束, 耗时: {:.2f} s".format(time.time() - self.start_time))
            self.ocr_time = 0

    # 检测范围区域和翻译区域是否有重叠
    def checkOverlap(self):

        # 翻译框坐标
        rect = self.geometry()
        X1 = rect.left()
        Y1 = rect.top() + (self.height() - self.translate_text.height())
        X2 = rect.left() + rect.width()
        Y2 = rect.top() + rect.height()

        # 范围框坐标
        rect = self.object.range_ui.geometry()
        x1 = rect.left()
        y1 = rect.top()
        x2 = rect.left() + rect.width()
        y2 = rect.top() + rect.height()

        rr1 = utils.range.Rectangular(X1, Y1, X2 - X1, Y2 - Y1)
        rr2 = utils.range.Rectangular(x1, y1, x2 - x1, y2 - y1)

        if rr2.collision(rr1):
            self.customSetGeometry(self.temp_text, 0, 30,
                                   self.translate_text.width(),
                                   self.translate_text.height())
            self.translate_text.hide()
            self.temp_text.show()
        else:
            self.temp_text.hide()
            self.translate_text.show()

    # 加载翻译引擎1
    def openWebdriver1(self):

        # 翻译模块1
        self.webdriver1 = translator.all.Webdriver(self.object)
        # 连接消息提示框
        self.webdriver1.message_sign.connect(self.showStatusbar)
        # 加载翻译引擎
        self.webdriver1.openWebdriver()
        # 开启翻译页面
        if self.webdriver_type1:
            utils.thread.createThread(self.webdriver1.openWeb,
                                      self.webdriver_type1)

    # 加载翻译引擎2
    def openWebdriver2(self):

        # 翻译模块2
        self.webdriver2 = translator.all.Webdriver(self.object)
        # 连接消息提示框
        self.webdriver2.message_sign.connect(self.showStatusbar)
        # 加载翻译引擎
        self.webdriver2.openWebdriver()
        # 开启翻译页面
        if self.webdriver_type2:
            utils.thread.createThread(self.webdriver2.openWeb,
                                      self.webdriver_type2)

    # 加载翻译引擎3
    def openWebdriver3(self):

        # 翻译模块3
        self.webdriver3 = translator.all.Webdriver(self.object)
        # 连接消息提示框
        self.webdriver3.message_sign.connect(self.showStatusbar)
        # 加载翻译引擎
        self.webdriver3.openWebdriver()
        # 开启翻译页面
        if self.webdriver_type3:
            utils.thread.createThread(self.webdriver3.openWeb,
                                      self.webdriver_type3)

    # 开启翻译模块
    def createWebdriverThread(self):

        self.statusbar.showMessage("翻译模块启动中, 请等待完成后再操作...")

        # 筛选翻译源类型
        translater_list = [
            "youdaoUse", "baiduwebUse", "tencentwebUse", "deeplUse",
            "googleUse", "caiyunUse"
        ]
        for val in translater_list:
            if self.object.config[val] == "False":
                continue
            if not self.webdriver_type1:
                # 翻译模块一的翻译源类型
                self.webdriver_type1 = val.replace("Use",
                                                   "").replace("web", "")
            elif not self.webdriver_type2:
                # 翻译模块二的翻译源类型
                self.webdriver_type2 = val.replace("Use",
                                                   "").replace("web", "")
            else:
                self.webdriver_type3 = val.replace("Use",
                                                   "").replace("web", "")

        utils.thread.createThread(self.openWebdriver1)
        utils.thread.createThread(self.openWebdriver2)
        utils.thread.createThread(self.openWebdriver3)

    # 状态栏显示消息信号槽
    def showStatusbar(self, message):

        self.statusbar.showMessage(message)

    # 按下屏蔽词键后做的事情
    def clickFilter(self):

        self.hide()
        self.object.filter_ui.show()

    # 按下范围框选键
    def clickRange(self):

        # 如果处于自动模式下则暂停
        if self.translate_mode:
            self.stop_sign = True

        self.object.screen_shot_ui = ui.range.WScreenShot(self.object)
        self.object.screen_shot_ui.show()
        self.show()

    # 关闭selenuim的driver引擎
    def killDriVer(self):

        utils.thread.createThreadDaemonFalse(
            os.popen, "taskkill /im chromedriver.exe /F")
        utils.thread.createThreadDaemonFalse(
            os.popen, "taskkill /im geckodriver.exe /F")
        utils.thread.createThreadDaemonFalse(
            os.popen, "taskkill /im msedgedriver.exe /F")

    # 退出提示框
    def showAppquitMessageBox(self):

        utils.message.quitAppMessageBox("退出程序", "真的要关闭团子吗?QAQ      ",
                                        self.object)

    # 退出程序
    def quit(self):

        # 界面关闭
        self.hide()
        self.object.range_ui.close()
        # 注销快捷键
        utils.thread.createThreadDaemonFalse(self.unregisterHotKey)
        # 关闭引擎模块
        utils.thread.createThreadDaemonFalse(self.sound.close)
        utils.thread.createThreadDaemonFalse(self.webdriver1.close)
        utils.thread.createThreadDaemonFalse(self.webdriver2.close)
        utils.thread.createThreadDaemonFalse(self.webdriver3.close)
        # 关闭selenium的driver引擎
        self.killDriVer()
        # 退出程序前保存设置
        utils.thread.createThreadDaemonFalse(utils.config.postSaveSettin,
                                             self.object)

        self.close()
示例#12
0
        # mouse.click(button='left')

        # x,y = win32api.GetCursorPos()
        # win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN,x,y,0,0)
        # win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP,x,y,0,0)

        ptg.click()

        ptg.mouseDown()
        ptg.mouseUp()
        print("click")
        time.sleep(0.5)


def hotkeyCallback(x):
    global flag
    flag = flag ^ 1
    print("触发热键!a = ", flag)
    if flag:
        threading.Thread(target=click).start()


try:
    hk = SystemHotkey()
    hk.register(('control', 'shift', 'h'), callback=hotkeyCallback)
    print('热键已注册!')
    input("按回车键结束程序!\n")
finally:
    print('热键已注销!')
    hk.unregister(('control', 'shift', 'h'))
class playWindow(QWidget):
    sig_hot_key = pyqtSignal(str)

    def __init__(self, parent=None):
        super(playWindow, self).__init__(parent)
        # 创建自动演奏线程
        self.playThread = PlayThread()
        # ---------设置全局快捷键----------
        # 设置我们的自定义热键响应函数
        self.sig_hot_key.connect(self.mkey_press_event)
        # 初始化热键
        self.hk_stop = SystemHotkey()
        # 绑定快捷键和对应的信号发送函数
        try:
            self.hk_stop.register(
                ('control', 'shift', 'g'),
                callback=lambda x: self.send_key_event("stop"))
        except InvalidKeyError as e:
            QMessageBox(QMessageBox.Warning, '警告', '热键设置失败').exec_()
            print(e)
        except SystemRegisterError as e:
            QMessageBox(QMessageBox.Warning, '警告', '热键设置冲突').exec_()
            print(e)

        # 5.设置pyqt5的快捷键,ESC退出工具
        QShortcut(QKeySequence("Escape"), self, self.stop_tool)
        # 6.设置图形界面
        self.setup_ui()

    def setup_ui(self):
        self.setWindowTitle("疯物之诗琴")
        self.setWindowIcon(QIcon('icon.ico'))
        self.setFixedSize(QSize(360, 400))
        self.setWindowFlags(Qt.WindowStaysOnTopHint)
        # self.setAttribute(Qt.WA_TranslucentBackground)

        self.widgetLayout = QVBoxLayout()  # 创建垂直布局
        self.widgetLayout.setObjectName("widgetLayout")
        self.setLayout(self.widgetLayout)
        self.playList = QListWidget()
        self.playList.setGeometry(QRect(0, 50, 340, 60))
        self.playList.setMinimumSize(QSize(340, 60))
        self.playList.setBaseSize(QSize(340, 60))
        try:
            self.fileList = os.listdir("midi/")
            self.playList.addItems(self.fileList)
        except FileNotFoundError as e:
            QMessageBox(QMessageBox.Warning, '警告', '没有找到midi文件').exec_()
            print(e)

        self.msgLabel = QLabel(
            '双击列表选项开始或停止演奏\nEsc退出程序,Ctrl+Shift+G停止演奏\n目前一共有%d条曲目' %
            (len(self.playList)))
        self.msgLabel.setGeometry(QRect(0, 0, 360, 50))
        self.msgLabel.setMinimumSize(QSize(360, 50))
        self.msgLabel.setBaseSize(QSize(360, 50))
        self.msgLabel.setAlignment(Qt.AlignLeft)
        self.msgLabel.setObjectName("msgLabel")

        self.playStatus = QLabel('请选择一首音乐开始演奏')
        self.playStatus.setGeometry(QRect(0, 130, 360, 20))
        self.playStatus.setMinimumSize(QSize(360, 20))
        self.playStatus.setBaseSize(QSize(360, 20))
        # 添加控件到布局中
        self.widgetLayout.addWidget(self.msgLabel)
        self.widgetLayout.addWidget(self.playList)
        self.widgetLayout.addWidget(self.playStatus)
        # 绑定操作函数
        self.playList.itemClicked.connect(self.play_item_clicked)
        self.playList.doubleClicked.connect(self.play_midi)
        self.playThread.playSignal.connect(self.show_stop_play)

    # 在界面显示选择的状态
    def play_item_clicked(self, item):
        print('你选择了:' + item.text())
        self.playStatus.setText('你选择了:' + item.text())

    # 热键处理函数
    def mkey_press_event(self, i_str):
        print("按下的按键是%s" % (i_str, ))
        self.stop_play_thread()  # 按下全局快捷键终止演奏线程

    # 热键信号发送函数(将外部信号,转化成qt信号)
    def send_key_event(self, i_str):
        self.sig_hot_key.emit(i_str)

    # 启动playThread进行自动演奏
    def play_midi(self, index):
        self.stop_play_thread()
        print('开始演奏:' + self.fileList[index.row()])
        # 显示演奏的状态
        self.playStatus.setText('开始演奏:' + self.fileList[index.row()])
        self.playThread.set_file_path("midi/" + self.fileList[index.row()])
        self.playThread.start()
        pass

    def show_stop_play(self, msg):
        self.playStatus.setText(msg)

    # 终止演奏线程,停止自动演奏
    def stop_play_thread(self):
        self.playStatus.setText('停止演奏')  # 在工具界面显示状态
        self.playThread.stop_play()
        time.sleep(0.1)
        if not self.playThread.isFinished():
            self.playThread.terminate()
            self.playThread.wait()
        return

    # 工具退出函数,主要用来停止演奏线程和退出注销热键
    def stop_tool(self):
        self.stop_play_thread()
        time.sleep(0.1)
        try:
            self.hk_stop.unregister(('control', 'shift', 'g'))
        except UnregisterError as e:
            QMessageBox(QMessageBox.Warning, '警告', '热键注销失败').exec_()
            print(e)
        QCoreApplication.instance().quit()
        print('退出了应用!!!')