示例#1
0
    def test_identity(self):
        # COM indentity rules

        # these should be identical
        a = POINTER(IUnknown)()
        b = POINTER(IUnknown)()
        self.assertEqual(a, b)
        self.assertEqual(hash(a), hash(b))

        from comtypes.typeinfo import CreateTypeLib

        # we do not save the lib, so no file will be created.
        # these should NOT be identical
        a = CreateTypeLib("blahblah")
        b = CreateTypeLib("spam")

        self.assertNotEqual(a, b)
        self.assertNotEqual(hash(a), hash(b))

        a = a.QueryInterface(IUnknown)
        b = b.QueryInterface(IUnknown)

        self.assertNotEqual(a, b)
        self.assertNotEqual(hash(a), hash(b))

        # These must be identical
        c = a.QueryInterface(IUnknown)
        self.assertEqual(a, c)
        self.assertEqual(hash(a), hash(c))
示例#2
0
文件: utils.py 项目: NoSegfault/pyia2
def accessibleObjectFromEvent(event):
    if not windll.user32.IsWindow(event.hwnd):
        return None
    ptr = POINTER(IAccessible)()
    varChild = VARIANT()
    res = windll.oleacc.AccessibleObjectFromEvent(event.hwnd, event.object_id,
                                                  event.child_id, byref(ptr),
                                                  byref(varChild))
    if res == 0:
        child = varChild.value
        return ptr.QueryInterface(IAccessible)
    else:
        return None
示例#3
0
    def test_qi(self):
        p = POINTER(IUnknown)()
        windll.oleaut32.CreateTypeLib2(1, "blabla", byref(p))
        self.assertEqual(p.AddRef(), 2)
        self.assertEqual(p.Release(), 1)

        other = p.QueryInterface(IUnknown)
        self.assertEqual(other.AddRef(), 3)
        self.assertEqual(p.AddRef(), 4)
        self.assertEqual(p.Release(), 3)
        self.assertEqual(other.Release(), 2)

        del p  # calls p.Release()

        self.assertEqual(other.AddRef(), 2)
        self.assertEqual(other.Release(), 1)
