windows.media.speech: Implement ResultGenerated event.
Also add helpers to manage typed event handlers. Signed-off-by: Bernhard Kölbl <besentv@gmail.com> Signed-off-by: Rémi Bernon <rbernon@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
0ff960b737
commit
3549bb80d0
|
@ -2,6 +2,7 @@ MODULE = windows.media.speech.dll
|
||||||
IMPORTS = combase uuid
|
IMPORTS = combase uuid
|
||||||
|
|
||||||
C_SRCS = \
|
C_SRCS = \
|
||||||
|
event_handlers.c \
|
||||||
listconstraint.c \
|
listconstraint.c \
|
||||||
main.c \
|
main.c \
|
||||||
recognizer.c \
|
recognizer.c \
|
||||||
|
|
|
@ -0,0 +1,108 @@
|
||||||
|
/* WinRT Windows.Media.SpeechRecognition implementation
|
||||||
|
*
|
||||||
|
* Copyright 2022 Bernhard Kölbl
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "private.h"
|
||||||
|
|
||||||
|
static CRITICAL_SECTION handlers_cs;
|
||||||
|
static CRITICAL_SECTION_DEBUG handlers_cs_debug =
|
||||||
|
{
|
||||||
|
0, 0, &handlers_cs,
|
||||||
|
{ &handlers_cs_debug.ProcessLocksList, &handlers_cs_debug.ProcessLocksList },
|
||||||
|
0, 0, { (DWORD_PTR)(__FILE__ ": handlers_cs") }
|
||||||
|
};
|
||||||
|
static CRITICAL_SECTION handlers_cs = { &handlers_cs_debug, -1, 0, 0, 0, 0 };
|
||||||
|
static EventRegistrationToken next_token = {.value = 1};
|
||||||
|
|
||||||
|
struct typed_event_handler_entry
|
||||||
|
{
|
||||||
|
struct list entry;
|
||||||
|
EventRegistrationToken token;
|
||||||
|
ITypedEventHandler_IInspectable_IInspectable *handler;
|
||||||
|
};
|
||||||
|
|
||||||
|
HRESULT typed_event_handlers_append( struct list *list, ITypedEventHandler_IInspectable_IInspectable *handler, EventRegistrationToken *token )
|
||||||
|
{
|
||||||
|
struct typed_event_handler_entry *entry;
|
||||||
|
|
||||||
|
if (!(entry = calloc(1, sizeof(*entry)))) return E_OUTOFMEMORY;
|
||||||
|
ITypedEventHandler_IInspectable_IInspectable_AddRef((entry->handler = handler));
|
||||||
|
|
||||||
|
EnterCriticalSection(&handlers_cs);
|
||||||
|
|
||||||
|
*token = entry->token = next_token;
|
||||||
|
next_token.value++;
|
||||||
|
list_add_tail(list, &entry->entry);
|
||||||
|
|
||||||
|
LeaveCriticalSection(&handlers_cs);
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT typed_event_handlers_remove( struct list *list, EventRegistrationToken *token )
|
||||||
|
{
|
||||||
|
struct typed_event_handler_entry *entry;
|
||||||
|
BOOL found = FALSE;
|
||||||
|
|
||||||
|
EnterCriticalSection(&handlers_cs);
|
||||||
|
|
||||||
|
LIST_FOR_EACH_ENTRY(entry, list, struct typed_event_handler_entry, entry)
|
||||||
|
if ((found = !memcmp(&entry->token, token, sizeof(*token)))) break;
|
||||||
|
if (found) list_remove(&entry->entry);
|
||||||
|
|
||||||
|
LeaveCriticalSection(&handlers_cs);
|
||||||
|
|
||||||
|
if (found)
|
||||||
|
{
|
||||||
|
ITypedEventHandler_IInspectable_IInspectable_Release(entry->handler);
|
||||||
|
free(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT typed_event_handlers_notify( struct list *list, IInspectable *sender, IInspectable *args )
|
||||||
|
{
|
||||||
|
struct typed_event_handler_entry *entry;
|
||||||
|
|
||||||
|
EnterCriticalSection(&handlers_cs);
|
||||||
|
|
||||||
|
LIST_FOR_EACH_ENTRY(entry, list, struct typed_event_handler_entry, entry)
|
||||||
|
ITypedEventHandler_IInspectable_IInspectable_Invoke(entry->handler, sender, args);
|
||||||
|
|
||||||
|
LeaveCriticalSection(&handlers_cs);
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT typed_event_handlers_clear( struct list* list )
|
||||||
|
{
|
||||||
|
struct typed_event_handler_entry *entry, *entry_cursor2;
|
||||||
|
|
||||||
|
EnterCriticalSection(&handlers_cs);
|
||||||
|
|
||||||
|
LIST_FOR_EACH_ENTRY_SAFE(entry, entry_cursor2, list, struct typed_event_handler_entry, entry)
|
||||||
|
{
|
||||||
|
list_remove(&entry->entry);
|
||||||
|
free(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
LeaveCriticalSection(&handlers_cs);
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
|
@ -40,6 +40,8 @@
|
||||||
#define WIDL_using_Windows_Media_SpeechRecognition
|
#define WIDL_using_Windows_Media_SpeechRecognition
|
||||||
#include "windows.media.speechrecognition.h"
|
#include "windows.media.speechrecognition.h"
|
||||||
|
|
||||||
|
#include "wine/list.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
* Windows.Media.SpeechRecognition
|
* Windows.Media.SpeechRecognition
|
||||||
|
@ -59,6 +61,11 @@ extern IActivationFactory *synthesizer_factory;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
HRESULT typed_event_handlers_append( struct list *list, ITypedEventHandler_IInspectable_IInspectable *handler, EventRegistrationToken *token );
|
||||||
|
HRESULT typed_event_handlers_remove( struct list *list, EventRegistrationToken *token );
|
||||||
|
HRESULT typed_event_handlers_notify( struct list *list, IInspectable *sender, IInspectable *args );
|
||||||
|
HRESULT typed_event_handlers_clear( struct list* list );
|
||||||
|
|
||||||
#define DEFINE_IINSPECTABLE_( pfx, iface_type, impl_type, impl_from, iface_mem, expr ) \
|
#define DEFINE_IINSPECTABLE_( pfx, iface_type, impl_type, impl_from, iface_mem, expr ) \
|
||||||
static inline impl_type *impl_from( iface_type *iface ) \
|
static inline impl_type *impl_from( iface_type *iface ) \
|
||||||
{ \
|
{ \
|
||||||
|
|
|
@ -33,6 +33,8 @@ struct session
|
||||||
{
|
{
|
||||||
ISpeechContinuousRecognitionSession ISpeechContinuousRecognitionSession_iface;
|
ISpeechContinuousRecognitionSession ISpeechContinuousRecognitionSession_iface;
|
||||||
LONG ref;
|
LONG ref;
|
||||||
|
|
||||||
|
struct list result_handlers;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -80,7 +82,10 @@ static ULONG WINAPI session_Release( ISpeechContinuousRecognitionSession *iface
|
||||||
TRACE("iface %p, ref %lu.\n", iface, ref);
|
TRACE("iface %p, ref %lu.\n", iface, ref);
|
||||||
|
|
||||||
if (!ref)
|
if (!ref)
|
||||||
|
{
|
||||||
|
typed_event_handlers_clear(&impl->result_handlers);
|
||||||
free(impl);
|
free(impl);
|
||||||
|
}
|
||||||
|
|
||||||
return ref;
|
return ref;
|
||||||
}
|
}
|
||||||
|
@ -171,14 +176,17 @@ static HRESULT WINAPI session_add_ResultGenerated( ISpeechContinuousRecognitionS
|
||||||
ITypedEventHandler_SpeechContinuousRecognitionSession_SpeechContinuousRecognitionResultGeneratedEventArgs *handler,
|
ITypedEventHandler_SpeechContinuousRecognitionSession_SpeechContinuousRecognitionResultGeneratedEventArgs *handler,
|
||||||
EventRegistrationToken *token)
|
EventRegistrationToken *token)
|
||||||
{
|
{
|
||||||
FIXME("iface %p, handler %p, token %p stub!\n", iface, handler, token);
|
struct session *impl = impl_from_ISpeechContinuousRecognitionSession(iface);
|
||||||
return E_NOTIMPL;
|
TRACE("iface %p, handler %p, token %p.\n", iface, handler, token);
|
||||||
|
if (!handler) return E_INVALIDARG;
|
||||||
|
return typed_event_handlers_append(&impl->result_handlers, (ITypedEventHandler_IInspectable_IInspectable *)handler, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
static HRESULT WINAPI session_remove_ResultGenerated( ISpeechContinuousRecognitionSession *iface, EventRegistrationToken token )
|
static HRESULT WINAPI session_remove_ResultGenerated( ISpeechContinuousRecognitionSession *iface, EventRegistrationToken token )
|
||||||
{
|
{
|
||||||
FIXME("iface %p, token.value %#I64x stub!\n", iface, token.value);
|
struct session *impl = impl_from_ISpeechContinuousRecognitionSession(iface);
|
||||||
return E_NOTIMPL;
|
TRACE("iface %p, token.value %#I64x.\n", iface, token.value);
|
||||||
|
return typed_event_handlers_remove(&impl->result_handlers, &token);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct ISpeechContinuousRecognitionSessionVtbl session_vtbl =
|
static const struct ISpeechContinuousRecognitionSessionVtbl session_vtbl =
|
||||||
|
@ -637,6 +645,7 @@ static HRESULT WINAPI recognizer_factory_Create( ISpeechRecognizerFactory *iface
|
||||||
|
|
||||||
session->ISpeechContinuousRecognitionSession_iface.lpVtbl = &session_vtbl;
|
session->ISpeechContinuousRecognitionSession_iface.lpVtbl = &session_vtbl;
|
||||||
session->ref = 1;
|
session->ref = 1;
|
||||||
|
list_init(&session->result_handlers);
|
||||||
|
|
||||||
impl->ISpeechRecognizer_iface.lpVtbl = &speech_recognizer_vtbl;
|
impl->ISpeechRecognizer_iface.lpVtbl = &speech_recognizer_vtbl;
|
||||||
impl->IClosable_iface.lpVtbl = &closable_vtbl;
|
impl->IClosable_iface.lpVtbl = &closable_vtbl;
|
||||||
|
|
|
@ -40,6 +40,12 @@
|
||||||
|
|
||||||
#define SPERR_WINRT_INTERNAL_ERROR 0x800455a0
|
#define SPERR_WINRT_INTERNAL_ERROR 0x800455a0
|
||||||
|
|
||||||
|
#define IHandler_RecognitionResult ITypedEventHandler_SpeechContinuousRecognitionSession_SpeechContinuousRecognitionResultGeneratedEventArgs
|
||||||
|
#define IHandler_RecognitionResultVtbl ITypedEventHandler_SpeechContinuousRecognitionSession_SpeechContinuousRecognitionResultGeneratedEventArgsVtbl
|
||||||
|
#define IID_IHandler_RecognitionResult IID_ITypedEventHandler_SpeechContinuousRecognitionSession_SpeechContinuousRecognitionResultGeneratedEventArgs
|
||||||
|
#define impl_from_IHandler_RecognitionResult impl_from_ITypedEventHandler_SpeechContinuousRecognitionSession_SpeechContinuousRecognitionResultGeneratedEventArgs
|
||||||
|
#define IHandler_RecognitionResult_iface ITypedEventHandler_SpeechContinuousRecognitionSession_SpeechContinuousRecognitionResultGeneratedEventArgs_iface
|
||||||
|
|
||||||
HRESULT WINAPI (*pDllGetActivationFactory)(HSTRING, IActivationFactory **);
|
HRESULT WINAPI (*pDllGetActivationFactory)(HSTRING, IActivationFactory **);
|
||||||
static BOOL is_win10_1507 = FALSE;
|
static BOOL is_win10_1507 = FALSE;
|
||||||
|
|
||||||
|
@ -80,6 +86,72 @@ static const char *debugstr_hstring(HSTRING hstr)
|
||||||
return wine_dbgstr_wn(str, len);
|
return wine_dbgstr_wn(str, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct recognition_result_handler
|
||||||
|
{
|
||||||
|
IHandler_RecognitionResult IHandler_RecognitionResult_iface;
|
||||||
|
LONG ref;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline struct recognition_result_handler *impl_from_IHandler_RecognitionResult( IHandler_RecognitionResult *iface )
|
||||||
|
{
|
||||||
|
return CONTAINING_RECORD(iface, struct recognition_result_handler, IHandler_RecognitionResult_iface);
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT WINAPI recognition_result_handler_QueryInterface( IHandler_RecognitionResult *iface, REFIID iid, void **out )
|
||||||
|
{
|
||||||
|
if (IsEqualGUID(iid, &IID_IUnknown) ||
|
||||||
|
IsEqualGUID(iid, &IID_IHandler_RecognitionResult))
|
||||||
|
{
|
||||||
|
IUnknown_AddRef(iface);
|
||||||
|
*out = iface;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
trace("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
|
||||||
|
*out = NULL;
|
||||||
|
return E_NOINTERFACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
ULONG WINAPI recognition_result_handler_AddRef( IHandler_RecognitionResult *iface )
|
||||||
|
{
|
||||||
|
struct recognition_result_handler *impl = impl_from_IHandler_RecognitionResult(iface);
|
||||||
|
ULONG ref = InterlockedIncrement(&impl->ref);
|
||||||
|
return ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
ULONG WINAPI recognition_result_handler_Release( IHandler_RecognitionResult *iface )
|
||||||
|
{
|
||||||
|
struct recognition_result_handler *impl = impl_from_IHandler_RecognitionResult(iface);
|
||||||
|
ULONG ref = InterlockedDecrement(&impl->ref);
|
||||||
|
return ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT WINAPI recognition_result_handler_Invoke( IHandler_RecognitionResult *iface,
|
||||||
|
ISpeechContinuousRecognitionSession *sender,
|
||||||
|
ISpeechContinuousRecognitionResultGeneratedEventArgs *args )
|
||||||
|
{
|
||||||
|
trace("iface %p, sender %p, args %p.\n", iface, sender, args);
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct IHandler_RecognitionResultVtbl recognition_result_handler_vtbl =
|
||||||
|
{
|
||||||
|
/* IUnknown methods */
|
||||||
|
recognition_result_handler_QueryInterface,
|
||||||
|
recognition_result_handler_AddRef,
|
||||||
|
recognition_result_handler_Release,
|
||||||
|
/* ITypedEventHandler<SpeechContinuousRecognitionSession*, SpeechContinuousRecognitionResultGeneratedEventArgs* > methods */
|
||||||
|
recognition_result_handler_Invoke
|
||||||
|
};
|
||||||
|
|
||||||
|
static HRESULT WINAPI recognition_result_handler_create_static( struct recognition_result_handler *impl )
|
||||||
|
{
|
||||||
|
impl->IHandler_RecognitionResult_iface.lpVtbl = &recognition_result_handler_vtbl;
|
||||||
|
impl->ref = 1;
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
struct iterator_hstring
|
struct iterator_hstring
|
||||||
{
|
{
|
||||||
IIterator_HSTRING IIterator_HSTRING_iface;
|
IIterator_HSTRING IIterator_HSTRING_iface;
|
||||||
|
@ -192,7 +264,7 @@ static const struct IIterator_HSTRINGVtbl iterator_hstring_vtbl =
|
||||||
iterator_hstring_GetMany
|
iterator_hstring_GetMany
|
||||||
};
|
};
|
||||||
|
|
||||||
static HRESULT WINAPI iterator_hstring_create_static(struct iterator_hstring *impl, HSTRING *strings, UINT32 size)
|
static HRESULT WINAPI iterator_hstring_create_static( struct iterator_hstring *impl, HSTRING *strings, UINT32 size )
|
||||||
{
|
{
|
||||||
impl->IIterator_HSTRING_iface.lpVtbl = &iterator_hstring_vtbl;
|
impl->IIterator_HSTRING_iface.lpVtbl = &iterator_hstring_vtbl;
|
||||||
impl->ref = 1;
|
impl->ref = 1;
|
||||||
|
@ -294,7 +366,7 @@ static const struct IIterable_HSTRINGVtbl iterable_hstring_vtbl =
|
||||||
iterable_hstring_First
|
iterable_hstring_First
|
||||||
};
|
};
|
||||||
|
|
||||||
static HRESULT WINAPI iterable_hstring_create_static(struct iterable_hstring *impl, struct iterator_hstring *iterator)
|
static HRESULT WINAPI iterable_hstring_create_static( struct iterable_hstring *impl, struct iterator_hstring *iterator )
|
||||||
{
|
{
|
||||||
impl->IIterable_HSTRING_iface.lpVtbl = &iterable_hstring_vtbl;
|
impl->IIterable_HSTRING_iface.lpVtbl = &iterable_hstring_vtbl;
|
||||||
impl->ref = 1;
|
impl->ref = 1;
|
||||||
|
@ -579,6 +651,8 @@ static void test_SpeechRecognizer(void)
|
||||||
IInspectable *inspectable = NULL;
|
IInspectable *inspectable = NULL;
|
||||||
IClosable *closable = NULL;
|
IClosable *closable = NULL;
|
||||||
ILanguage *language = NULL;
|
ILanguage *language = NULL;
|
||||||
|
struct recognition_result_handler result_handler;
|
||||||
|
EventRegistrationToken token = { .value = 0 };
|
||||||
HSTRING hstr, hstr_lang;
|
HSTRING hstr, hstr_lang;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
LONG ref;
|
LONG ref;
|
||||||
|
@ -654,6 +728,18 @@ static void test_SpeechRecognizer(void)
|
||||||
check_refcount(session, 2);
|
check_refcount(session, 2);
|
||||||
check_refcount(inspectable, 3);
|
check_refcount(inspectable, 3);
|
||||||
|
|
||||||
|
hr = ISpeechContinuousRecognitionSession_add_ResultGenerated(session, NULL, &token);
|
||||||
|
ok(hr == E_INVALIDARG, "ISpeechContinuousRecognitionSession_add_ResultGenerated failed, hr %#lx.\n", hr);
|
||||||
|
|
||||||
|
token.value = 0xdeadbeef;
|
||||||
|
recognition_result_handler_create_static(&result_handler);
|
||||||
|
hr = ISpeechContinuousRecognitionSession_add_ResultGenerated(session, &result_handler.IHandler_RecognitionResult_iface, &token);
|
||||||
|
ok(hr == S_OK, "ISpeechContinuousRecognitionSession_add_ResultGenerated failed, hr %#lx.\n", hr);
|
||||||
|
ok(token.value != 0xdeadbeef, "Got unexpexted token: %#I64x.\n", token.value);
|
||||||
|
|
||||||
|
hr = ISpeechContinuousRecognitionSession_remove_ResultGenerated(session, token);
|
||||||
|
ok(hr == S_OK, "ISpeechContinuousRecognitionSession_remove_ResultGenerated failed, hr %#lx.\n", hr);
|
||||||
|
|
||||||
ref = ISpeechContinuousRecognitionSession_Release(session);
|
ref = ISpeechContinuousRecognitionSession_Release(session);
|
||||||
ok(ref == 1, "Got unexpected ref %lu.\n", ref);
|
ok(ref == 1, "Got unexpected ref %lu.\n", ref);
|
||||||
|
|
||||||
|
|
|
@ -171,6 +171,7 @@ namespace Windows {
|
||||||
interface Windows.Foundation.AsyncOperationCompletedHandler<boolean>;
|
interface Windows.Foundation.AsyncOperationCompletedHandler<boolean>;
|
||||||
interface Windows.Foundation.IAsyncOperation<boolean>;
|
interface Windows.Foundation.IAsyncOperation<boolean>;
|
||||||
interface Windows.Foundation.IReference<INT32>;
|
interface Windows.Foundation.IReference<INT32>;
|
||||||
|
interface Windows.Foundation.TypedEventHandler<IInspectable *, IInspectable *>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue