mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-21 05:09:34 -06:00
Clean up "ControllerInterface" a bit.
git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@7339 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
@ -233,15 +233,15 @@ Joystick::Joystick( /*const LPCDIDEVICEINSTANCE lpddi, */const LPDIRECTINPUTDEVI
|
||||
//m_must_poll = (js_caps.dwFlags & DIDC_POLLEDDATAFORMAT) != 0;
|
||||
|
||||
// buttons
|
||||
for ( unsigned int i = 0; i < js_caps.dwButtons; ++i )
|
||||
AddInput( new Button( i ) );
|
||||
for (u8 i = 0; i != js_caps.dwButtons; ++i)
|
||||
AddInput(new Button(i, m_state_in.rgbButtons[m_index]));
|
||||
|
||||
// hats
|
||||
for ( unsigned int i = 0; i < js_caps.dwPOVs; ++i )
|
||||
for (u8 i = 0; i != js_caps.dwPOVs; ++i)
|
||||
{
|
||||
// each hat gets 4 input instances associated with it, (up down left right)
|
||||
for ( unsigned int d = 0; d<4; ++d )
|
||||
AddInput( new Hat( i, d ) );
|
||||
for (u8 d = 0; d != 4; ++d)
|
||||
AddInput(new Hat(i, m_state_in.rgdwPOV[m_index], d));
|
||||
}
|
||||
|
||||
// get up to 6 axes and 2 sliders
|
||||
@ -264,9 +264,11 @@ Joystick::Joystick( /*const LPCDIDEVICEINSTANCE lpddi, */const LPDIRECTINPUTDEVI
|
||||
if (SUCCEEDED(m_device->GetProperty(DIPROP_RANGE, &range.diph)))
|
||||
{
|
||||
const LONG base = (range.lMin + range.lMax) / 2;
|
||||
const LONG& ax = (&m_state_in.lX)[m_index];
|
||||
|
||||
// each axis gets a negative and a positive input instance associated with it
|
||||
AddInput(new Axis(offset, base, range.lMin-base));
|
||||
AddInput(new Axis(offset, base, range.lMax-base));
|
||||
AddInput(new Axis(offset, ax, base, range.lMin-base));
|
||||
AddInput(new Axis(offset, ax, base, range.lMax-base));
|
||||
}
|
||||
}
|
||||
|
||||
@ -319,11 +321,11 @@ Joystick::Joystick( /*const LPCDIDEVICEINSTANCE lpddi, */const LPDIRECTINPUTDEVI
|
||||
{
|
||||
// ugly if ladder again :/
|
||||
if (0 == f)
|
||||
AddOutput(new ForceConstant(i, f));
|
||||
AddOutput(new ForceConstant(f, m_state_out[i]));
|
||||
else if (1 == f)
|
||||
AddOutput(new ForceRamp(i, f));
|
||||
AddOutput(new ForceRamp(f, m_state_out[i]));
|
||||
else
|
||||
AddOutput(new ForcePeriodic(i, f));
|
||||
AddOutput(new ForcePeriodic(f, m_state_out[i]));
|
||||
|
||||
++i;
|
||||
m_state_out.push_back(EffectState(pEffect));
|
||||
@ -501,44 +503,31 @@ std::string Joystick::Hat::GetName() const
|
||||
template <typename P>
|
||||
std::string Joystick::Force<P>::GetName() const
|
||||
{
|
||||
return force_type_names[m_type].name;
|
||||
return force_type_names[m_index].name;
|
||||
}
|
||||
|
||||
// get / set state
|
||||
|
||||
ControlState Joystick::GetInputState( const ControllerInterface::Device::Input* const input ) const
|
||||
ControlState Joystick::Axis::GetState() const
|
||||
{
|
||||
return ((Input*)input)->GetState( &m_state_in );
|
||||
return std::max(0.0f, ControlState(m_axis - m_base) / m_range);
|
||||
}
|
||||
|
||||
void Joystick::SetOutputState( const ControllerInterface::Device::Output* const output, const ControlState state )
|
||||
ControlState Joystick::Button::GetState() const
|
||||
{
|
||||
((Output*)output)->SetState( state, &m_state_out[0] );
|
||||
return ControlState(m_button > 0);
|
||||
}
|
||||
|
||||
// get / set state
|
||||
|
||||
ControlState Joystick::Axis::GetState( const DIJOYSTATE* const joystate ) const
|
||||
{
|
||||
return std::max( 0.0f, ControlState((&joystate->lX)[m_index]-m_base) / m_range );
|
||||
}
|
||||
|
||||
ControlState Joystick::Button::GetState( const DIJOYSTATE* const joystate ) const
|
||||
{
|
||||
return ControlState( joystate->rgbButtons[m_index] > 0 );
|
||||
}
|
||||
|
||||
ControlState Joystick::Hat::GetState( const DIJOYSTATE* const joystate ) const
|
||||
ControlState Joystick::Hat::GetState() const
|
||||
{
|
||||
// can this func be simplified ?
|
||||
const DWORD val = joystate->rgdwPOV[m_index];
|
||||
// hat centered code from msdn
|
||||
if ( 0xFFFF == LOWORD(val) )
|
||||
if (0xFFFF == LOWORD(m_hat))
|
||||
return 0;
|
||||
return ( abs( (int)(val/4500-m_direction*2+8)%8 - 4) > 2 );
|
||||
return (abs((int)(m_hat / 4500 - m_direction * 2 + 8) % 8 - 4) > 2);
|
||||
}
|
||||
|
||||
void Joystick::ForceConstant::SetState(const ControlState state, Joystick::EffectState* const joystate)
|
||||
void Joystick::ForceConstant::SetState(const ControlState state)
|
||||
{
|
||||
const LONG new_val = LONG(10000 * state);
|
||||
|
||||
@ -546,28 +535,28 @@ void Joystick::ForceConstant::SetState(const ControlState state, Joystick::Effec
|
||||
if (val != new_val)
|
||||
{
|
||||
val = new_val;
|
||||
joystate[m_index].params = ¶ms; // tells UpdateOutput the state has changed
|
||||
m_state.params = ¶ms; // tells UpdateOutput the state has changed
|
||||
|
||||
// tells UpdateOutput to either start or stop the force
|
||||
joystate[m_index].size = new_val ? sizeof(params) : 0;
|
||||
m_state.size = new_val ? sizeof(params) : 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Joystick::ForceRamp::SetState(const ControlState state, Joystick::EffectState* const joystate)
|
||||
void Joystick::ForceRamp::SetState(const ControlState state)
|
||||
{
|
||||
const LONG new_val = LONG(10000 * state);
|
||||
|
||||
if (params.lStart != new_val)
|
||||
{
|
||||
params.lStart = params.lEnd = new_val;
|
||||
joystate[m_index].params = ¶ms; // tells UpdateOutput the state has changed
|
||||
m_state.params = ¶ms; // tells UpdateOutput the state has changed
|
||||
|
||||
// tells UpdateOutput to either start or stop the force
|
||||
joystate[m_index].size = new_val ? sizeof(params) : 0;
|
||||
m_state.size = new_val ? sizeof(params) : 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Joystick::ForcePeriodic::SetState(const ControlState state, Joystick::EffectState* const joystate)
|
||||
void Joystick::ForcePeriodic::SetState(const ControlState state)
|
||||
{
|
||||
const LONG new_val = LONG(10000 * state);
|
||||
|
||||
@ -577,16 +566,16 @@ void Joystick::ForcePeriodic::SetState(const ControlState state, Joystick::Effec
|
||||
val = new_val;
|
||||
//params.dwPeriod = 0;//DWORD(0.05 * DI_SECONDS); // zero is working fine for me
|
||||
|
||||
joystate[m_index].params = ¶ms; // tells UpdateOutput the state has changed
|
||||
m_state.params = ¶ms; // tells UpdateOutput the state has changed
|
||||
|
||||
// tells UpdateOutput to either start or stop the force
|
||||
joystate[m_index].size = new_val ? sizeof(params) : 0;
|
||||
m_state.size = new_val ? sizeof(params) : 0;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename P>
|
||||
Joystick::Force<P>::Force(const unsigned int index, const unsigned int type)
|
||||
: m_index(index), m_type(type)
|
||||
Joystick::Force<P>::Force(u8 index, EffectState& state)
|
||||
: m_index(index), m_state(state)
|
||||
{
|
||||
ZeroMemory(¶ms, sizeof(params));
|
||||
}
|
||||
|
@ -25,11 +25,7 @@ void InitJoystick(IDirectInput8* const idi8, std::vector<ControllerInterface::De
|
||||
|
||||
class Joystick : public ControllerInterface::Device
|
||||
{
|
||||
friend class ControllerInterface;
|
||||
friend class ControllerInterface::ControlReference;
|
||||
|
||||
protected:
|
||||
|
||||
private:
|
||||
struct EffectState
|
||||
{
|
||||
EffectState(LPDIRECTINPUTEFFECT eff) : iface(eff), params(NULL), size(0) {}
|
||||
@ -39,88 +35,63 @@ protected:
|
||||
u8 size; // zero when force should stop
|
||||
};
|
||||
|
||||
class Input : public ControllerInterface::Device::Input
|
||||
{
|
||||
friend class Joystick;
|
||||
protected:
|
||||
virtual ControlState GetState( const DIJOYSTATE* const joystate ) const = 0;
|
||||
};
|
||||
|
||||
// can probably eliminate this base class
|
||||
class Output : public ControllerInterface::Device::Output
|
||||
{
|
||||
friend class Joystick;
|
||||
protected:
|
||||
virtual void SetState( const ControlState state, EffectState* const joystate ) = 0;
|
||||
};
|
||||
|
||||
class Button : public Input
|
||||
{
|
||||
friend class Joystick;
|
||||
public:
|
||||
std::string GetName() const;
|
||||
protected:
|
||||
Button( const unsigned int index ) : m_index(index) {}
|
||||
ControlState GetState( const DIJOYSTATE* const joystate ) const;
|
||||
Button(u8 index, const BYTE& button) : m_index(index), m_button(button) {}
|
||||
ControlState GetState() const;
|
||||
private:
|
||||
const unsigned int m_index;
|
||||
const BYTE& m_button;
|
||||
const u8 m_index;
|
||||
};
|
||||
|
||||
class Axis : public Input
|
||||
{
|
||||
friend class Joystick;
|
||||
public:
|
||||
std::string GetName() const;
|
||||
protected:
|
||||
Axis( const unsigned int index, const LONG base, const LONG range ) : m_index(index), m_base(base), m_range(range) {}
|
||||
ControlState GetState( const DIJOYSTATE* const joystate ) const;
|
||||
Axis(u8 index, const LONG& axis, LONG base, LONG range) : m_index(index), m_axis(axis), m_base(base), m_range(range) {}
|
||||
ControlState GetState() const;
|
||||
private:
|
||||
const unsigned int m_index;
|
||||
const LONG m_base;
|
||||
const LONG m_range;
|
||||
const LONG& m_axis;
|
||||
const LONG m_base, m_range;
|
||||
const u8 m_index;
|
||||
};
|
||||
|
||||
class Hat : public Input
|
||||
{
|
||||
friend class Joystick;
|
||||
public:
|
||||
std::string GetName() const;
|
||||
protected:
|
||||
Hat( const unsigned int index, const unsigned int direction ) : m_index(index), m_direction(direction) {}
|
||||
ControlState GetState( const DIJOYSTATE* const joystate ) const;
|
||||
Hat(u8 index, const DWORD& hat, u8 direction) : m_index(index), m_hat(hat), m_direction(direction) {}
|
||||
ControlState GetState() const;
|
||||
private:
|
||||
const unsigned int m_index;
|
||||
const unsigned int m_direction;
|
||||
const DWORD& m_hat;
|
||||
const u8 m_index, m_direction;
|
||||
};
|
||||
|
||||
template <typename P>
|
||||
class Force : public Output
|
||||
{
|
||||
friend class Joystick;
|
||||
public:
|
||||
std::string GetName() const;
|
||||
protected:
|
||||
Force(const unsigned int index, const unsigned int type);
|
||||
void SetState(const ControlState state, EffectState* const joystate);
|
||||
Force(u8 index, EffectState& state);
|
||||
void SetState(ControlState state);
|
||||
private:
|
||||
const unsigned int m_index;
|
||||
const unsigned int m_type;
|
||||
P params;
|
||||
EffectState& m_state;
|
||||
P params;
|
||||
const u8 m_index;
|
||||
};
|
||||
typedef Force<DICONSTANTFORCE> ForceConstant;
|
||||
typedef Force<DIRAMPFORCE> ForceRamp;
|
||||
typedef Force<DIPERIODIC> ForcePeriodic;
|
||||
|
||||
public:
|
||||
bool UpdateInput();
|
||||
bool UpdateOutput();
|
||||
|
||||
ControlState GetInputState( const ControllerInterface::Device::Input* const input ) const;
|
||||
void SetOutputState( const ControllerInterface::Device::Output* const input, const ControlState state );
|
||||
|
||||
void ClearInputState();
|
||||
|
||||
public:
|
||||
Joystick( /*const LPCDIDEVICEINSTANCE lpddi, */const LPDIRECTINPUTDEVICE8 device, const unsigned int index );
|
||||
Joystick(const LPDIRECTINPUTDEVICE8 device, const unsigned int index);
|
||||
~Joystick();
|
||||
|
||||
std::string GetName() const;
|
||||
@ -130,7 +101,6 @@ public:
|
||||
private:
|
||||
const LPDIRECTINPUTDEVICE8 m_device;
|
||||
const unsigned int m_index;
|
||||
//const std::string m_name;
|
||||
|
||||
DIJOYSTATE m_state_in;
|
||||
std::vector<EffectState> m_state_out;
|
||||
|
@ -101,10 +101,10 @@ KeyboardMouse::KeyboardMouse(const LPDIRECTINPUTDEVICE8 kb_device, const LPDIREC
|
||||
|
||||
// KEYBOARD
|
||||
// add keys
|
||||
for (unsigned int i = 0; i < sizeof(named_keys)/sizeof(*named_keys); ++i)
|
||||
AddInput(new Key(i));
|
||||
for (u8 i = 0; i < sizeof(named_keys)/sizeof(*named_keys); ++i)
|
||||
AddInput(new Key(i, m_state_in.keyboard[named_keys[i].code]));
|
||||
// add lights
|
||||
for (unsigned int i = 0; i < sizeof(named_lights)/sizeof(*named_lights); ++i)
|
||||
for (u8 i = 0; i < sizeof(named_lights)/sizeof(*named_lights); ++i)
|
||||
AddOutput(new Light(i));
|
||||
|
||||
// MOUSE
|
||||
@ -114,18 +114,20 @@ KeyboardMouse::KeyboardMouse(const LPDIRECTINPUTDEVICE8 kb_device, const LPDIREC
|
||||
mouse_caps.dwSize = sizeof(mouse_caps);
|
||||
m_mo_device->GetCapabilities(&mouse_caps);
|
||||
// mouse buttons
|
||||
for (unsigned int i = 0; i < mouse_caps.dwButtons; ++i)
|
||||
AddInput(new Button(i));
|
||||
for (u8 i = 0; i < mouse_caps.dwButtons; ++i)
|
||||
AddInput(new Button(i, m_state_in.mouse.rgbButtons[i]));
|
||||
// mouse axes
|
||||
for (unsigned int i = 0; i < mouse_caps.dwAxes; ++i)
|
||||
{
|
||||
const LONG& ax = (&m_state_in.mouse.lX)[i];
|
||||
|
||||
// each axis gets a negative and a positive input instance associated with it
|
||||
AddInput(new Axis(i, (2==i) ? -1 : -MOUSE_AXIS_SENSITIVITY));
|
||||
AddInput(new Axis(i, -(2==i) ? 1 : MOUSE_AXIS_SENSITIVITY));
|
||||
AddInput(new Axis(i, ax, (2==i) ? -1 : -MOUSE_AXIS_SENSITIVITY));
|
||||
AddInput(new Axis(i, ax, -(2==i) ? 1 : MOUSE_AXIS_SENSITIVITY));
|
||||
}
|
||||
// cursor, with a hax for-loop
|
||||
for (unsigned int i=0; i<4; ++i)
|
||||
AddInput(new Cursor(!!(i&2), !!(i&1)));
|
||||
AddInput(new Cursor(!!(i&2), (&m_state_in.cursor.x)[i/2], !!(i&1)));
|
||||
}
|
||||
|
||||
void GetMousePos(float* const x, float* const y)
|
||||
@ -244,15 +246,15 @@ std::string KeyboardMouse::GetSource() const
|
||||
return DINPUT_SOURCE_NAME;
|
||||
}
|
||||
|
||||
ControlState KeyboardMouse::GetInputState(const ControllerInterface::Device::Input* const input) const
|
||||
{
|
||||
return (((Input*)input)->GetState(&m_state_in));
|
||||
}
|
||||
|
||||
void KeyboardMouse::SetOutputState(const ControllerInterface::Device::Output* const output, const ControlState state)
|
||||
{
|
||||
((Output*)output)->SetState(state, m_state_out);
|
||||
}
|
||||
//ControlState KeyboardMouse::GetInputState(const ControllerInterface::Device::Input* const input) const
|
||||
//{
|
||||
// return (((Input*)input)->GetState(&m_state_in));
|
||||
//}
|
||||
//
|
||||
//void KeyboardMouse::SetOutputState(const ControllerInterface::Device::Output* const output, const ControlState state)
|
||||
//{
|
||||
// ((Output*)output)->SetState(state, m_state_out);
|
||||
//}
|
||||
|
||||
// names
|
||||
std::string KeyboardMouse::Key::GetName() const
|
||||
@ -283,33 +285,33 @@ std::string KeyboardMouse::Cursor::GetName() const
|
||||
|
||||
std::string KeyboardMouse::Light::GetName() const
|
||||
{
|
||||
return named_lights[ m_index ].name;
|
||||
return named_lights[m_index].name;
|
||||
}
|
||||
|
||||
// get/set state
|
||||
ControlState KeyboardMouse::Key::GetState(const State* const state) const
|
||||
ControlState KeyboardMouse::Key::GetState() const
|
||||
{
|
||||
return (state->keyboard[named_keys[m_index].code] != 0);
|
||||
return (m_key != 0);
|
||||
}
|
||||
|
||||
ControlState KeyboardMouse::Button::GetState(const State* const state) const
|
||||
ControlState KeyboardMouse::Button::GetState() const
|
||||
{
|
||||
return (state->mouse.rgbButtons[m_index] != 0);
|
||||
return (m_button != 0);
|
||||
}
|
||||
|
||||
ControlState KeyboardMouse::Axis::GetState(const State* const state) const
|
||||
ControlState KeyboardMouse::Axis::GetState() const
|
||||
{
|
||||
return std::max(0.0f, ControlState((&state->mouse.lX)[m_index]) / m_range);
|
||||
return std::max(0.0f, ControlState(m_axis) / m_range);
|
||||
}
|
||||
|
||||
ControlState KeyboardMouse::Cursor::GetState(const State* const state) const
|
||||
ControlState KeyboardMouse::Cursor::GetState() const
|
||||
{
|
||||
return std::max(0.0f, ControlState((&state->cursor.x)[m_index]) / (m_positive ? 1.0f : -1.0f));
|
||||
return std::max(0.0f, ControlState(m_axis) / (m_positive ? 1.0f : -1.0f));
|
||||
}
|
||||
|
||||
void KeyboardMouse::Light::SetState(const ControlState state, unsigned char* const state_out)
|
||||
void KeyboardMouse::Light::SetState(const ControlState state)
|
||||
{
|
||||
state_out[m_index] = (unsigned char)(state * 255);
|
||||
//state_out[m_index] = (unsigned char)(state * 255);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -18,11 +18,7 @@ void InitKeyboardMouse(IDirectInput8* const idi8, std::vector<ControllerInterfac
|
||||
|
||||
class KeyboardMouse : public ControllerInterface::Device
|
||||
{
|
||||
friend class ControllerInterface;
|
||||
friend class ControllerInterface::ControlReference;
|
||||
|
||||
protected:
|
||||
|
||||
private:
|
||||
struct State
|
||||
{
|
||||
BYTE keyboard[256];
|
||||
@ -33,90 +29,67 @@ protected:
|
||||
} cursor;
|
||||
};
|
||||
|
||||
class Input : public ControllerInterface::Device::Input
|
||||
{
|
||||
friend class KeyboardMouse;
|
||||
protected:
|
||||
virtual ControlState GetState(const State* const boardstate) const = 0;
|
||||
};
|
||||
|
||||
class Output : public ControllerInterface::Device::Output
|
||||
{
|
||||
friend class KeyboardMouse;
|
||||
protected:
|
||||
virtual void SetState(const ControlState state, unsigned char* const state_out) = 0;
|
||||
};
|
||||
|
||||
class Key : public Input
|
||||
{
|
||||
friend class KeyboardMouse;
|
||||
public:
|
||||
std::string GetName() const;
|
||||
protected:
|
||||
Key( const unsigned int index ) : m_index(index) {}
|
||||
ControlState GetState(const State* const state) const;
|
||||
Key(u8 index, const BYTE& key) : m_index(index), m_key(key) {}
|
||||
ControlState GetState() const;
|
||||
private:
|
||||
const unsigned int m_index;
|
||||
const BYTE& m_key;
|
||||
const u8 m_index;
|
||||
};
|
||||
|
||||
class Button : public Input
|
||||
{
|
||||
friend class KeyboardMouse;
|
||||
public:
|
||||
std::string GetName() const;
|
||||
protected:
|
||||
Button( const unsigned int index ) : m_index(index) {}
|
||||
ControlState GetState(const State* const state) const;
|
||||
Button(u8 index, const BYTE& button) : m_index(index), m_button(button) {}
|
||||
ControlState GetState() const;
|
||||
private:
|
||||
const unsigned int m_index;
|
||||
const BYTE& m_button;
|
||||
const u8 m_index;
|
||||
};
|
||||
|
||||
class Axis : public Input
|
||||
{
|
||||
friend class KeyboardMouse;
|
||||
public:
|
||||
std::string GetName() const;
|
||||
protected:
|
||||
Axis( const unsigned int index, const LONG range ) : m_index(index), m_range(range) {}
|
||||
ControlState GetState(const State* const state) const;
|
||||
Axis(u8 index, const LONG& axis, LONG range) : m_index(index), m_axis(axis), m_range(range) {}
|
||||
ControlState GetState() const;
|
||||
private:
|
||||
const unsigned int m_index;
|
||||
const LONG m_range;
|
||||
const LONG& m_axis;
|
||||
const LONG m_range;
|
||||
const u8 m_index;
|
||||
};
|
||||
|
||||
class Cursor : public Input
|
||||
{
|
||||
friend class KeyboardMouse;
|
||||
public:
|
||||
std::string GetName() const;
|
||||
bool IsDetectable() { return false; }
|
||||
protected:
|
||||
Cursor(const unsigned int index, const bool positive) : m_index(index), m_positive(positive) {}
|
||||
ControlState GetState(const State* const state) const;
|
||||
Cursor(u8 index, const float& axis, const bool positive) : m_index(index), m_axis(axis), m_positive(positive) {}
|
||||
ControlState GetState() const;
|
||||
private:
|
||||
const unsigned int m_index;
|
||||
const bool m_positive;
|
||||
const float& m_axis;
|
||||
const u8 m_index;
|
||||
const bool m_positive;
|
||||
};
|
||||
|
||||
class Light : public Output
|
||||
{
|
||||
friend class KeyboardMouse;
|
||||
public:
|
||||
std::string GetName() const;
|
||||
protected:
|
||||
Light( const unsigned int index ) : m_index(index) {}
|
||||
void SetState( const ControlState state, unsigned char* const state_out );
|
||||
Light(u8 index) : m_index(index) {}
|
||||
void SetState(ControlState state);
|
||||
private:
|
||||
const unsigned int m_index;
|
||||
const u8 m_index;
|
||||
};
|
||||
|
||||
|
||||
public:
|
||||
bool UpdateInput();
|
||||
bool UpdateOutput();
|
||||
|
||||
ControlState GetInputState( const ControllerInterface::Device::Input* const input ) const;
|
||||
void SetOutputState( const ControllerInterface::Device::Output* const input, const ControlState state );
|
||||
|
||||
public:
|
||||
KeyboardMouse(const LPDIRECTINPUTDEVICE8 kb_device, const LPDIRECTINPUTDEVICE8 mo_device);
|
||||
~KeyboardMouse();
|
||||
|
||||
|
Reference in New Issue
Block a user