示例#4
0
class SynthDriver(SynthDriver):

    name = "sapi4"
    description = "Microsoft Speech API version 4"
    supportedSettings = [SynthDriver.VoiceSetting()]
    supportedNotifications = {synthIndexReached, synthDoneSpeaking}

    @classmethod
    def check(cls):
        try:
            winreg.OpenKey(winreg.HKEY_CLASSES_ROOT,
                           r"CLSID\%s" % CLSID_TTSEnumerator).Close()
            return True
        except WindowsError:
            return False

    def _fetchEnginesList(self):
        enginesList = []
        self._ttsEngines.Reset()
        while True:
            mode = TTSMODEINFO()
            fetched = c_ulong()
            try:
                self._ttsEngines.Next(1, byref(mode), byref(fetched))
            except:
                log.error("can't get next engine", exc_info=True)
                break
            if fetched.value == 0:
                break
            enginesList.append(mode)
        return enginesList

    def __init__(self):
        self._finalIndex = None
        self._bufSink = SynthDriverBufSink(weakref.ref(self))
        self._bufSinkPtr = self._bufSink.QueryInterface(ITTSBufNotifySink)
        # HACK: Some buggy engines call Release() too many times on our buf sink.
        # Therefore, don't let the buf sink be deleted before we release it ourselves.
        self._bufSink._allowDelete = False
        self._ttsEngines = CoCreateInstance(CLSID_TTSEnumerator, ITTSEnumW)
        self._enginesList = self._fetchEnginesList()
        if len(self._enginesList) == 0:
            raise RuntimeError("No Sapi4 engines available")
        self.voice = str(self._enginesList[0].gModeID)

    def terminate(self):
        self._bufSink._allowDelete = True

    def speak(self, speechSequence):
        textList = []
        charMode = False
        item = None
        isPitchCommand = False
        pitch = WORD()
        self._ttsAttrs.PitchGet(byref(pitch))
        oldPitch = pitch.value

        for item in speechSequence:
            if isinstance(item, str):
                textList.append(item.replace('\\', '\\\\'))
            elif isinstance(item, IndexCommand):
                textList.append("\\mrk=%d\\" % item.index)
            elif isinstance(item, CharacterModeCommand):
                textList.append("\\RmS=1\\" if item.state else "\\RmS=0\\")
                charMode = item.state
            elif isinstance(item, BreakCommand):
                textList.append(f"\\Pau={item.time}\\")
            elif isinstance(item, PitchCommand):
                offset = int(config.conf["speech"]['sapi4']["capPitchChange"])
                offset = int((self._maxPitch - self._minPitch) * offset / 100)
                val = oldPitch + offset
                if val > self._maxPitch:
                    val = self._maxPitch
                if val < self._minPitch:
                    val = self._minPitch
                self._ttsAttrs.PitchSet(val)
                isPitchCommand = True
            elif isinstance(item, SpeechCommand):
                log.debugWarning("Unsupported speech command: %s" % item)
            else:
                log.error("Unknown speech: %s" % item)
        if isinstance(item, IndexCommand):
            # This is the index denoting the end of the speech sequence.
            self._finalIndex = item.index
        if charMode:
            # Some synths stay in character mode if we don't explicitly disable it.
            textList.append("\\RmS=0\\")
        # Some SAPI4 synthesizers complete speech sequence just after the last text
        # and ignore any indexes passed after it
        # Therefore we add the pause of 1ms at the end
        textList.append("\\PAU=1\\")
        text = "".join(textList)
        flags = TTSDATAFLAG_TAGGED
        if isPitchCommand:
            self._ttsCentral.TextData(VOICECHARSET.CHARSET_TEXT, flags,
                                      TextSDATA(text), self._bufSinkPtr,
                                      ITTSBufNotifySink._iid_)
            self._ttsAttrs.PitchSet(oldPitch)
            isPitchCommand = False
        else:
            self._ttsCentral.TextData(VOICECHARSET.CHARSET_TEXT, flags,
                                      TextSDATA(text), self._bufSinkPtr,
                                      ITTSBufNotifySink._iid_)

    def cancel(self):
        self._ttsCentral.AudioReset()
        self.lastIndex = None

    def pause(self, switch):
        if switch:
            try:
                self._ttsCentral.AudioPause()
            except COMError:
                pass
        else:
            self._ttsCentral.AudioResume()

    def removeSetting(self, name):
        #Putting it here because currently no other synths make use of it. OrderedDict, where you are?
        for i, s in enumerate(self.supportedSettings):
            if s.name == name:
                del self.supportedSettings[i]
                return

    def _set_voice(self, val):
        try:
            val = GUID(val)
        except:
            val = self._enginesList[0].gModeID
        mode = None
        for mode in self._enginesList:
            if mode.gModeID == val:
                break
        if mode is None:
            raise ValueError("no such mode: %s" % val)
        self._currentMode = mode
        self._ttsAudio = CoCreateInstance(CLSID_MMAudioDest,
                                          IAudioMultiMediaDevice)
        self._ttsAudio.DeviceNumSet(
            nvwave.outputDeviceNameToID(config.conf["speech"]["outputDevice"],
                                        True))
        self._ttsCentral = POINTER(ITTSCentralW)()
        self._ttsEngines.Select(self._currentMode.gModeID,
                                byref(self._ttsCentral), self._ttsAudio)
        self._ttsAttrs = self._ttsCentral.QueryInterface(ITTSAttributes)
        #Find out rate limits
        hasRate = bool(mode.dwFeatures & TTSFEATURE_SPEED)
        if hasRate:
            try:
                oldVal = DWORD()
                self._ttsAttrs.SpeedGet(byref(oldVal))
                self._ttsAttrs.SpeedSet(TTSATTR_MINSPEED)
                newVal = DWORD()
                self._ttsAttrs.SpeedGet(byref(newVal))
                self._minRate = newVal.value
                self._ttsAttrs.SpeedSet(TTSATTR_MAXSPEED)
                self._ttsAttrs.SpeedGet(byref(newVal))
                # ViaVoice (and perhaps other synths) doesn't seem to like the speed being set to maximum.
                self._maxRate = newVal.value - 1
                self._ttsAttrs.SpeedSet(oldVal.value)
                if self._maxRate <= self._minRate:
                    hasRate = False
            except COMError:
                hasRate = False
        if hasRate:
            if not self.isSupported('rate'):
                self.supportedSettings.insert(1, SynthDriver.RateSetting())
        else:
            if self.isSupported("rate"): self.removeSetting("rate")
        #Find out pitch limits
        hasPitch = bool(mode.dwFeatures & TTSFEATURE_PITCH)
        if hasPitch:
            try:
                oldVal = WORD()
                self._ttsAttrs.PitchGet(byref(oldVal))
                self._ttsAttrs.PitchSet(TTSATTR_MINPITCH)
                newVal = WORD()
                self._ttsAttrs.PitchGet(byref(newVal))
                self._minPitch = newVal.value
                self._ttsAttrs.PitchSet(TTSATTR_MAXPITCH)
                self._ttsAttrs.PitchGet(byref(newVal))
                self._maxPitch = newVal.value
                self._ttsAttrs.PitchSet(oldVal.value)
                if self._maxPitch <= self._minPitch:
                    hasPitch = False
            except COMError:
                hasPitch = False
        if hasPitch:
            if not self.isSupported('pitch'):
                self.supportedSettings.insert(2, SynthDriver.PitchSetting())
        else:
            if self.isSupported('pitch'): self.removeSetting('pitch')
        #Find volume limits
        hasVolume = bool(mode.dwFeatures & TTSFEATURE_VOLUME)
        if hasVolume:
            try:
                oldVal = DWORD()
                self._ttsAttrs.VolumeGet(byref(oldVal))
                self._ttsAttrs.VolumeSet(TTSATTR_MINVOLUME)
                newVal = DWORD()
                self._ttsAttrs.VolumeGet(byref(newVal))
                self._minVolume = newVal.value
                self._ttsAttrs.VolumeSet(TTSATTR_MAXVOLUME)
                self._ttsAttrs.VolumeGet(byref(newVal))
                self._maxVolume = newVal.value
                self._ttsAttrs.VolumeSet(oldVal.value)
                if self._maxVolume <= self._minVolume:
                    hasVolume = False
            except COMError:
                hasVolume = False
        if hasVolume:
            if not self.isSupported('volume'):
                self.supportedSettings.insert(3, SynthDriver.VolumeSetting())
        else:
            if self.isSupported('volume'): self.removeSetting('volume')

    def _get_voice(self):
        return str(self._currentMode.gModeID)

    def _getAvailableVoices(self):
        voices = OrderedDict()
        for mode in self._enginesList:
            ID = str(mode.gModeID)
            name = "%s - %s" % (mode.szModeName, mode.szProductName)
            try:
                language = locale.windows_locale[mode.language.LanguageID]
            except KeyError:
                language = None
            voices[ID] = VoiceInfo(ID, name, language)
        return voices

    def _get_rate(self):
        val = DWORD()
        self._ttsAttrs.SpeedGet(byref(val))
        return self._paramToPercent(val.value, self._minRate, self._maxRate)

    def _set_rate(self, val):
        val = self._percentToParam(val, self._minRate, self._maxRate)
        self._ttsAttrs.SpeedSet(val)

    def _get_pitch(self):
        val = WORD()
        self._ttsAttrs.PitchGet(byref(val))
        return self._paramToPercent(val.value, self._minPitch, self._maxPitch)

    def _set_pitch(self, val):
        val = self._percentToParam(val, self._minPitch, self._maxPitch)
        self._ttsAttrs.PitchSet(val)

    def _get_volume(self):
        val = DWORD()
        self._ttsAttrs.VolumeGet(byref(val))
        return self._paramToPercent(val.value & 0xffff,
                                    self._minVolume & 0xffff,
                                    self._maxVolume & 0xffff)

    def _set_volume(self, val):
        val = self._percentToParam(val, self._minVolume & 0xffff,
                                   self._maxVolume & 0xffff)
        val += val << 16
        self._ttsAttrs.VolumeSet(val)