mirror of https://github.com/stella-emu/stella.git
Merge branch 'master' into feature/filesystem
This commit is contained in:
commit
1419f2d538
|
@ -4068,10 +4068,10 @@
|
|||
|
||||
<p>Stella supports viewing images and ROM properties of the currently
|
||||
selected ROM in the ROM launcher. Image support is automatic, as long as your
|
||||
image directory contains snapshots in the appropriate format. The label
|
||||
(if existing) and the number of matching snapshots are displayed under the
|
||||
current one. The mouse or the ROM Launcher hotkeys can be used to browse
|
||||
multiple images or a ROM.</p>
|
||||
image directory contains any images in the appropriate format. The label (if
|
||||
existing) and the number of matching images are displayed under the
|
||||
current image. The mouse, the ROM Launcher hotkeys or the controller can be
|
||||
used to browse multiple images of a ROM.</p>
|
||||
|
||||
Notes:
|
||||
<li>The images can have PNG or JPG format.</li>
|
||||
|
|
|
@ -160,6 +160,16 @@
|
|||
Button 2 or 6 close the menu without any action.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Button 1 + Left</td>
|
||||
<td>-</td>
|
||||
<td>Display previous image</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Button 1 + Right</td>
|
||||
<td>-</td>
|
||||
<td>Display next image</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Button 2</td>
|
||||
<td>SKILL P2</td>
|
||||
|
|
|
@ -74,11 +74,6 @@ SoundSDL2::~SoundSDL2()
|
|||
if(!myIsInitializedFlag)
|
||||
return;
|
||||
|
||||
if(myWavDevice)
|
||||
{
|
||||
SDL_CloseAudioDevice(myWavDevice);
|
||||
SDL_FreeWAV(myWavBuffer);
|
||||
}
|
||||
SDL_CloseAudioDevice(myDevice);
|
||||
SDL_QuitSubSystem(SDL_INIT_AUDIO);
|
||||
}
|
||||
|
@ -165,7 +160,7 @@ void SoundSDL2::open(shared_ptr<AudioQueue> audioQueue,
|
|||
openDevice();
|
||||
|
||||
myEmulationTiming = emulationTiming;
|
||||
myWavSpeed = 262 * 60 * 2. / myEmulationTiming->audioSampleRate();
|
||||
myWavHandler.setSpeed(262 * 60 * 2. / myEmulationTiming->audioSampleRate());
|
||||
|
||||
Logger::debug("SoundSDL2::open started ...");
|
||||
|
||||
|
@ -214,11 +209,7 @@ void SoundSDL2::mute(bool state)
|
|||
{
|
||||
myAudioSettings.setEnabled(!state);
|
||||
if(state)
|
||||
{
|
||||
SDL_LockAudioDevice(myDevice);
|
||||
myVolumeFactor = 0;
|
||||
SDL_UnlockAudioDevice(myDevice);
|
||||
}
|
||||
else
|
||||
setVolume(myAudioSettings.volume());
|
||||
}
|
||||
|
@ -242,10 +233,10 @@ bool SoundSDL2::pause(bool state)
|
|||
|
||||
const bool oldstate = SDL_GetAudioDeviceStatus(myDevice) == SDL_AUDIO_PAUSED;
|
||||
if(myIsInitializedFlag)
|
||||
{
|
||||
SDL_PauseAudioDevice(myDevice, state ? 1 : 0);
|
||||
if(myWavDevice)
|
||||
SDL_PauseAudioDevice(myWavDevice, state ? 1 : 0);
|
||||
|
||||
myWavHandler.pause(state);
|
||||
}
|
||||
return oldstate;
|
||||
}
|
||||
|
||||
|
@ -255,10 +246,7 @@ void SoundSDL2::setVolume(uInt32 volume)
|
|||
if(myIsInitializedFlag && (volume <= 100))
|
||||
{
|
||||
myAudioSettings.setVolume(volume);
|
||||
|
||||
SDL_LockAudioDevice(myDevice);
|
||||
myVolumeFactor = myAudioSettings.enabled() ? static_cast<float>(volume) / 100.F : 0;
|
||||
SDL_UnlockAudioDevice(myDevice);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -336,15 +324,6 @@ string SoundSDL2::about() const
|
|||
return buf.str();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void SoundSDL2::processFragment(float* stream, uInt32 length)
|
||||
{
|
||||
myResampler->fillFragment(stream, length);
|
||||
|
||||
for(uInt32 i = 0; i < length; ++i)
|
||||
stream[i] *= myVolumeFactor;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void SoundSDL2::initResampler()
|
||||
{
|
||||
|
@ -395,12 +374,21 @@ void SoundSDL2::initResampler()
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void SoundSDL2::callback(void* udata, uInt8* stream, int len)
|
||||
void SoundSDL2::callback(void* object, uInt8* stream, int len)
|
||||
{
|
||||
auto* self = static_cast<SoundSDL2*>(udata);
|
||||
auto* self = static_cast<SoundSDL2*>(object);
|
||||
|
||||
if(self->myAudioQueue)
|
||||
self->processFragment(reinterpret_cast<float*>(stream), len >> 2);
|
||||
{
|
||||
// The stream is 32-bit float (even though this callback is 8-bits), since
|
||||
// the resampler and TIA audio subsystem always generate float samples
|
||||
auto* s = reinterpret_cast<float*>(stream);
|
||||
const uInt32 length = len >> 2;
|
||||
self->myResampler->fillFragment(s, length);
|
||||
|
||||
for(uInt32 i = 0; i < length; ++i) // TODO - perhaps move into Resampler
|
||||
s[i] *= SoundSDL2::myVolumeFactor;
|
||||
}
|
||||
else
|
||||
SDL_memset(stream, 0, len);
|
||||
}
|
||||
|
@ -408,129 +396,161 @@ void SoundSDL2::callback(void* udata, uInt8* stream, int len)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool SoundSDL2::playWav(const string& fileName, const uInt32 position,
|
||||
const uInt32 length)
|
||||
{
|
||||
// Load WAV file
|
||||
if(fileName != myWavFilename || myWavBuffer == nullptr)
|
||||
{
|
||||
if(myWavBuffer)
|
||||
{
|
||||
SDL_FreeWAV(myWavBuffer);
|
||||
myWavBuffer = nullptr;
|
||||
}
|
||||
if(SDL_LoadWAV(fileName.c_str(), &myWavSpec, &myWavBuffer, &myWavLength) == nullptr)
|
||||
return false;
|
||||
// Set the callback function
|
||||
myWavSpec.callback = wavCallback;
|
||||
myWavSpec.userdata = nullptr;
|
||||
//myWavSpec.samples = 4096; // decrease for smaller samples;
|
||||
}
|
||||
if(position > myWavLength)
|
||||
return false;
|
||||
|
||||
myWavFilename = fileName;
|
||||
|
||||
myWavLen = length
|
||||
? std::min(length, myWavLength - position)
|
||||
: myWavLength;
|
||||
myWavPos = myWavBuffer + position;
|
||||
|
||||
// Open audio device
|
||||
if(!myWavDevice)
|
||||
{
|
||||
const char* device = myDeviceId ? myDevices.at(myDeviceId).first.c_str() : nullptr;
|
||||
|
||||
myWavDevice = SDL_OpenAudioDevice(device, 0, &myWavSpec, nullptr, 0);
|
||||
if(!myWavDevice)
|
||||
return false;
|
||||
// Play audio
|
||||
SDL_PauseAudioDevice(myWavDevice, 0);
|
||||
}
|
||||
return true;
|
||||
return myWavHandler.play(fileName, device, position, length);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void SoundSDL2::stopWav()
|
||||
{
|
||||
if(myWavBuffer)
|
||||
{
|
||||
// Clean up
|
||||
myWavLen = 0;
|
||||
SDL_CloseAudioDevice(myWavDevice);
|
||||
myWavDevice = 0;
|
||||
SDL_FreeWAV(myWavBuffer);
|
||||
myWavBuffer = nullptr;
|
||||
}
|
||||
if(myWavCvtBuffer)
|
||||
{
|
||||
myWavCvtBuffer.reset();
|
||||
myWavCvtBufferSize = 0;
|
||||
}
|
||||
myWavHandler.stop();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 SoundSDL2::wavSize() const
|
||||
{
|
||||
return myWavBuffer ? myWavLen : 0;
|
||||
return myWavHandler.size();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void SoundSDL2::wavCallback(void* udata, uInt8* stream, int len)
|
||||
bool SoundSDL2::WavHandlerSDL2::play(
|
||||
const string& fileName, const char* device,
|
||||
const uInt32 position, const uInt32 length
|
||||
)
|
||||
{
|
||||
SDL_memset(stream, myWavSpec.silence, len);
|
||||
if(myWavLen)
|
||||
// Load WAV file
|
||||
if(fileName != myFilename || myBuffer == nullptr)
|
||||
{
|
||||
if(myWavSpeed != 1.0)
|
||||
if(myBuffer)
|
||||
{
|
||||
SDL_FreeWAV(myBuffer);
|
||||
myBuffer = nullptr;
|
||||
}
|
||||
SDL_zero(mySpec);
|
||||
if(SDL_LoadWAV(fileName.c_str(), &mySpec, &myBuffer, &myLength) == nullptr)
|
||||
return false;
|
||||
|
||||
// Set the callback function
|
||||
mySpec.callback = callback;
|
||||
mySpec.userdata = this;
|
||||
}
|
||||
if(position > myLength)
|
||||
return false;
|
||||
|
||||
myFilename = fileName;
|
||||
|
||||
myRemaining = length
|
||||
? std::min(length, myLength - position)
|
||||
: myLength;
|
||||
myPos = myBuffer + position;
|
||||
|
||||
// Open audio device
|
||||
if(!myDevice)
|
||||
{
|
||||
myDevice = SDL_OpenAudioDevice(device, 0, &mySpec, nullptr, 0);
|
||||
if(!myDevice)
|
||||
return false;
|
||||
// Play audio
|
||||
SDL_PauseAudioDevice(myDevice, 0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void SoundSDL2::WavHandlerSDL2::stop()
|
||||
{
|
||||
if(myBuffer)
|
||||
{
|
||||
// Clean up
|
||||
myRemaining = 0;
|
||||
SDL_CloseAudioDevice(myDevice); myDevice = 0;
|
||||
SDL_FreeWAV(myBuffer); myBuffer = nullptr;
|
||||
}
|
||||
if(myCvtBuffer)
|
||||
{
|
||||
myCvtBuffer.reset();
|
||||
myCvtBufferSize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void SoundSDL2::WavHandlerSDL2::processWav(uInt8* stream, uInt32 len)
|
||||
{
|
||||
SDL_memset(stream, mySpec.silence, len);
|
||||
if(myRemaining)
|
||||
{
|
||||
if(mySpeed != 1.0)
|
||||
{
|
||||
const int origLen = len;
|
||||
len = std::round(len / myWavSpeed);
|
||||
len = std::round(len / mySpeed);
|
||||
const int newFreq =
|
||||
std::round(static_cast<double>(myWavSpec.freq) * origLen / len);
|
||||
std::round(static_cast<double>(mySpec.freq) * origLen / len);
|
||||
|
||||
if(static_cast<uInt32>(len) > myWavLen)
|
||||
len = myWavLen;
|
||||
if(static_cast<uInt32>(len) > myRemaining)
|
||||
len = myRemaining;
|
||||
|
||||
SDL_AudioCVT cvt;
|
||||
SDL_BuildAudioCVT(&cvt, myWavSpec.format, myWavSpec.channels, myWavSpec.freq,
|
||||
myWavSpec.format, myWavSpec.channels, newFreq);
|
||||
SDL_BuildAudioCVT(&cvt, mySpec.format, mySpec.channels, mySpec.freq,
|
||||
mySpec.format, mySpec.channels, newFreq);
|
||||
SDL_assert(cvt.needed); // Obviously, this one is always needed.
|
||||
cvt.len = len * myWavSpec.channels; // Mono 8 bit sample frames
|
||||
cvt.len = len * mySpec.channels; // Mono 8 bit sample frames
|
||||
|
||||
if(!myWavCvtBuffer ||
|
||||
myWavCvtBufferSize < static_cast<uInt32>(cvt.len * cvt.len_mult))
|
||||
if(!myCvtBuffer ||
|
||||
myCvtBufferSize < static_cast<uInt32>(cvt.len * cvt.len_mult))
|
||||
{
|
||||
myWavCvtBufferSize = cvt.len * cvt.len_mult;
|
||||
myWavCvtBuffer = make_unique<uInt8[]>(myWavCvtBufferSize);
|
||||
myCvtBufferSize = cvt.len * cvt.len_mult;
|
||||
myCvtBuffer = make_unique<uInt8[]>(myCvtBufferSize);
|
||||
}
|
||||
cvt.buf = myWavCvtBuffer.get();
|
||||
cvt.buf = myCvtBuffer.get();
|
||||
|
||||
// Read original data into conversion buffer
|
||||
SDL_memcpy(cvt.buf, myWavPos, cvt.len);
|
||||
SDL_memcpy(cvt.buf, myPos, cvt.len);
|
||||
SDL_ConvertAudio(&cvt);
|
||||
// Mix volume adjusted WAV data into silent buffer
|
||||
SDL_MixAudioFormat(stream, cvt.buf, myWavSpec.format, cvt.len_cvt,
|
||||
SDL_MIX_MAXVOLUME * myVolumeFactor);
|
||||
SDL_MixAudioFormat(stream, cvt.buf, mySpec.format, cvt.len_cvt,
|
||||
SDL_MIX_MAXVOLUME * SoundSDL2::myVolumeFactor);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(static_cast<uInt32>(len) > myWavLen)
|
||||
len = myWavLen;
|
||||
if(static_cast<uInt32>(len) > myRemaining)
|
||||
len = myRemaining;
|
||||
|
||||
// Mix volume adjusted WAV data into silent buffer
|
||||
SDL_MixAudioFormat(stream, myWavPos, myWavSpec.format, len,
|
||||
SDL_MixAudioFormat(stream, myPos, mySpec.format, len,
|
||||
SDL_MIX_MAXVOLUME * myVolumeFactor);
|
||||
}
|
||||
myWavPos += len;
|
||||
myWavLen -= len;
|
||||
myPos += len;
|
||||
myRemaining -= len;
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void SoundSDL2::WavHandlerSDL2::callback(void* object, uInt8* stream, int len)
|
||||
{
|
||||
static_cast<WavHandlerSDL2*>(object)->processWav(
|
||||
stream, static_cast<uInt32>(len));
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
SoundSDL2::WavHandlerSDL2::~WavHandlerSDL2()
|
||||
{
|
||||
if(myDevice)
|
||||
{
|
||||
SDL_CloseAudioDevice(myDevice);
|
||||
SDL_FreeWAV(myBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void SoundSDL2::WavHandlerSDL2::pause(bool state) const
|
||||
{
|
||||
if(myDevice)
|
||||
SDL_PauseAudioDevice(myDevice, state ? 1 : 0);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
float SoundSDL2::myVolumeFactor = 0.F;
|
||||
SDL_AudioSpec SoundSDL2::myWavSpec; // audio output format
|
||||
uInt8* SoundSDL2::myWavPos = nullptr; // pointer to the audio buffer to be played
|
||||
uInt32 SoundSDL2::myWavLen = 0; // remaining length of the sample we have to play
|
||||
double SoundSDL2::myWavSpeed = 1.0;
|
||||
unique_ptr<uInt8[]> SoundSDL2::myWavCvtBuffer;
|
||||
uInt32 SoundSDL2::myWavCvtBufferSize = 0;
|
||||
|
||||
#endif // SOUND_SUPPORT
|
||||
|
|
|
@ -125,7 +125,7 @@ class SoundSDL2 : public Sound
|
|||
@param position The position to start playing
|
||||
@param length The played length
|
||||
|
||||
@return True, if the WAV file can be played
|
||||
@return True if the WAV file can be played, else false
|
||||
*/
|
||||
bool playWav(const string& fileName, const uInt32 position = 0,
|
||||
const uInt32 length = 0) override;
|
||||
|
@ -142,7 +142,7 @@ class SoundSDL2 : public Sound
|
|||
*/
|
||||
uInt32 wavSize() const override;
|
||||
|
||||
protected:
|
||||
private:
|
||||
/**
|
||||
This method is called to query the audio devices.
|
||||
|
||||
|
@ -150,17 +150,6 @@ class SoundSDL2 : public Sound
|
|||
*/
|
||||
void queryHardware(VariantList& devices) override;
|
||||
|
||||
/**
|
||||
Invoked by the sound callback to process the next sound fragment.
|
||||
The stream is 16-bits (even though the callback is 8-bits), since
|
||||
the TIASnd class always generates signed 16-bit stereo samples.
|
||||
|
||||
@param stream Pointer to the start of the fragment
|
||||
@param length Length of the fragment
|
||||
*/
|
||||
void processFragment(float* stream, uInt32 length);
|
||||
|
||||
private:
|
||||
/**
|
||||
The actual sound device is opened only when absolutely necessary.
|
||||
Typically this will only happen once per program run, but it can also
|
||||
|
@ -171,47 +160,75 @@ class SoundSDL2 : public Sound
|
|||
void initResampler();
|
||||
|
||||
private:
|
||||
AudioSettings& myAudioSettings;
|
||||
|
||||
// Indicates if the sound device was successfully initialized
|
||||
bool myIsInitializedFlag{false};
|
||||
|
||||
// Audio specification structure
|
||||
SDL_AudioSpec myHardwareSpec;
|
||||
|
||||
SDL_AudioDeviceID myDevice{0};
|
||||
uInt32 myDeviceId{0};
|
||||
|
||||
SDL_AudioDeviceID myDevice{0};
|
||||
|
||||
shared_ptr<AudioQueue> myAudioQueue;
|
||||
unique_ptr<Resampler> myResampler;
|
||||
|
||||
EmulationTiming* myEmulationTiming{nullptr};
|
||||
|
||||
Int16* myCurrentFragment{nullptr};
|
||||
bool myUnderrun{false};
|
||||
|
||||
unique_ptr<Resampler> myResampler;
|
||||
string myAboutString;
|
||||
|
||||
AudioSettings& myAudioSettings;
|
||||
/**
|
||||
This class implements WAV file playback using the SDL2 sound API.
|
||||
*/
|
||||
class WavHandlerSDL2
|
||||
{
|
||||
public:
|
||||
explicit WavHandlerSDL2() = default;
|
||||
~WavHandlerSDL2();
|
||||
|
||||
// WAV file sound variables
|
||||
string myWavFilename;
|
||||
uInt32 myWavLength{0};
|
||||
SDL_AudioDeviceID myWavDevice{0};
|
||||
uInt8* myWavBuffer{nullptr};
|
||||
bool play(const string& fileName, const char* device,
|
||||
const uInt32 position, const uInt32 length);
|
||||
void stop();
|
||||
uInt32 size() const { return myBuffer ? myRemaining : 0; }
|
||||
|
||||
void setSpeed(const double speed) { mySpeed = speed; }
|
||||
void pause(bool state) const;
|
||||
|
||||
private:
|
||||
string myFilename;
|
||||
uInt32 myLength{0};
|
||||
SDL_AudioDeviceID myDevice{0};
|
||||
uInt8* myBuffer{nullptr};
|
||||
double mySpeed{1.0};
|
||||
unique_ptr<uInt8[]> myCvtBuffer;
|
||||
uInt32 myCvtBufferSize{0};
|
||||
SDL_AudioSpec mySpec; // audio output format
|
||||
uInt8* myPos{nullptr}; // pointer to the audio buffer to be played
|
||||
uInt32 myRemaining{0}; // remaining length of the sample we have to play
|
||||
|
||||
private:
|
||||
// Callback function invoked by the SDL Audio library when it needs data
|
||||
void processWav(uInt8* stream, uInt32 len);
|
||||
static void callback(void* object, uInt8* stream, int len);
|
||||
|
||||
// Following constructors and assignment operators not supported
|
||||
WavHandlerSDL2(const WavHandlerSDL2&) = delete;
|
||||
WavHandlerSDL2(WavHandlerSDL2&&) = delete;
|
||||
WavHandlerSDL2& operator=(const WavHandlerSDL2&) = delete;
|
||||
WavHandlerSDL2& operator=(WavHandlerSDL2&&) = delete;
|
||||
};
|
||||
|
||||
WavHandlerSDL2 myWavHandler;
|
||||
|
||||
static float myVolumeFactor; // Current volume level (0 - 100)
|
||||
static double myWavSpeed;
|
||||
static unique_ptr<uInt8[]> myWavCvtBuffer;
|
||||
static uInt32 myWavCvtBufferSize;
|
||||
static SDL_AudioSpec myWavSpec; // audio output format
|
||||
static uInt8* myWavPos; // pointer to the audio buffer to be played
|
||||
static uInt32 myWavLen; // remaining length of the sample we have to play
|
||||
|
||||
string myAboutString;
|
||||
|
||||
private:
|
||||
// Callback functions invoked by the SDL Audio library when it needs data
|
||||
static void callback(void* udata, uInt8* stream, int len);
|
||||
static void wavCallback(void* udata, uInt8* stream, int len);
|
||||
static void callback(void* object, uInt8* stream, int len);
|
||||
|
||||
// Following constructors and assignment operators not supported
|
||||
SoundSDL2() = delete;
|
||||
|
|
|
@ -67,7 +67,7 @@ void DialogContainer::updateTime(uInt64 time)
|
|||
// Joystick has been pressed long
|
||||
if(myCurrentButtonDown.stick != -1 && myButtonLongPressTime < myTime)
|
||||
{
|
||||
myButtonLongPress = true;
|
||||
myIgnoreButtonUp = true;
|
||||
activeDialog->handleJoyDown(myCurrentButtonDown.stick, myCurrentButtonDown.button, true);
|
||||
myButtonLongPressTime = myButtonRepeatTime = myTime + _REPEAT_NONE;
|
||||
}
|
||||
|
@ -75,6 +75,10 @@ void DialogContainer::updateTime(uInt64 time)
|
|||
// Joystick axis still pressed
|
||||
if(myCurrentAxisDown.stick != -1 && myAxisRepeatTime < myTime)
|
||||
{
|
||||
if(myCurrentButtonDown.stick == myCurrentAxisDown.stick)
|
||||
activeDialog->handleJoyAxis(myCurrentAxisDown.stick, myCurrentAxisDown.axis,
|
||||
myCurrentAxisDown.adir, myCurrentButtonDown.button);
|
||||
else
|
||||
activeDialog->handleJoyAxis(myCurrentAxisDown.stick, myCurrentAxisDown.axis,
|
||||
myCurrentAxisDown.adir);
|
||||
myAxisRepeatTime = myTime + _REPEAT_SUSTAIN_DELAY;
|
||||
|
@ -323,7 +327,10 @@ void DialogContainer::handleJoyBtnEvent(int stick, int button, bool pressed)
|
|||
// Send the event to the dialog box on the top of the stack
|
||||
Dialog* activeDialog = myDialogStack.top();
|
||||
|
||||
if(pressed && myButtonRepeatTime < myTime) // prevent pending repeats after enabling repeat again
|
||||
if(pressed)
|
||||
{
|
||||
if(myButtonRepeatTime < myTime || // prevent pending repeats after enabling repeat again
|
||||
myButtonRepeatTime + _REPEAT_INITIAL_DELAY > myTime) // ignore blocking delays
|
||||
{
|
||||
myCurrentButtonDown.stick = stick;
|
||||
myCurrentButtonDown.button = button;
|
||||
|
@ -332,6 +339,7 @@ void DialogContainer::handleJoyBtnEvent(int stick, int button, bool pressed)
|
|||
|
||||
activeDialog->handleJoyDown(stick, button);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Only stop firing events if it's the current button
|
||||
|
@ -340,8 +348,8 @@ void DialogContainer::handleJoyBtnEvent(int stick, int button, bool pressed)
|
|||
myCurrentButtonDown.stick = myCurrentButtonDown.button = -1;
|
||||
myButtonRepeatTime = myButtonLongPressTime = 0;
|
||||
}
|
||||
if (myButtonLongPress)
|
||||
myButtonLongPress = false;
|
||||
if(myIgnoreButtonUp)
|
||||
myIgnoreButtonUp = false;
|
||||
else
|
||||
activeDialog->handleJoyUp(stick, button);
|
||||
}
|
||||
|
@ -356,7 +364,8 @@ void DialogContainer::handleJoyAxisEvent(int stick, JoyAxis axis, JoyDir adir, i
|
|||
// Send the event to the dialog box on the top of the stack
|
||||
Dialog* activeDialog = myDialogStack.top();
|
||||
|
||||
// Prevent long button press in button/axis combinations
|
||||
// Prevent button repeats and long button press in button/axis combinations
|
||||
myButtonRepeatTime = myTime + _REPEAT_NONE;
|
||||
myButtonLongPressTime = myTime + _REPEAT_NONE;
|
||||
|
||||
// Only stop firing events if it's the current stick
|
||||
|
@ -374,6 +383,8 @@ void DialogContainer::handleJoyAxisEvent(int stick, JoyAxis axis, JoyDir adir, i
|
|||
myCurrentAxisDown.adir = adir;
|
||||
myAxisRepeatTime = myTime + (activeDialog->repeatEnabled() ? _REPEAT_INITIAL_DELAY : _REPEAT_NONE);
|
||||
}
|
||||
if(adir != JoyDir::NONE)
|
||||
myIgnoreButtonUp = true; // prevent button released events
|
||||
activeDialog->handleJoyAxis(stick, axis, adir, button);
|
||||
}
|
||||
|
||||
|
@ -386,7 +397,8 @@ void DialogContainer::handleJoyHatEvent(int stick, int hat, JoyHatDir hdir, int
|
|||
// Send the event to the dialog box on the top of the stack
|
||||
Dialog* activeDialog = myDialogStack.top();
|
||||
|
||||
// Prevent long button press in button/hat combinations
|
||||
// Prevent button repeats and long button press in button/hat combinations
|
||||
myButtonRepeatTime = myTime + _REPEAT_NONE;
|
||||
myButtonLongPressTime = myTime + _REPEAT_NONE;
|
||||
|
||||
// Only stop firing events if it's the current stick
|
||||
|
|
|
@ -214,7 +214,7 @@ class DialogContainer
|
|||
} myCurrentButtonDown;
|
||||
uInt64 myButtonRepeatTime{0};
|
||||
uInt64 myButtonLongPressTime{0};
|
||||
bool myButtonLongPress{false};
|
||||
bool myIgnoreButtonUp{false};
|
||||
|
||||
// For continuous 'joy axis down' events
|
||||
struct {
|
||||
|
|
|
@ -952,12 +952,13 @@ Event::Type LauncherDialog::getJoyAxisEvent(int stick, JoyAxis axis, JoyDir adir
|
|||
break;
|
||||
|
||||
case Event::UITabPrev:
|
||||
// TODO: check with controller, then update doc (R77 too)
|
||||
myRomImageWidget->changeImage(-1);
|
||||
myEventHandled = true;
|
||||
break;
|
||||
|
||||
case Event::UITabNext:
|
||||
myRomImageWidget->changeImage(1);
|
||||
myEventHandled = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -1136,11 +1137,13 @@ void LauncherDialog::openContextMenu(int x, int y)
|
|||
{
|
||||
// Dynamically create context menu for ROM list options
|
||||
|
||||
bool addCancel = false;
|
||||
if(x < 0 || y < 0)
|
||||
{
|
||||
// Long pressed button, determine position from currently selected list item
|
||||
x = myList->getLeft() + myList->getWidth() / 2;
|
||||
y = myList->getTop() + (myList->getSelected() - myList->currentPos() + 1) * _font.getLineHeight();
|
||||
addCancel = true;
|
||||
}
|
||||
|
||||
struct ContextItem {
|
||||
|
@ -1219,6 +1222,8 @@ void LauncherDialog::openContextMenu(int x, int y)
|
|||
// items.push_back(ContextItem("Options" + ELLIPSIS, "Ctrl+O", "options"));
|
||||
//}
|
||||
}
|
||||
if(addCancel)
|
||||
items.push_back(ContextItem("Cancel", "")); // closes the context menu and does nothing
|
||||
|
||||
// Format items for menu
|
||||
VariantList varItems;
|
||||
|
|
Loading…
Reference in New Issue