diff --git a/src/xenia/apu/xma_context.cc b/src/xenia/apu/xma_context.cc index f948a46db..f800fd503 100644 --- a/src/xenia/apu/xma_context.cc +++ b/src/xenia/apu/xma_context.cc @@ -246,35 +246,41 @@ void XmaContext::DecodePackets(XMA_CONTEXT_DATA& data) { // This'll copy audio samples into the output buffer. // The samples need to be 2 bytes long! // Copies one frame at a time, so keep calling this until size == 0 - int read_bytes = 0; + int written_bytes = 0; int decode_attempts_remaining = 3; uint8_t work_buffer[kOutputMaxSizeBytes]; while (decode_attempts_remaining) { - read_bytes = DecodePacket(work_buffer, 0, output_remaining_bytes); - if (read_bytes >= 0) { - // assert_true((read_bytes % 256) == 0); - auto written_bytes = output_rb.Write(work_buffer, read_bytes); - assert_true(read_bytes == written_bytes); + size_t read_bytes = 0; + written_bytes = + DecodePacket(work_buffer, 0, output_remaining_bytes, &read_bytes); + if (written_bytes >= 0) { + // assert_true((written_bytes % 256) == 0); + auto written_bytes_rb = output_rb.Write(work_buffer, written_bytes); + assert_true(written_bytes == written_bytes_rb); // Ok. break; - } else { + } else if (read_bytes % 2048 == 0) { // Sometimes the decoder will fail on a packet. I think it's // looking for cross-packet frames and failing. If you run it again // on the same packet it'll work though. --decode_attempts_remaining; + } else { + // Failed in the middle of a packet, do not retry! + decode_attempts_remaining = 0; + break; } } if (!decode_attempts_remaining) { XELOGAPU("XmaContext: libav failed to decode packet (returned %.8X)", - -read_bytes); + -written_bytes); // Failed out. if (data.input_buffer_0_valid || data.input_buffer_1_valid) { // There's new data available - maybe we'll be ok if we decode it? - read_bytes = 0; + written_bytes = 0; DiscardPacket(); } else { // No data and hosed - bail. @@ -283,10 +289,10 @@ void XmaContext::DecodePackets(XMA_CONTEXT_DATA& data) { } data.output_buffer_write_offset = output_rb.write_offset() / 256; - output_remaining_bytes -= read_bytes; + output_remaining_bytes -= written_bytes; // If we need more data and the input buffers have it, grab it. - if (read_bytes) { + if (written_bytes) { // Haven't finished with current packet. continue; } else if (data.input_buffer_0_valid || data.input_buffer_1_valid) { @@ -417,9 +423,12 @@ void XmaContext::DiscardPacket() { } int XmaContext::DecodePacket(uint8_t* output, size_t output_offset, - size_t output_size) { + size_t output_size, size_t* read_bytes) { size_t to_copy = 0; size_t original_offset = output_offset; + if (read_bytes) { + *read_bytes = 0; + } // We're holding onto an already-decoded frame. Copy it out. if (current_frame_pos_ != frame_samples_size_) { @@ -443,6 +452,10 @@ int XmaContext::DecodePacket(uint8_t* output, size_t output_offset, return len; } + if (read_bytes) { + *read_bytes += len; + } + // Offset by decoded length packet_->size -= len; packet_->data += len; diff --git a/src/xenia/apu/xma_context.h b/src/xenia/apu/xma_context.h index 818a082f2..2f947afd1 100644 --- a/src/xenia/apu/xma_context.h +++ b/src/xenia/apu/xma_context.h @@ -171,7 +171,8 @@ class XmaContext { int sample_rate, int channels); void DiscardPacket(); - int DecodePacket(uint8_t* output, size_t offset, size_t size); + int DecodePacket(uint8_t* output, size_t offset, size_t size, + size_t* read_bytes); Memory* memory_; diff --git a/src/xenia/hid/winkey/winkey_input_driver.cc b/src/xenia/hid/winkey/winkey_input_driver.cc index a239e79a2..5ebff9373 100644 --- a/src/xenia/hid/winkey/winkey_input_driver.cc +++ b/src/xenia/hid/winkey/winkey_input_driver.cc @@ -102,6 +102,24 @@ X_RESULT WinKeyInputDriver::GetState(uint32_t user_index, } } + // Right stick + if (IS_KEY_DOWN(0x26)) { + // Up + thumb_ry += SHRT_MAX; + } + if (IS_KEY_DOWN(0x28)) { + // Down + thumb_ry += SHRT_MIN; + } + if (IS_KEY_DOWN(0x27)) { + // Right + thumb_rx += SHRT_MAX; + } + if (IS_KEY_DOWN(0x25)) { + // Left + thumb_rx += SHRT_MIN; + } + if (IS_KEY_DOWN(0x4C)) { // L buttons |= 0x4000; // XINPUT_GAMEPAD_X @@ -162,6 +180,87 @@ X_RESULT WinKeyInputDriver::GetKeystroke(uint32_t user_index, uint32_t flags, uint16_t keystroke_flags = 0; uint8_t hid_code = 0; + if (IS_KEY_TOGGLED(VK_CAPITAL)) { + // dpad toggled + if (IS_KEY_DOWN(0x41)) { + // A + virtual_key = 0x5812; // VK_PAD_DPAD_LEFT + } else if (IS_KEY_DOWN(0x44)) { + // D + virtual_key = 0x5813; // VK_PAD_DPAD_RIGHT + } else if (IS_KEY_DOWN(0x53)) { + // S + virtual_key = 0x5811; // VK_PAD_DPAD_DOWN + } else if (IS_KEY_DOWN(0x57)) { + // W + virtual_key = 0x5810; // VK_PAD_DPAD_UP + } + } else { + // left stick + if (IS_KEY_DOWN(0x57)) { + // W + virtual_key = 0x5820; // VK_PAD_LTHUMB_UP + } + if (IS_KEY_DOWN(0x53)) { + // S + virtual_key = 0x5821; // VK_PAD_LTHUMB_DOWN + } + if (IS_KEY_DOWN(0x44)) { + // D + virtual_key = 0x5822; // VK_PAD_LTHUMB_RIGHT + } + if (IS_KEY_DOWN(0x41)) { + // A + virtual_key = 0x5823; // VK_PAD_LTHUMB_LEFT + } + } + + // Right stick + if (IS_KEY_DOWN(0x26)) { + // Up + virtual_key = 0x5830; + } + if (IS_KEY_DOWN(0x28)) { + // Down + virtual_key = 0x5831; + } + if (IS_KEY_DOWN(0x27)) { + // Right + virtual_key = 0x5832; + } + if (IS_KEY_DOWN(0x25)) { + // Left + virtual_key = 0x5833; + } + + if (IS_KEY_DOWN(0x4C)) { + // L + virtual_key = 0x5802; // VK_PAD_X + } else if (IS_KEY_DOWN(VK_OEM_7)) { + // ' + virtual_key = 0x5801; // VK_PAD_B + } else if (IS_KEY_DOWN(VK_OEM_1)) { + // ; + virtual_key = 0x5800; // VK_PAD_A + } else if (IS_KEY_DOWN(0x50)) { + // P + virtual_key = 0x5803; // VK_PAD_Y + } + + if (IS_KEY_DOWN(0x58)) { + // X + virtual_key = 0x5814; // VK_PAD_START + } + if (IS_KEY_DOWN(0x5A)) { + // Z + virtual_key = 0x5815; // VK_PAD_BACK + } + + if (virtual_key != 0) { + keystroke_flags |= 0x0001; // XINPUT_KEYSTROKE_DOWN + result = X_ERROR_SUCCESS; + } + out_keystroke->virtual_key = virtual_key; out_keystroke->unicode = unicode; out_keystroke->flags = keystroke_flags; diff --git a/src/xenia/kernel/objects/xenumerator.h b/src/xenia/kernel/objects/xenumerator.h index 49c6647b0..cea1f92be 100644 --- a/src/xenia/kernel/objects/xenumerator.h +++ b/src/xenia/kernel/objects/xenumerator.h @@ -29,10 +29,14 @@ class XEnumerator : public XObject { virtual uint32_t item_count() const = 0; virtual void WriteItems(uint8_t* buffer) = 0; + virtual bool WriteItem(uint8_t* buffer) = 0; + + size_t current_item() const { return current_item_; } protected: - size_t item_capacity_; - size_t item_size_; + size_t item_capacity_ = 0; + size_t item_size_ = 0; + size_t current_item_ = 0; }; class XStaticEnumerator : public XEnumerator { @@ -58,6 +62,18 @@ class XStaticEnumerator : public XEnumerator { std::memcpy(buffer, buffer_.data(), item_count_ * item_size_); } + bool WriteItem(uint8_t* buffer) { + if (current_item_ >= item_count_) { + return false; + } + + std::memcpy(buffer, buffer_.data() + current_item_ * item_size_, + item_size_); + current_item_++; + + return true; + } + private: uint32_t item_count_; std::vector buffer_; diff --git a/src/xenia/kernel/util/shim_utils.h b/src/xenia/kernel/util/shim_utils.h index 2a1411bf1..20277199e 100644 --- a/src/xenia/kernel/util/shim_utils.h +++ b/src/xenia/kernel/util/shim_utils.h @@ -231,7 +231,7 @@ class StringPointerParam : public ParamBase { uintptr_t host_address() const { return reinterpret_cast(host_ptr_); } - STR value() const { return STR(host_ptr_); } + STR value() const { return xe::load_and_swap(host_ptr_); } operator CHAR*() const { return host_ptr_; } operator bool() const { return host_ptr_ != nullptr; } diff --git a/src/xenia/kernel/xam_content.cc b/src/xenia/kernel/xam_content.cc index bec942911..b540a3649 100644 --- a/src/xenia/kernel/xam_content.cc +++ b/src/xenia/kernel/xam_content.cc @@ -25,7 +25,11 @@ struct DeviceInfo { std::wstring name; }; static const DeviceInfo dummy_device_info_ = { - 0xF00D0000, 1, 1024 * 1024 * 1024, 1024 * 1024 * 1024, L"Dummy HDD", + 0xF00D0000, + 1, + 1024ull * 1024ull * 1024ull * 1024ull, // 1TB + 1024ull * 1024ull * 1024ull * 1024ull, // 1TB + L"Dummy HDD", }; SHIM_CALL XamContentGetLicenseMask_shim(PPCContext* ppc_context, @@ -48,40 +52,6 @@ SHIM_CALL XamContentGetLicenseMask_shim(PPCContext* ppc_context, } } -SHIM_CALL XamShowDeviceSelectorUI_shim(PPCContext* ppc_context, - KernelState* kernel_state) { - uint32_t user_index = SHIM_GET_ARG_32(0); - uint32_t content_type = SHIM_GET_ARG_32(1); - uint32_t content_flags = SHIM_GET_ARG_32(2); - uint64_t total_requested = SHIM_GET_ARG_64(3); - uint32_t device_id_ptr = SHIM_GET_ARG_32(4); - uint32_t overlapped_ptr = SHIM_GET_ARG_32(5); - - XELOGD("XamShowDeviceSelectorUI(%d, %.8X, %.8X, %.8X, %.8X, %.8X)", - user_index, content_type, content_flags, total_requested, - device_id_ptr, overlapped_ptr); - - switch (content_type) { - case 1: // save game - SHIM_SET_MEM_32(device_id_ptr, dummy_device_info_.device_id | 0x0001); - break; - case 2: // marketplace - SHIM_SET_MEM_32(device_id_ptr, dummy_device_info_.device_id | 0x0002); - break; - case 3: // title/publisher update? - SHIM_SET_MEM_32(device_id_ptr, dummy_device_info_.device_id | 0x0003); - break; - } - - X_RESULT result = X_ERROR_SUCCESS; - if (overlapped_ptr) { - kernel_state->CompleteOverlappedImmediate(overlapped_ptr, result); - SHIM_SET_RETURN_32(X_ERROR_IO_PENDING); - } else { - SHIM_SET_RETURN_32(result); - } -} - SHIM_CALL XamContentGetDeviceName_shim(PPCContext* ppc_context, KernelState* kernel_state) { uint32_t device_id = SHIM_GET_ARG_32(0); @@ -149,7 +119,7 @@ SHIM_CALL XamContentGetDeviceData_shim(PPCContext* ppc_context, const auto& device_info = dummy_device_info_; SHIM_SET_MEM_32(device_data_ptr + 0, device_info.device_id); - SHIM_SET_MEM_32(device_data_ptr + 4, device_info.device_type); + SHIM_SET_MEM_32(device_data_ptr + 4, device_id & 0xFFFF); // Fake it. SHIM_SET_MEM_64(device_data_ptr + 8, device_info.total_bytes); SHIM_SET_MEM_64(device_data_ptr + 16, device_info.free_bytes); xe::store_and_swap(SHIM_MEM_ADDR(device_data_ptr + 24), @@ -183,54 +153,49 @@ SHIM_CALL XamContentResolve_shim(PPCContext* ppc_context, } // http://gameservice.googlecode.com/svn-history/r14/trunk/ContentManager.cpp -SHIM_CALL XamContentCreateEnumerator_shim(PPCContext* ppc_context, - KernelState* kernel_state) { - uint32_t user_index = SHIM_GET_ARG_32(0); - uint32_t device_id = SHIM_GET_ARG_32(1); - uint32_t content_type = SHIM_GET_ARG_32(2); - uint32_t content_flags = SHIM_GET_ARG_32(3); - uint32_t item_count = SHIM_GET_ARG_32(4); - uint32_t buffer_size_ptr = SHIM_GET_ARG_32(5); - uint32_t handle_ptr = SHIM_GET_ARG_32(6); +// https://github.com/LestaD/SourceEngine2007/blob/master/se2007/engine/xboxsystem.cpp#L499 +dword_result_t XamContentCreateEnumerator(dword_t user_index, dword_t device_id, + dword_t content_type, + dword_t content_flags, + dword_t max_count, + lpdword_t buffer_size_ptr, + lpdword_t handle_out) { + assert_not_null(handle_out); + if ((device_id && (device_id & 0xFFFF0000) != dummy_device_info_.device_id) || + !handle_out) { + if (buffer_size_ptr) { + *buffer_size_ptr = 0; + } - XELOGD("XamContentCreateEnumerator(%d, %.8X, %.8X, %.8X, %.8X, %.8X, %.8X)", - user_index, device_id, content_type, content_flags, item_count, - buffer_size_ptr, handle_ptr); - - if (device_id && (device_id & 0xFFFF0000) != dummy_device_info_.device_id) { // TODO(benvanik): memset 0 the data? - SHIM_SET_RETURN_32(X_E_INVALIDARG); - return; - } - if (!device_id) { - // 0 == whatever - device_id = dummy_device_info_.device_id; + return X_E_INVALIDARG; } if (buffer_size_ptr) { - SHIM_SET_MEM_32(buffer_size_ptr, item_count * XCONTENT_DATA::kSize); + *buffer_size_ptr = (uint32_t)XCONTENT_DATA::kSize; } auto e = - new XStaticEnumerator(kernel_state, item_count, XCONTENT_DATA::kSize); + new XStaticEnumerator(kernel_state(), max_count, XCONTENT_DATA::kSize); e->Initialize(); // Get all content data. - auto content_datas = - kernel_state->content_manager()->ListContent(device_id, content_type); + auto content_datas = kernel_state()->content_manager()->ListContent( + device_id ? device_id : dummy_device_info_.device_id, content_type); for (auto& content_data : content_datas) { auto ptr = e->AppendItem(); if (!ptr) { // Too many items. break; } + content_data.Write(ptr); } - SHIM_SET_MEM_32(handle_ptr, e->handle()); - - SHIM_SET_RETURN_32(X_ERROR_SUCCESS); + *handle_out = e->handle(); + return X_ERROR_SUCCESS; } +DECLARE_XAM_EXPORT(XamContentCreateEnumerator, ExportTag::kImplemented); void XamContentCreateCore(PPCContext* ppc_context, KernelState* kernel_state, uint32_t user_index, std::string root_name, @@ -542,12 +507,10 @@ SHIM_CALL XamContentDelete_shim(PPCContext* ppc_context, void xe::kernel::xam::RegisterContentExports( xe::cpu::ExportResolver* export_resolver, KernelState* kernel_state) { SHIM_SET_MAPPING("xam.xex", XamContentGetLicenseMask, state); - SHIM_SET_MAPPING("xam.xex", XamShowDeviceSelectorUI, state); SHIM_SET_MAPPING("xam.xex", XamContentGetDeviceName, state); SHIM_SET_MAPPING("xam.xex", XamContentGetDeviceState, state); SHIM_SET_MAPPING("xam.xex", XamContentGetDeviceData, state); SHIM_SET_MAPPING("xam.xex", XamContentResolve, state); - SHIM_SET_MAPPING("xam.xex", XamContentCreateEnumerator, state); SHIM_SET_MAPPING("xam.xex", XamContentCreate, state); SHIM_SET_MAPPING("xam.xex", XamContentCreateEx, state); SHIM_SET_MAPPING("xam.xex", XamContentFlush, state); diff --git a/src/xenia/kernel/xam_info.cc b/src/xenia/kernel/xam_info.cc index ee095bb5a..e362986d9 100644 --- a/src/xenia/kernel/xam_info.cc +++ b/src/xenia/kernel/xam_info.cc @@ -198,51 +198,44 @@ SHIM_CALL XamFree_shim(PPCContext* ppc_context, KernelState* kernel_state) { SHIM_SET_RETURN_32(X_ERROR_SUCCESS); } -SHIM_CALL XamEnumerate_shim(PPCContext* ppc_context, - KernelState* kernel_state) { - uint32_t handle = SHIM_GET_ARG_32(0); - uint32_t zero = SHIM_GET_ARG_32(1); - uint32_t buffer_ptr = SHIM_GET_ARG_32(2); - uint32_t buffer_length = SHIM_GET_ARG_32(3); - uint32_t item_count_ptr = SHIM_GET_ARG_32(4); - uint32_t overlapped_ptr = SHIM_GET_ARG_32(5); +// https://github.com/LestaD/SourceEngine2007/blob/master/se2007/engine/xboxsystem.cpp#L518 +dword_result_t XamEnumerate(dword_t handle, dword_t flags, lpvoid_t buffer, + dword_t buffer_length, lpdword_t items_returned, + pointer_t overlapped) { + assert_true(flags == 0); - assert_true(zero == 0); - - XELOGD("XamEnumerate(%.8X, %d, %.8X, %d, %.8X, %.8X)", handle, zero, - buffer_ptr, buffer_length, item_count_ptr, overlapped_ptr); - - auto e = kernel_state->object_table()->LookupObject(handle); + auto e = kernel_state()->object_table()->LookupObject(handle); if (!e) { - if (overlapped_ptr) { - kernel_state->CompleteOverlappedImmediateEx( - overlapped_ptr, X_ERROR_INVALID_HANDLE, X_ERROR_INVALID_HANDLE, 0); - SHIM_SET_RETURN_32(X_ERROR_IO_PENDING); + if (overlapped) { + kernel_state()->CompleteOverlappedImmediateEx( + overlapped, X_ERROR_INVALID_HANDLE, X_ERROR_INVALID_HANDLE, 0); + return X_ERROR_IO_PENDING; } else { - SHIM_SET_RETURN_32(X_ERROR_INVALID_HANDLE); + return X_ERROR_INVALID_HANDLE; } - return; } - auto item_count = e->item_count(); - e->WriteItems(SHIM_MEM_ADDR(buffer_ptr)); + buffer.Zero(buffer_length); + X_RESULT result = + e->WriteItem(buffer) ? X_ERROR_SUCCESS : X_ERROR_NO_MORE_FILES; + if (items_returned) { + assert_true(!overlapped); + *items_returned = result == X_ERROR_SUCCESS ? 1 : 0; - X_RESULT result = item_count ? X_ERROR_SUCCESS : X_ERROR_NO_MORE_FILES; - if (item_count_ptr) { - assert_zero(overlapped_ptr); - SHIM_SET_MEM_32(item_count_ptr, item_count); - } else if (overlapped_ptr) { - assert_zero(item_count_ptr); - kernel_state->CompleteOverlappedImmediateEx(overlapped_ptr, result, result, - item_count); - result = X_ERROR_IO_PENDING; + return result; + } else if (overlapped) { + assert_true(!items_returned); + kernel_state()->CompleteOverlappedImmediateEx( + overlapped, result, result, + result == X_ERROR_SUCCESS ? e->item_count() : 0); + + return X_ERROR_IO_PENDING; } else { assert_always(); - result = X_ERROR_INVALID_PARAMETER; + return X_ERROR_INVALID_PARAMETER; } - - SHIM_SET_RETURN_32(result); } +DECLARE_XAM_EXPORT(XamEnumerate, ExportTag::kImplemented); } // namespace kernel } // namespace xe @@ -258,6 +251,4 @@ void xe::kernel::xam::RegisterInfoExports( SHIM_SET_MAPPING("xam.xex", XamAlloc, state); SHIM_SET_MAPPING("xam.xex", XamFree, state); - - SHIM_SET_MAPPING("xam.xex", XamEnumerate, state); } diff --git a/src/xenia/kernel/xam_ui.cc b/src/xenia/kernel/xam_ui.cc index 654d75019..b9905e693 100644 --- a/src/xenia/kernel/xam_ui.cc +++ b/src/xenia/kernel/xam_ui.cc @@ -79,7 +79,9 @@ class MessageBoxWindow : public el::ModalWindow { } bool OnEvent(const el::Event& ev) override { - if (ev.target->IsOfType() && ev.type == el::EventType::kClick) { + if (ev.target->IsOfType() && + (ev.type == el::EventType::kClick || + ev.special_key == el::SpecialKey::kEnter)) { int data_value = ev.target->data.as_integer(); if (data_value) { *out_chosen_button_ = data_value - 100; @@ -166,6 +168,179 @@ SHIM_CALL XamShowMessageBoxUI_shim(PPCContext* ppc_context, SHIM_SET_RETURN_32(X_ERROR_IO_PENDING); } +class KeyboardInputWindow : public el::ModalWindow { + public: + KeyboardInputWindow(xe::threading::Fence* fence) + : ModalWindow([fence]() { fence->Signal(); }) {} + ~KeyboardInputWindow() override = default; + + // TODO(benvanik): icon. + void Show(el::Element* root_element, std::wstring title, + std::wstring description, std::wstring default_text, + std::wstring* out_text, size_t max_length) { + title_ = std::move(title); + description_ = std::move(description); + default_text_ = std::move(default_text); + out_text_ = out_text; + max_length_ = max_length; + + // Incase we're cancelled, set as the default text. + if (out_text) { + *out_text = default_text; + } + + ModalWindow::Show(root_element); + + EnsureFocus(); + } + + protected: + void BuildUI() override { + using namespace el::dsl; + + set_text(xe::to_string(title_)); + + LoadNodeTree( + LayoutBoxNode() + .axis(Axis::kY) + .gravity(Gravity::kAll) + .position(LayoutPosition::kLeftTop) + .min_width(300) + .distribution(LayoutDistribution::kAvailable) + .distribution_position(LayoutDistributionPosition::kLeftTop) + .child(LabelNode(xe::to_string(description_).c_str())) + .child(LayoutBoxNode() + .axis(Axis::kX) + .distribution(LayoutDistribution::kGravity) + .child(TextBoxNode() + .id("text_input") + .gravity(Gravity::kLeftRight) + .placeholder(xe::to_string(default_text_)) + .min_width(150) + .autofocus(true))) + .child(LayoutBoxNode() + .distribution_position( + LayoutDistributionPosition::kRightBottom) + .child(ButtonNode("OK").id("ok_button")) + .child(ButtonNode("Cancel").id("cancel_button")))); + } + + bool OnEvent(const el::Event& ev) override { + if (ev.special_key == el::SpecialKey::kEnter || + (ev.target->id() == TBIDC("ok_button") && + ev.type == el::EventType::kClick)) { + // Pressed enter or clicked OK + // Grab the text. + if (out_text_) { + *out_text_ = + xe::to_wstring(GetElementById("text_input")->text()); + } + + Die(); + return true; + } else if (ev.target->id() == TBIDC("cancel_button") && + ev.type == el::EventType::kClick) { + // Cancel. + Die(); + return true; + } + + return ModalWindow::OnEvent(ev); + } + + std::wstring title_; + std::wstring description_; + std::wstring default_text_; + std::wstring* out_text_ = nullptr; + size_t max_length_ = 0; +}; + +// http://www.se7ensins.com/forums/threads/release-how-to-use-xshowkeyboardui-release.906568/ +dword_result_t XamShowKeyboardUI(dword_t r3, dword_t flags, + lpwstring_t default_text, lpwstring_t title, + lpwstring_t description, lpwstring_t buffer, + dword_t buffer_length, + pointer_t overlapped) { + // Unknown parameters. I've only seen zero. + assert_zero(r3); + assert_zero(flags); + + if (!buffer) { + return X_ERROR_INVALID_PARAMETER; + } + + if (FLAGS_headless) { + // Redirect default_text back into the buffer. + std::memset(buffer, 0, buffer_length * 2); + if (default_text) { + xe::store_and_swap(buffer, default_text.value()); + } + + if (overlapped) { + kernel_state()->CompleteOverlappedImmediate(overlapped, X_ERROR_SUCCESS); + return X_ERROR_IO_PENDING; + } else { + return X_ERROR_SUCCESS; + } + } + + std::wstring out_text; + + auto display_window = kernel_state()->emulator()->display_window(); + xe::threading::Fence fence; + display_window->loop()->PostSynchronous([&]() { + auto root_element = display_window->root_element(); + auto window = new KeyboardInputWindow(&fence); + window->Show(root_element, title ? title.value() : L"", + description ? description.value() : L"", + default_text ? default_text.value() : L"", &out_text, + buffer_length); + }); + fence.Wait(); + + // Zero the output buffer. + std::memset(buffer, 0, buffer_length * 2); + + // Truncate the string. + out_text = out_text.substr(0, buffer_length - 1); + xe::store_and_swap(buffer, out_text); + + if (overlapped) { + kernel_state()->CompleteOverlappedImmediate(overlapped, X_ERROR_SUCCESS); + return X_ERROR_IO_PENDING; + } else { + return X_ERROR_SUCCESS; + } +} +DECLARE_XAM_EXPORT(XamShowKeyboardUI, ExportTag::kImplemented); + +dword_result_t XamShowDeviceSelectorUI(dword_t user_index, dword_t content_type, + dword_t content_flags, + qword_t total_requested, + lpdword_t device_id_ptr, + pointer_t overlapped) { + // NOTE: 0xF00D0000 magic from xam_content.cc + switch (content_type) { + case 1: // save game + *device_id_ptr = 0xF00D0000 | 0x0001; + break; + case 2: // marketplace + *device_id_ptr = 0xF00D0000 | 0x0002; + break; + case 3: // title/publisher update? + *device_id_ptr = 0xF00D0000 | 0x0003; + break; + } + + if (overlapped) { + kernel_state()->CompleteOverlappedImmediate(overlapped, X_ERROR_SUCCESS); + return X_ERROR_IO_PENDING; + } else { + return X_ERROR_SUCCESS; + } +} +DECLARE_XAM_EXPORT(XamShowDeviceSelectorUI, ExportTag::kImplemented); + class DirtyDiscWindow : public el::ModalWindow { public: DirtyDiscWindow(xe::threading::Fence* fence) diff --git a/src/xenia/kernel/xobject.cc b/src/xenia/kernel/xobject.cc index 5338e4359..b6c8df7ac 100644 --- a/src/xenia/kernel/xobject.cc +++ b/src/xenia/kernel/xobject.cc @@ -40,8 +40,8 @@ XObject::~XObject() { auto header = memory()->TranslateVirtual(ptr); // Free the object creation info - if (header->object_create_info) { - memory()->SystemHeapFree(header->object_create_info); + if (header->object_type_ptr) { + memory()->SystemHeapFree(header->object_type_ptr); } memory()->SystemHeapFree(ptr); @@ -241,15 +241,13 @@ uint8_t* XObject::CreateNative(uint32_t size) { auto header = memory()->TranslateVirtual(mem); - auto creation_info = - memory()->SystemHeapAlloc(sizeof(X_OBJECT_CREATE_INFORMATION)); - if (creation_info) { - memory()->Zero(creation_info, sizeof(X_OBJECT_CREATE_INFORMATION)); - + auto object_type = + memory()->SystemHeapAlloc(sizeof(X_OBJECT_TYPE)); + if (object_type) { // Set it up in the header. - // Some kernel method is accessing this struct and dereferencing a member. - // With our current definition that member is non_paged_pool_charge. - header->object_create_info = creation_info; + // Some kernel method is accessing this struct and dereferencing a member + // @ offset 0x14 + header->object_type_ptr = object_type; } return memory()->TranslateVirtual(guest_object_ptr_); diff --git a/src/xenia/kernel/xobject.h b/src/xenia/kernel/xobject.h index 70bdc4e4c..7b54ed030 100644 --- a/src/xenia/kernel/xobject.h +++ b/src/xenia/kernel/xobject.h @@ -63,7 +63,6 @@ struct X_OBJECT_HEADER { xe::be handle_count; xe::be next_to_free; }; - xe::be object_type_ptr; uint8_t name_info_offset; uint8_t handle_info_offset; uint8_t quota_info_offset; @@ -72,7 +71,8 @@ struct X_OBJECT_HEADER { xe::be object_create_info; // X_OBJECT_CREATE_INFORMATION xe::be quota_block_charged; }; - xe::be security_descriptor; + xe::be object_type_ptr; // -0x8 POBJECT_TYPE + xe::be unk_04; // -0x4 // Object lives after this header. // (There's actually a body field here which is the object itself) @@ -80,19 +80,29 @@ struct X_OBJECT_HEADER { // http://www.nirsoft.net/kernel_struct/vista/OBJECT_CREATE_INFORMATION.html struct X_OBJECT_CREATE_INFORMATION { - xe::be attributes; - xe::be root_directory_ptr; - xe::be parse_context_ptr; - xe::be probe_mode; - xe::be paged_pool_charge; - xe::be non_paged_pool_charge; - xe::be security_descriptor_charge; - xe::be security_descriptor; - xe::be security_qos_ptr; + xe::be attributes; // 0x0 + xe::be root_directory_ptr; // 0x4 + xe::be parse_context_ptr; // 0x8 + xe::be probe_mode; // 0xC + xe::be paged_pool_charge; // 0x10 + xe::be non_paged_pool_charge; // 0x14 + xe::be security_descriptor_charge; // 0x18 + xe::be security_descriptor; // 0x1C + xe::be security_qos_ptr; // 0x20 // Security QoS here (SECURITY_QUALITY_OF_SERVICE) too! }; +struct X_OBJECT_TYPE { + xe::be constructor; // 0x0 + xe::be destructor; // 0x4 + xe::be unk_08; // 0x8 + xe::be unk_0C; // 0xC + xe::be unk_10; // 0x10 + xe::be unk_14; // 0x14 probably offset from ntobject to keobject + xe::be pool_tag; // 0x18 +}; + class XObject { public: enum Type { diff --git a/src/xenia/xbox.h b/src/xenia/xbox.h index 8a4990fa4..668be2e5e 100644 --- a/src/xenia/xbox.h +++ b/src/xenia/xbox.h @@ -191,6 +191,17 @@ enum X_FILE_INFORMATION_CLASS { XFileMaximumInformation }; +// Known as XOVERLAPPED to 360 code. +struct XAM_OVERLAPPED { + xe::be result; // 0x0 + xe::be length; // 0x4 + xe::be context; // 0x8 + xe::be event; // 0xC + xe::be completion_routine; // 0x10 + xe::be completion_context; // 0x14 + xe::be extended_error; // 0x18 +}; + inline uint32_t XOverlappedGetResult(void* ptr) { auto p = reinterpret_cast(ptr); return xe::load_and_swap(&p[0]);