Initial swkbd implementation (#826)

* am: Initial swkbd implementation

Currently only implements the full screen keyboard, inline keyboard will come later.

* Remove unnecessary logging

* Miscellaneous tidy up

* am: Always pop incoming interactive session data

* am: Add a reminder to implement the full config struct

* am: Check for a max length of zero

We should only limit/truncate text when the max length is set to a non-zero value.

* Add documentation

* am: Return IStorage not available when queue is empty

We should be returning the appropriate error code when the FIFO is empty, rather than just throwing an exception and killing the emulator.

* Fix typo

* Code style changes
This commit is contained in:
jduncanator 2019-11-18 22:16:26 +11:00 committed by Ac_K
parent 79abc6ed93
commit ee81ab547e
14 changed files with 522 additions and 38 deletions

View file

@ -11,35 +11,50 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Lib
{
private IApplet _applet;
private AppletFifo<byte[]> _inData;
private AppletFifo<byte[]> _outData;
private AppletSession _normalSession;
private AppletSession _interactiveSession;
private KEvent _stateChangedEvent;
private KEvent _normalOutDataEvent;
private KEvent _interactiveOutDataEvent;
public ILibraryAppletAccessor(AppletId appletId, Horizon system)
{
_stateChangedEvent = new KEvent(system);
_stateChangedEvent = new KEvent(system);
_normalOutDataEvent = new KEvent(system);
_interactiveOutDataEvent = new KEvent(system);
_applet = AppletManager.Create(appletId, system);
_inData = new AppletFifo<byte[]>();
_outData = new AppletFifo<byte[]>();
_applet.AppletStateChanged += OnAppletStateChanged;
_applet = AppletManager.Create(appletId, system);
_normalSession = new AppletSession();
_interactiveSession = new AppletSession();
_applet.AppletStateChanged += OnAppletStateChanged;
_normalSession.DataAvailable += OnNormalOutData;
_interactiveSession.DataAvailable += OnInteractiveOutData;
Logger.PrintInfo(LogClass.ServiceAm, $"Applet '{appletId}' created.");
}
private void OnAppletStateChanged(object sender, EventArgs e)
{
_stateChangedEvent.ReadableEvent.Signal();
_stateChangedEvent.WritableEvent.Signal();
}
private void OnNormalOutData(object sender, EventArgs e)
{
_normalOutDataEvent.WritableEvent.Signal();
}
private void OnInteractiveOutData(object sender, EventArgs e)
{
_interactiveOutDataEvent.WritableEvent.Signal();
}
[Command(0)]
// GetAppletStateChangedEvent() -> handle<copy>
public ResultCode GetAppletStateChangedEvent(ServiceCtx context)
{
_stateChangedEvent.ReadableEvent.Signal();
if (context.Process.HandleTable.GenerateHandle(_stateChangedEvent.ReadableEvent, out int handle) != KernelResult.Success)
{
throw new InvalidOperationException("Out of handles!");
@ -54,7 +69,8 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Lib
// Start()
public ResultCode Start(ServiceCtx context)
{
return (ResultCode)_applet.Start(_inData, _outData);
return (ResultCode)_applet.Start(_normalSession.GetConsumer(),
_interactiveSession.GetConsumer());
}
[Command(30)]
@ -70,7 +86,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Lib
{
IStorage data = GetObject<IStorage>(context, 0);
_inData.Push(data.Data);
_normalSession.Push(data.Data);
return ResultCode.Success;
}
@ -79,10 +95,70 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Lib
// PopOutData() -> object<nn::am::service::IStorage>
public ResultCode PopOutData(ServiceCtx context)
{
byte[] data = _outData.Pop();
if(_normalSession.TryPop(out byte[] data))
{
MakeObject(context, new IStorage(data));
_normalOutDataEvent.WritableEvent.Clear();
return ResultCode.Success;
}
return ResultCode.NotAvailable;
}
[Command(103)]
// PushInteractiveInData(object<nn::am::service::IStorage>)
public ResultCode PushInteractiveInData(ServiceCtx context)
{
IStorage data = GetObject<IStorage>(context, 0);
_interactiveSession.Push(data.Data);
return ResultCode.Success;
}
[Command(104)]
// PopInteractiveOutData() -> object<nn::am::service::IStorage>
public ResultCode PopInteractiveOutData(ServiceCtx context)
{
if(_interactiveSession.TryPop(out byte[] data))
{
MakeObject(context, new IStorage(data));
_interactiveOutDataEvent.WritableEvent.Clear();
return ResultCode.Success;
}
return ResultCode.NotAvailable;
}
[Command(105)]
// GetPopOutDataEvent() -> handle<copy>
public ResultCode GetPopOutDataEvent(ServiceCtx context)
{
if (context.Process.HandleTable.GenerateHandle(_normalOutDataEvent.ReadableEvent, out int handle) != KernelResult.Success)
{
throw new InvalidOperationException("Out of handles!");
}
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
return ResultCode.Success;
}
[Command(106)]
// GetPopInteractiveOutDataEvent() -> handle<copy>
public ResultCode GetPopInteractiveOutDataEvent(ServiceCtx context)
{
if (context.Process.HandleTable.GenerateHandle(_interactiveOutDataEvent.ReadableEvent, out int handle) != KernelResult.Success)
{
throw new InvalidOperationException("Out of handles!");
}
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
MakeObject(context, new IStorage(data));
return ResultCode.Success;
}
}