commit
297f5fdcd3
|
@ -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;
|
||||
|
|
|
@ -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_;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<uint8_t> buffer_;
|
||||
|
|
|
@ -231,7 +231,7 @@ class StringPointerParam : public ParamBase<uint32_t> {
|
|||
uintptr_t host_address() const {
|
||||
return reinterpret_cast<uintptr_t>(host_ptr_);
|
||||
}
|
||||
STR value() const { return STR(host_ptr_); }
|
||||
STR value() const { return xe::load_and_swap<STR>(host_ptr_); }
|
||||
operator CHAR*() const { return host_ptr_; }
|
||||
operator bool() const { return host_ptr_ != nullptr; }
|
||||
|
||||
|
|
|
@ -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<std::wstring>(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);
|
||||
|
|
|
@ -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<XAM_OVERLAPPED> 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<XEnumerator>(handle);
|
||||
auto e = kernel_state()->object_table()->LookupObject<XEnumerator>(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);
|
||||
}
|
||||
|
|
|
@ -79,7 +79,9 @@ class MessageBoxWindow : public el::ModalWindow {
|
|||
}
|
||||
|
||||
bool OnEvent(const el::Event& ev) override {
|
||||
if (ev.target->IsOfType<el::Button>() && ev.type == el::EventType::kClick) {
|
||||
if (ev.target->IsOfType<el::Button>() &&
|
||||
(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<el::TextBox>("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<XAM_OVERLAPPED> 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<std::wstring>(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<std::wstring>(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<XAM_OVERLAPPED> 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)
|
||||
|
|
|
@ -40,8 +40,8 @@ XObject::~XObject() {
|
|||
auto header = memory()->TranslateVirtual<X_OBJECT_HEADER*>(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<X_OBJECT_HEADER*>(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_);
|
||||
|
|
|
@ -63,7 +63,6 @@ struct X_OBJECT_HEADER {
|
|||
xe::be<uint32_t> handle_count;
|
||||
xe::be<uint32_t> next_to_free;
|
||||
};
|
||||
xe::be<uint32_t> 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<uint32_t> object_create_info; // X_OBJECT_CREATE_INFORMATION
|
||||
xe::be<uint32_t> quota_block_charged;
|
||||
};
|
||||
xe::be<uint32_t> security_descriptor;
|
||||
xe::be<uint32_t> object_type_ptr; // -0x8 POBJECT_TYPE
|
||||
xe::be<uint32_t> 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<uint32_t> attributes;
|
||||
xe::be<uint32_t> root_directory_ptr;
|
||||
xe::be<uint32_t> parse_context_ptr;
|
||||
xe::be<uint32_t> probe_mode;
|
||||
xe::be<uint32_t> paged_pool_charge;
|
||||
xe::be<uint32_t> non_paged_pool_charge;
|
||||
xe::be<uint32_t> security_descriptor_charge;
|
||||
xe::be<uint32_t> security_descriptor;
|
||||
xe::be<uint32_t> security_qos_ptr;
|
||||
xe::be<uint32_t> attributes; // 0x0
|
||||
xe::be<uint32_t> root_directory_ptr; // 0x4
|
||||
xe::be<uint32_t> parse_context_ptr; // 0x8
|
||||
xe::be<uint32_t> probe_mode; // 0xC
|
||||
xe::be<uint32_t> paged_pool_charge; // 0x10
|
||||
xe::be<uint32_t> non_paged_pool_charge; // 0x14
|
||||
xe::be<uint32_t> security_descriptor_charge; // 0x18
|
||||
xe::be<uint32_t> security_descriptor; // 0x1C
|
||||
xe::be<uint32_t> security_qos_ptr; // 0x20
|
||||
|
||||
// Security QoS here (SECURITY_QUALITY_OF_SERVICE) too!
|
||||
};
|
||||
|
||||
struct X_OBJECT_TYPE {
|
||||
xe::be<uint32_t> constructor; // 0x0
|
||||
xe::be<uint32_t> destructor; // 0x4
|
||||
xe::be<uint32_t> unk_08; // 0x8
|
||||
xe::be<uint32_t> unk_0C; // 0xC
|
||||
xe::be<uint32_t> unk_10; // 0x10
|
||||
xe::be<uint32_t> unk_14; // 0x14 probably offset from ntobject to keobject
|
||||
xe::be<uint32_t> pool_tag; // 0x18
|
||||
};
|
||||
|
||||
class XObject {
|
||||
public:
|
||||
enum Type {
|
||||
|
|
|
@ -191,6 +191,17 @@ enum X_FILE_INFORMATION_CLASS {
|
|||
XFileMaximumInformation
|
||||
};
|
||||
|
||||
// Known as XOVERLAPPED to 360 code.
|
||||
struct XAM_OVERLAPPED {
|
||||
xe::be<uint32_t> result; // 0x0
|
||||
xe::be<uint32_t> length; // 0x4
|
||||
xe::be<uint32_t> context; // 0x8
|
||||
xe::be<uint32_t> event; // 0xC
|
||||
xe::be<uint32_t> completion_routine; // 0x10
|
||||
xe::be<uint32_t> completion_context; // 0x14
|
||||
xe::be<uint32_t> extended_error; // 0x18
|
||||
};
|
||||
|
||||
inline uint32_t XOverlappedGetResult(void* ptr) {
|
||||
auto p = reinterpret_cast<uint32_t*>(ptr);
|
||||
return xe::load_and_swap<uint32_t>(&p[0]);
|
||||
|
|
Loading…
Reference in New Issue