You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1308 lines
36 KiB
1308 lines
36 KiB
/*****************************************************************************
|
|
* CoreInteraction.m: MacOS X interface module
|
|
*****************************************************************************
|
|
* Copyright (C) 2011-2015 Felix Paul Kühne
|
|
* $Id$
|
|
*
|
|
* Authors: Felix Paul Kühne <fkuehne -at- videolan -dot- org>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
|
|
*****************************************************************************/
|
|
|
|
#import "CoreInteraction.h"
|
|
#import "intf.h"
|
|
#import "open.h"
|
|
#import "VLCPlaylist.h"
|
|
#import <math.h>
|
|
#import <vlc_playlist.h>
|
|
#import <vlc_input.h>
|
|
#import <vlc_keys.h>
|
|
#import <vlc_vout.h>
|
|
#import <vlc_vout_osd.h>
|
|
#import <vlc/vlc.h>
|
|
#import <vlc_strings.h>
|
|
#import <vlc_url.h>
|
|
#import <vlc_modules.h>
|
|
#import <vlc_charset.h>
|
|
#include <vlc_plugin.h>
|
|
#import "SPMediaKeyTap.h"
|
|
#import "AppleRemote.h"
|
|
#import "InputManager.h"
|
|
|
|
static int BossCallback(vlc_object_t *p_this, const char *psz_var,
|
|
vlc_value_t oldval, vlc_value_t new_val, void *param)
|
|
{
|
|
@autoreleasepool {
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
[[VLCCoreInteraction sharedInstance] pause];
|
|
[[NSApplication sharedApplication] hide:nil];
|
|
});
|
|
|
|
return VLC_SUCCESS;
|
|
}
|
|
}
|
|
|
|
@interface VLCCoreInteraction ()
|
|
{
|
|
int i_currentPlaybackRate;
|
|
mtime_t timeA, timeB;
|
|
|
|
float f_maxVolume;
|
|
|
|
/* media key support */
|
|
BOOL b_mediaKeySupport;
|
|
BOOL b_mediakeyJustJumped;
|
|
SPMediaKeyTap *_mediaKeyController;
|
|
BOOL b_mediaKeyTrapEnabled;
|
|
|
|
AppleRemote *_remote;
|
|
BOOL b_remote_button_hold; /* true as long as the user holds the left,right,plus or minus on the remote control */
|
|
|
|
NSArray *_usedHotkeys;
|
|
}
|
|
@end
|
|
|
|
@implementation VLCCoreInteraction
|
|
|
|
#pragma mark - Initialization
|
|
|
|
+ (VLCCoreInteraction *)sharedInstance
|
|
{
|
|
static VLCCoreInteraction *sharedInstance = nil;
|
|
static dispatch_once_t pred;
|
|
|
|
dispatch_once(&pred, ^{
|
|
sharedInstance = [VLCCoreInteraction new];
|
|
});
|
|
|
|
return sharedInstance;
|
|
}
|
|
|
|
- (instancetype)init
|
|
{
|
|
self = [super init];
|
|
if (self) {
|
|
intf_thread_t *p_intf = getIntf();
|
|
|
|
/* init media key support */
|
|
b_mediaKeySupport = var_InheritBool(p_intf, "macosx-mediakeys");
|
|
if (b_mediaKeySupport) {
|
|
_mediaKeyController = [[SPMediaKeyTap alloc] initWithDelegate:self];
|
|
[[NSUserDefaults standardUserDefaults] registerDefaults:[NSDictionary dictionaryWithObjectsAndKeys:
|
|
[SPMediaKeyTap defaultMediaKeyUserBundleIdentifiers], kMediaKeyUsingBundleIdentifiersDefaultsKey,
|
|
nil]];
|
|
}
|
|
[[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(coreChangedMediaKeySupportSetting:) name: @"VLCMediaKeySupportSettingChanged" object: nil];
|
|
|
|
/* init Apple Remote support */
|
|
_remote = [[AppleRemote alloc] init];
|
|
[_remote setClickCountEnabledButtons: kRemoteButtonPlay];
|
|
[_remote setDelegate: self];
|
|
|
|
var_AddCallback(p_intf->p_libvlc, "intf-boss", BossCallback, (__bridge void *)self);
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (void)dealloc
|
|
{
|
|
intf_thread_t *p_intf = getIntf();
|
|
var_DelCallback(p_intf->p_libvlc, "intf-boss", BossCallback, (__bridge void *)self);
|
|
[[NSNotificationCenter defaultCenter] removeObserver: self];
|
|
}
|
|
|
|
|
|
#pragma mark - Playback Controls
|
|
|
|
- (void)playOrPause
|
|
{
|
|
input_thread_t *p_input = pl_CurrentInput(getIntf());
|
|
playlist_t *p_playlist = pl_Get(getIntf());
|
|
|
|
if (p_input) {
|
|
playlist_TogglePause(p_playlist);
|
|
vlc_object_release(p_input);
|
|
|
|
} else {
|
|
PLRootType root = [[[[VLCMain sharedInstance] playlist] model] currentRootType];
|
|
if ([[[VLCMain sharedInstance] playlist] isSelectionEmpty] && (root == ROOT_TYPE_PLAYLIST || root == ROOT_TYPE_MEDIALIBRARY))
|
|
[[[VLCMain sharedInstance] open] openFileGeneric];
|
|
else
|
|
[[[VLCMain sharedInstance] playlist] playItem:nil];
|
|
}
|
|
}
|
|
|
|
- (void)pause
|
|
{
|
|
playlist_t *p_playlist = pl_Get(getIntf());
|
|
|
|
playlist_Pause(p_playlist);
|
|
}
|
|
|
|
- (void)stop
|
|
{
|
|
playlist_Stop(pl_Get(getIntf()));
|
|
}
|
|
|
|
- (void)faster
|
|
{
|
|
var_TriggerCallback(pl_Get(getIntf()), "rate-faster");
|
|
}
|
|
|
|
- (void)slower
|
|
{
|
|
var_TriggerCallback(pl_Get(getIntf()), "rate-slower");
|
|
}
|
|
|
|
- (void)normalSpeed
|
|
{
|
|
var_SetFloat(pl_Get(getIntf()), "rate", 1.);
|
|
}
|
|
|
|
- (void)toggleRecord
|
|
{
|
|
intf_thread_t *p_intf = getIntf();
|
|
if (!p_intf)
|
|
return;
|
|
|
|
input_thread_t * p_input;
|
|
p_input = pl_CurrentInput(p_intf);
|
|
if (p_input) {
|
|
var_ToggleBool(p_input, "record");
|
|
vlc_object_release(p_input);
|
|
}
|
|
}
|
|
|
|
- (void)setPlaybackRate:(int)i_value
|
|
{
|
|
playlist_t * p_playlist = pl_Get(getIntf());
|
|
|
|
double speed = pow(2, (double)i_value / 17);
|
|
int rate = INPUT_RATE_DEFAULT / speed;
|
|
if (i_currentPlaybackRate != rate)
|
|
var_SetFloat(p_playlist, "rate", (float)INPUT_RATE_DEFAULT / (float)rate);
|
|
i_currentPlaybackRate = rate;
|
|
}
|
|
|
|
- (int)playbackRate
|
|
{
|
|
float f_rate;
|
|
|
|
intf_thread_t *p_intf = getIntf();
|
|
if (!p_intf)
|
|
return 0;
|
|
|
|
input_thread_t * p_input;
|
|
p_input = pl_CurrentInput(p_intf);
|
|
if (p_input) {
|
|
f_rate = var_GetFloat(p_input, "rate");
|
|
vlc_object_release(p_input);
|
|
}
|
|
else
|
|
{
|
|
playlist_t * p_playlist = pl_Get(getIntf());
|
|
f_rate = var_GetFloat(p_playlist, "rate");
|
|
}
|
|
|
|
double value = 17 * log(f_rate) / log(2.);
|
|
int returnValue = (int) ((value > 0) ? value + .5 : value - .5);
|
|
|
|
if (returnValue < -34)
|
|
returnValue = -34;
|
|
else if (returnValue > 34)
|
|
returnValue = 34;
|
|
|
|
i_currentPlaybackRate = returnValue;
|
|
return returnValue;
|
|
}
|
|
|
|
- (void)previous
|
|
{
|
|
playlist_Prev(pl_Get(getIntf()));
|
|
}
|
|
|
|
- (void)next
|
|
{
|
|
playlist_Next(pl_Get(getIntf()));
|
|
}
|
|
|
|
- (int)durationOfCurrentPlaylistItem
|
|
{
|
|
intf_thread_t *p_intf = getIntf();
|
|
if (!p_intf)
|
|
return 0;
|
|
|
|
input_thread_t * p_input = pl_CurrentInput(p_intf);
|
|
int64_t i_duration = -1;
|
|
if (!p_input)
|
|
return i_duration;
|
|
|
|
input_Control(p_input, INPUT_GET_LENGTH, &i_duration);
|
|
vlc_object_release(p_input);
|
|
|
|
return (int)(i_duration / 1000000);
|
|
}
|
|
|
|
- (NSURL*)URLOfCurrentPlaylistItem
|
|
{
|
|
intf_thread_t *p_intf = getIntf();
|
|
if (!p_intf)
|
|
return nil;
|
|
|
|
input_thread_t *p_input = pl_CurrentInput(p_intf);
|
|
if (!p_input)
|
|
return nil;
|
|
|
|
input_item_t *p_item = input_GetItem(p_input);
|
|
if (!p_item) {
|
|
vlc_object_release(p_input);
|
|
return nil;
|
|
}
|
|
|
|
char *psz_uri = input_item_GetURI(p_item);
|
|
if (!psz_uri) {
|
|
vlc_object_release(p_input);
|
|
return nil;
|
|
}
|
|
|
|
NSURL *o_url;
|
|
o_url = [NSURL URLWithString:toNSStr(psz_uri)];
|
|
vlc_object_release(p_input);
|
|
|
|
return o_url;
|
|
}
|
|
|
|
- (NSString*)nameOfCurrentPlaylistItem
|
|
{
|
|
intf_thread_t *p_intf = getIntf();
|
|
if (!p_intf)
|
|
return nil;
|
|
|
|
input_thread_t *p_input = pl_CurrentInput(p_intf);
|
|
if (!p_input)
|
|
return nil;
|
|
|
|
input_item_t *p_item = input_GetItem(p_input);
|
|
if (!p_item) {
|
|
vlc_object_release(p_input);
|
|
return nil;
|
|
}
|
|
|
|
char *psz_uri = input_item_GetURI(p_item);
|
|
if (!psz_uri) {
|
|
vlc_object_release(p_input);
|
|
return nil;
|
|
}
|
|
|
|
NSString *o_name = @"";
|
|
char *format = var_InheritString(getIntf(), "input-title-format");
|
|
if (format) {
|
|
char *formated = str_format_meta(p_input, format);
|
|
free(format);
|
|
o_name = toNSStr(formated);
|
|
free(formated);
|
|
}
|
|
|
|
NSURL * o_url = [NSURL URLWithString:toNSStr(psz_uri)];
|
|
free(psz_uri);
|
|
|
|
if ([o_name isEqualToString:@""]) {
|
|
if ([o_url isFileURL])
|
|
o_name = [[NSFileManager defaultManager] displayNameAtPath:[o_url path]];
|
|
else
|
|
o_name = [o_url absoluteString];
|
|
}
|
|
vlc_object_release(p_input);
|
|
return o_name;
|
|
}
|
|
|
|
- (void)forward
|
|
{
|
|
//LEGACY SUPPORT
|
|
[self forwardShort];
|
|
}
|
|
|
|
- (void)backward
|
|
{
|
|
//LEGACY SUPPORT
|
|
[self backwardShort];
|
|
}
|
|
|
|
- (void)jumpWithValue:(char *)p_value forward:(BOOL)b_value
|
|
{
|
|
input_thread_t *p_input = pl_CurrentInput(getIntf());
|
|
if (!p_input)
|
|
return;
|
|
|
|
int i_interval = var_InheritInteger( p_input, p_value );
|
|
if (i_interval > 0) {
|
|
mtime_t val = CLOCK_FREQ * i_interval;
|
|
if (!b_value)
|
|
val = val * -1;
|
|
var_SetInteger( p_input, "time-offset", val );
|
|
}
|
|
vlc_object_release(p_input);
|
|
}
|
|
|
|
- (void)forwardExtraShort
|
|
{
|
|
[self jumpWithValue:"extrashort-jump-size" forward:YES];
|
|
}
|
|
|
|
- (void)backwardExtraShort
|
|
{
|
|
[self jumpWithValue:"extrashort-jump-size" forward:NO];
|
|
}
|
|
|
|
- (void)forwardShort
|
|
{
|
|
[self jumpWithValue:"short-jump-size" forward:YES];
|
|
}
|
|
|
|
- (void)backwardShort
|
|
{
|
|
[self jumpWithValue:"short-jump-size" forward:NO];
|
|
}
|
|
|
|
- (void)forwardMedium
|
|
{
|
|
[self jumpWithValue:"medium-jump-size" forward:YES];
|
|
}
|
|
|
|
- (void)backwardMedium
|
|
{
|
|
[self jumpWithValue:"medium-jump-size" forward:NO];
|
|
}
|
|
|
|
- (void)forwardLong
|
|
{
|
|
[self jumpWithValue:"long-jump-size" forward:YES];
|
|
}
|
|
|
|
- (void)backwardLong
|
|
{
|
|
[self jumpWithValue:"long-jump-size" forward:NO];
|
|
}
|
|
|
|
- (void)shuffle
|
|
{
|
|
intf_thread_t *p_intf = getIntf();
|
|
if (!p_intf)
|
|
return;
|
|
|
|
vlc_value_t val;
|
|
playlist_t * p_playlist = pl_Get(p_intf);
|
|
vout_thread_t *p_vout = getVout();
|
|
|
|
var_Get(p_playlist, "random", &val);
|
|
val.b_bool = !val.b_bool;
|
|
var_Set(p_playlist, "random", val);
|
|
if (val.b_bool) {
|
|
if (p_vout) {
|
|
vout_OSDMessage(p_vout, SPU_DEFAULT_CHANNEL, "%s", _("Random On"));
|
|
vlc_object_release(p_vout);
|
|
}
|
|
config_PutInt(p_playlist, "random", 1);
|
|
}
|
|
else
|
|
{
|
|
if (p_vout) {
|
|
vout_OSDMessage(p_vout, SPU_DEFAULT_CHANNEL, "%s", _("Random Off"));
|
|
vlc_object_release(p_vout);
|
|
}
|
|
config_PutInt(p_playlist, "random", 0);
|
|
}
|
|
}
|
|
|
|
- (void)repeatAll
|
|
{
|
|
intf_thread_t *p_intf = getIntf();
|
|
if (!p_intf)
|
|
return;
|
|
|
|
playlist_t * p_playlist = pl_Get(p_intf);
|
|
|
|
var_SetBool(p_playlist, "repeat", NO);
|
|
var_SetBool(p_playlist, "loop", YES);
|
|
config_PutInt(p_playlist, "repeat", NO);
|
|
config_PutInt(p_playlist, "loop", YES);
|
|
|
|
vout_thread_t *p_vout = getVout();
|
|
if (p_vout) {
|
|
vout_OSDMessage(p_vout, SPU_DEFAULT_CHANNEL, "%s", _("Repeat All"));
|
|
vlc_object_release(p_vout);
|
|
}
|
|
}
|
|
|
|
- (void)repeatOne
|
|
{
|
|
intf_thread_t *p_intf = getIntf();
|
|
if (!p_intf)
|
|
return;
|
|
|
|
playlist_t * p_playlist = pl_Get(p_intf);
|
|
|
|
var_SetBool(p_playlist, "repeat", YES);
|
|
var_SetBool(p_playlist, "loop", NO);
|
|
config_PutInt(p_playlist, "repeat", YES);
|
|
config_PutInt(p_playlist, "loop", NO);
|
|
|
|
vout_thread_t *p_vout = getVout();
|
|
if (p_vout) {
|
|
vout_OSDMessage(p_vout, SPU_DEFAULT_CHANNEL, "%s", _("Repeat One"));
|
|
vlc_object_release(p_vout);
|
|
}
|
|
}
|
|
|
|
- (void)repeatOff
|
|
{
|
|
intf_thread_t *p_intf = getIntf();
|
|
if (!p_intf)
|
|
return;
|
|
|
|
playlist_t * p_playlist = pl_Get(p_intf);
|
|
|
|
var_SetBool(p_playlist, "repeat", NO);
|
|
var_SetBool(p_playlist, "loop", NO);
|
|
config_PutInt(p_playlist, "repeat", NO);
|
|
config_PutInt(p_playlist, "loop", NO);
|
|
|
|
vout_thread_t *p_vout = getVout();
|
|
if (p_vout) {
|
|
vout_OSDMessage(p_vout, SPU_DEFAULT_CHANNEL, "%s", _("Repeat Off"));
|
|
vlc_object_release(p_vout);
|
|
}
|
|
}
|
|
|
|
- (void)setAtoB
|
|
{
|
|
if (!timeA) {
|
|
input_thread_t * p_input = pl_CurrentInput(getIntf());
|
|
if (p_input) {
|
|
timeA = var_GetInteger(p_input, "time");
|
|
vlc_object_release(p_input);
|
|
}
|
|
} else if (!timeB) {
|
|
input_thread_t * p_input = pl_CurrentInput(getIntf());
|
|
if (p_input) {
|
|
timeB = var_GetInteger(p_input, "time");
|
|
vlc_object_release(p_input);
|
|
}
|
|
} else
|
|
[self resetAtoB];
|
|
}
|
|
|
|
- (void)resetAtoB
|
|
{
|
|
timeA = 0;
|
|
timeB = 0;
|
|
}
|
|
|
|
- (void)updateAtoB
|
|
{
|
|
if (timeB) {
|
|
input_thread_t * p_input = pl_CurrentInput(getIntf());
|
|
if (p_input) {
|
|
mtime_t currentTime = var_GetInteger(p_input, "time");
|
|
if ( currentTime >= timeB || currentTime < timeA)
|
|
var_SetInteger(p_input, "time", timeA);
|
|
vlc_object_release(p_input);
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void)volumeUp
|
|
{
|
|
intf_thread_t *p_intf = getIntf();
|
|
if (!p_intf)
|
|
return;
|
|
|
|
playlist_VolumeUp(pl_Get(p_intf), 1, NULL);
|
|
}
|
|
|
|
- (void)volumeDown
|
|
{
|
|
intf_thread_t *p_intf = getIntf();
|
|
if (!p_intf)
|
|
return;
|
|
|
|
playlist_VolumeDown(pl_Get(p_intf), 1, NULL);
|
|
}
|
|
|
|
- (void)toggleMute
|
|
{
|
|
intf_thread_t *p_intf = getIntf();
|
|
if (!p_intf)
|
|
return;
|
|
|
|
playlist_MuteToggle(pl_Get(p_intf));
|
|
}
|
|
|
|
- (BOOL)mute
|
|
{
|
|
intf_thread_t *p_intf = getIntf();
|
|
if (!p_intf)
|
|
return NO;
|
|
|
|
BOOL b_is_muted = NO;
|
|
b_is_muted = playlist_MuteGet(pl_Get(p_intf)) > 0;
|
|
|
|
return b_is_muted;
|
|
}
|
|
|
|
- (int)volume
|
|
{
|
|
intf_thread_t *p_intf = getIntf();
|
|
if (!p_intf)
|
|
return 0;
|
|
|
|
float volume = playlist_VolumeGet(pl_Get(p_intf));
|
|
|
|
return lroundf(volume * AOUT_VOLUME_DEFAULT);
|
|
}
|
|
|
|
- (void)setVolume: (int)i_value
|
|
{
|
|
intf_thread_t *p_intf = getIntf();
|
|
if (!p_intf)
|
|
return;
|
|
|
|
if (i_value >= self.maxVolume)
|
|
i_value = self.maxVolume;
|
|
|
|
float f_value = i_value / (float)AOUT_VOLUME_DEFAULT;
|
|
|
|
playlist_VolumeSet(pl_Get(p_intf), f_value);
|
|
}
|
|
|
|
- (float)maxVolume
|
|
{
|
|
if (f_maxVolume == 0.) {
|
|
f_maxVolume = (float)var_InheritInteger(getIntf(), "macosx-max-volume") / 100. * AOUT_VOLUME_DEFAULT;
|
|
}
|
|
|
|
return f_maxVolume;
|
|
}
|
|
|
|
- (void)addSubtitlesToCurrentInput:(NSArray *)paths
|
|
{
|
|
input_thread_t * p_input = pl_CurrentInput(getIntf());
|
|
if (!p_input)
|
|
return;
|
|
|
|
NSUInteger count = [paths count];
|
|
|
|
for (int i = 0; i < count ; i++) {
|
|
const char *path = [[[paths objectAtIndex:i] path] UTF8String];
|
|
msg_Dbg(getIntf(), "loading subs from %s", path);
|
|
|
|
int i_result = input_AddSubtitleOSD(p_input, path, true, true);
|
|
if (i_result != VLC_SUCCESS)
|
|
msg_Warn(getIntf(), "unable to load subtitles from '%s'", path);
|
|
}
|
|
vlc_object_release(p_input);
|
|
}
|
|
|
|
- (void)showPosition
|
|
{
|
|
input_thread_t *p_input = pl_CurrentInput(getIntf());
|
|
if (p_input != NULL) {
|
|
vout_thread_t *p_vout = input_GetVout(p_input);
|
|
if (p_vout != NULL) {
|
|
var_SetInteger(getIntf()->p_libvlc, "key-action", ACTIONID_POSITION);
|
|
vlc_object_release(p_vout);
|
|
}
|
|
vlc_object_release(p_input);
|
|
}
|
|
}
|
|
|
|
#pragma mark - Drop support for files into the video, controls bar or drop box
|
|
|
|
- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender;
|
|
{
|
|
NSArray *items = [[[VLCMain sharedInstance] playlist] createItemsFromExternalPasteboard:[sender draggingPasteboard]];
|
|
|
|
if (items.count == 0)
|
|
return NO;
|
|
|
|
// Try to add file as a subtitle
|
|
input_thread_t *p_input = pl_CurrentInput(getIntf());
|
|
if (items.count == 1 && p_input) {
|
|
NSString *url = [[items firstObject] valueForKey:@"ITEM_URL"];
|
|
char *path = vlc_uri2path([url UTF8String]);
|
|
|
|
if (path) {
|
|
int i_result = input_AddSubtitleOSD(p_input, path, true, true);
|
|
free(path);
|
|
if (i_result == VLC_SUCCESS) {
|
|
vlc_object_release(p_input);
|
|
return YES;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (p_input)
|
|
vlc_object_release(p_input);
|
|
|
|
[[[VLCMain sharedInstance] playlist] addPlaylistItems:items];
|
|
return YES;
|
|
}
|
|
|
|
#pragma mark - video output stuff
|
|
|
|
- (void)setAspectRatioIsLocked:(BOOL)b_value
|
|
{
|
|
config_PutInt(getIntf(), "macosx-lock-aspect-ratio", b_value);
|
|
}
|
|
|
|
- (BOOL)aspectRatioIsLocked
|
|
{
|
|
return config_GetInt(getIntf(), "macosx-lock-aspect-ratio");
|
|
}
|
|
|
|
- (void)toggleFullscreen
|
|
{
|
|
intf_thread_t *p_intf = getIntf();
|
|
if (!p_intf)
|
|
return;
|
|
|
|
vout_thread_t *p_vout = getVoutForActiveWindow();
|
|
if (p_vout) {
|
|
BOOL b_fs = var_ToggleBool(p_vout, "fullscreen");
|
|
var_SetBool(pl_Get(p_intf), "fullscreen", b_fs);
|
|
vlc_object_release(p_vout);
|
|
} else { // e.g. lion fullscreen toggle
|
|
BOOL b_fs = var_ToggleBool(pl_Get(p_intf), "fullscreen");
|
|
[[[VLCMain sharedInstance] voutController] setFullscreen:b_fs forWindow:nil withAnimation:YES];
|
|
}
|
|
}
|
|
|
|
#pragma mark - uncommon stuff
|
|
|
|
- (BOOL)fixPreferences
|
|
{
|
|
NSMutableString * o_workString;
|
|
NSRange returnedRange;
|
|
NSRange fullRange;
|
|
BOOL b_needsRestart = NO;
|
|
|
|
#define fixpref(pref) \
|
|
o_workString = [[NSMutableString alloc] initWithFormat:@"%s", config_GetPsz(getIntf(), pref)]; \
|
|
if ([o_workString length] > 0) \
|
|
{ \
|
|
returnedRange = [o_workString rangeOfString:@"macosx" options: NSCaseInsensitiveSearch]; \
|
|
if (returnedRange.location != NSNotFound) \
|
|
{ \
|
|
if ([o_workString isEqualToString:@"macosx"]) \
|
|
[o_workString setString:@""]; \
|
|
fullRange = NSMakeRange(0, [o_workString length]); \
|
|
[o_workString replaceOccurrencesOfString:@":macosx" withString:@"" options: NSCaseInsensitiveSearch range: fullRange]; \
|
|
fullRange = NSMakeRange(0, [o_workString length]); \
|
|
[o_workString replaceOccurrencesOfString:@"macosx:" withString:@"" options: NSCaseInsensitiveSearch range: fullRange]; \
|
|
\
|
|
config_PutPsz(getIntf(), pref, [o_workString UTF8String]); \
|
|
b_needsRestart = YES; \
|
|
} \
|
|
}
|
|
|
|
fixpref("control");
|
|
fixpref("extraintf");
|
|
#undef fixpref
|
|
|
|
return b_needsRestart;
|
|
}
|
|
|
|
#pragma mark - video filter handling
|
|
|
|
- (const char *)getFilterType:(const char *)psz_name
|
|
{
|
|
module_t *p_obj = module_find(psz_name);
|
|
if (!p_obj) {
|
|
return NULL;
|
|
}
|
|
|
|
if (module_provides(p_obj, "video splitter")) {
|
|
return "video-splitter";
|
|
} else if (module_provides(p_obj, "video filter2")) {
|
|
return "video-filter";
|
|
} else if (module_provides(p_obj, "sub source")) {
|
|
return "sub-source";
|
|
} else if (module_provides(p_obj, "sub filter")) {
|
|
return "sub-filter";
|
|
} else {
|
|
msg_Err(getIntf(), "Unknown video filter type.");
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
- (void)setVideoFilter: (const char *)psz_name on:(BOOL)b_on
|
|
{
|
|
intf_thread_t *p_intf = getIntf();
|
|
if (!p_intf)
|
|
return;
|
|
char *psz_string, *psz_parser;
|
|
|
|
const char *psz_filter_type = [self getFilterType:psz_name];
|
|
if (!psz_filter_type) {
|
|
msg_Err(p_intf, "Unable to find filter module \"%s\".", psz_name);
|
|
return;
|
|
}
|
|
|
|
msg_Dbg(p_intf, "will set filter '%s'", psz_name);
|
|
|
|
|
|
psz_string = config_GetPsz(p_intf, psz_filter_type);
|
|
|
|
if (b_on) {
|
|
if (psz_string == NULL) {
|
|
psz_string = strdup(psz_name);
|
|
} else if (strstr(psz_string, psz_name) == NULL) {
|
|
char *psz_tmp = strdup([[NSString stringWithFormat: @"%s:%s", psz_string, psz_name] UTF8String]);
|
|
free(psz_string);
|
|
psz_string = psz_tmp;
|
|
}
|
|
} else {
|
|
if (!psz_string)
|
|
return;
|
|
|
|
psz_parser = strstr(psz_string, psz_name);
|
|
if (psz_parser) {
|
|
if (*(psz_parser + strlen(psz_name)) == ':') {
|
|
memmove(psz_parser, psz_parser + strlen(psz_name) + 1,
|
|
strlen(psz_parser + strlen(psz_name) + 1) + 1);
|
|
} else {
|
|
*psz_parser = '\0';
|
|
}
|
|
|
|
/* Remove trailing : : */
|
|
if (strlen(psz_string) > 0 && *(psz_string + strlen(psz_string) -1) == ':')
|
|
*(psz_string + strlen(psz_string) -1) = '\0';
|
|
} else {
|
|
free(psz_string);
|
|
return;
|
|
}
|
|
}
|
|
config_PutPsz(p_intf, psz_filter_type, psz_string);
|
|
|
|
/* Try to set on the fly */
|
|
if (!strcmp(psz_filter_type, "video-splitter")) {
|
|
playlist_t *p_playlist = pl_Get(p_intf);
|
|
var_SetString(p_playlist, psz_filter_type, psz_string);
|
|
} else {
|
|
vout_thread_t *p_vout = getVout();
|
|
if (p_vout) {
|
|
var_SetString(p_vout, psz_filter_type, psz_string);
|
|
vlc_object_release(p_vout);
|
|
}
|
|
}
|
|
|
|
free(psz_string);
|
|
}
|
|
|
|
- (void)restartFilterIfNeeded: (const char *)psz_filter option: (const char *)psz_name
|
|
{
|
|
vout_thread_t *p_vout = getVout();
|
|
intf_thread_t *p_intf = getIntf();
|
|
if (!p_intf)
|
|
return;
|
|
|
|
if (p_vout == NULL)
|
|
return;
|
|
else
|
|
vlc_object_release(p_vout);
|
|
|
|
vlc_object_t *p_filter = vlc_object_find_name(pl_Get(p_intf), psz_filter);
|
|
if (p_filter) {
|
|
|
|
/* we cannot rely on the p_filter existence.
|
|
This filter might be just
|
|
disabled, but the object still exists. Therefore, the string
|
|
is checked, additionally.
|
|
*/
|
|
const char *psz_filter_type = [self getFilterType:psz_filter];
|
|
if (!psz_filter_type) {
|
|
msg_Err(p_intf, "Unable to find filter module \"%s\".", psz_name);
|
|
goto out;
|
|
}
|
|
|
|
char *psz_string = config_GetPsz(p_intf, psz_filter_type);
|
|
if (!psz_string) {
|
|
goto out;
|
|
}
|
|
if (strstr(psz_string, psz_filter) == NULL) {
|
|
free(psz_string);
|
|
goto out;
|
|
}
|
|
free(psz_string);
|
|
|
|
int i_type;
|
|
i_type = var_Type(p_filter, psz_name);
|
|
if (i_type == 0)
|
|
i_type = config_GetType(p_intf, psz_name);
|
|
|
|
if (!(i_type & VLC_VAR_ISCOMMAND)) {
|
|
msg_Warn(p_intf, "Brute-restarting filter '%s', because the last changed option isn't a command", psz_name);
|
|
|
|
[self setVideoFilter: psz_filter on: NO];
|
|
[self setVideoFilter: psz_filter on: YES];
|
|
} else
|
|
msg_Dbg(p_intf, "restart not needed");
|
|
|
|
out:
|
|
vlc_object_release(p_filter);
|
|
}
|
|
}
|
|
|
|
- (void)setVideoFilterProperty: (const char *)psz_name forFilter: (const char *)psz_filter integer: (int)i_value
|
|
{
|
|
vout_thread_t *p_vout = getVout();
|
|
vlc_object_t *p_filter;
|
|
intf_thread_t *p_intf = getIntf();
|
|
if (!p_intf)
|
|
return;
|
|
|
|
config_PutInt(p_intf, psz_name, i_value);
|
|
|
|
if (p_vout) {
|
|
p_filter = vlc_object_find_name(pl_Get(p_intf), psz_filter);
|
|
|
|
if (!p_filter) {
|
|
msg_Warn(p_intf, "filter '%s' isn't enabled", psz_filter);
|
|
vlc_object_release(p_vout);
|
|
return;
|
|
}
|
|
var_SetInteger(p_filter, psz_name, i_value);
|
|
vlc_object_release(p_vout);
|
|
vlc_object_release(p_filter);
|
|
|
|
[self restartFilterIfNeeded: psz_filter option: psz_name];
|
|
}
|
|
}
|
|
|
|
- (void)setVideoFilterProperty: (const char *)psz_name forFilter: (const char *)psz_filter float: (float)f_value
|
|
{
|
|
vout_thread_t *p_vout = getVout();
|
|
vlc_object_t *p_filter;
|
|
intf_thread_t *p_intf = getIntf();
|
|
if (!p_intf)
|
|
return;
|
|
|
|
config_PutFloat(p_intf, psz_name, f_value);
|
|
|
|
if (p_vout) {
|
|
p_filter = vlc_object_find_name(pl_Get(p_intf), psz_filter);
|
|
|
|
if (!p_filter) {
|
|
msg_Warn(p_intf, "filter '%s' isn't enabled", psz_filter);
|
|
vlc_object_release(p_vout);
|
|
return;
|
|
}
|
|
var_SetFloat(p_filter, psz_name, f_value);
|
|
vlc_object_release(p_vout);
|
|
vlc_object_release(p_filter);
|
|
|
|
[self restartFilterIfNeeded: psz_filter option: psz_name];
|
|
}
|
|
}
|
|
|
|
- (void)setVideoFilterProperty: (const char *)psz_name forFilter: (const char *)psz_filter string: (const char *)psz_value
|
|
{
|
|
char *psz_new_value = strdup(psz_value);
|
|
vout_thread_t *p_vout = getVout();
|
|
vlc_object_t *p_filter;
|
|
intf_thread_t *p_intf = getIntf();
|
|
if (!p_intf)
|
|
return;
|
|
|
|
config_PutPsz(p_intf, psz_name, EnsureUTF8(psz_new_value));
|
|
|
|
if (p_vout) {
|
|
p_filter = vlc_object_find_name(pl_Get(p_intf), psz_filter);
|
|
|
|
if (!p_filter) {
|
|
msg_Warn(p_intf, "filter '%s' isn't enabled", psz_filter);
|
|
vlc_object_release(p_vout);
|
|
return;
|
|
}
|
|
var_SetString(p_filter, psz_name, EnsureUTF8(psz_new_value));
|
|
vlc_object_release(p_vout);
|
|
vlc_object_release(p_filter);
|
|
|
|
[self restartFilterIfNeeded: psz_filter option: psz_name];
|
|
}
|
|
|
|
free(psz_new_value);
|
|
}
|
|
|
|
- (void)setVideoFilterProperty: (const char *)psz_name forFilter: (const char *)psz_filter boolean: (BOOL)b_value
|
|
{
|
|
vout_thread_t *p_vout = getVout();
|
|
vlc_object_t *p_filter;
|
|
intf_thread_t *p_intf = getIntf();
|
|
if (!p_intf)
|
|
return;
|
|
|
|
config_PutInt(p_intf, psz_name, b_value);
|
|
|
|
if (p_vout) {
|
|
p_filter = vlc_object_find_name(pl_Get(p_intf), psz_filter);
|
|
|
|
if (!p_filter) {
|
|
msg_Warn(p_intf, "filter '%s' isn't enabled", psz_filter);
|
|
vlc_object_release(p_vout);
|
|
return;
|
|
}
|
|
var_SetBool(p_filter, psz_name, b_value);
|
|
vlc_object_release(p_vout);
|
|
vlc_object_release(p_filter);
|
|
}
|
|
}
|
|
|
|
#pragma mark -
|
|
#pragma mark Media Key support
|
|
|
|
- (void)resetMediaKeyJump
|
|
{
|
|
b_mediakeyJustJumped = NO;
|
|
}
|
|
|
|
- (void)coreChangedMediaKeySupportSetting: (NSNotification *)o_notification
|
|
{
|
|
intf_thread_t *p_intf = getIntf();
|
|
if (!p_intf)
|
|
return;
|
|
|
|
b_mediaKeySupport = var_InheritBool(p_intf, "macosx-mediakeys");
|
|
if (b_mediaKeySupport && !_mediaKeyController)
|
|
_mediaKeyController = [[SPMediaKeyTap alloc] initWithDelegate:self];
|
|
|
|
VLCMain *main = [VLCMain sharedInstance];
|
|
if (b_mediaKeySupport && ([[[main playlist] model] hasChildren] ||
|
|
[[main inputManager] hasInput])) {
|
|
if (!b_mediaKeyTrapEnabled) {
|
|
b_mediaKeyTrapEnabled = YES;
|
|
msg_Dbg(p_intf, "Enable media key support");
|
|
[_mediaKeyController startWatchingMediaKeys];
|
|
}
|
|
} else {
|
|
if (b_mediaKeyTrapEnabled) {
|
|
b_mediaKeyTrapEnabled = NO;
|
|
msg_Dbg(p_intf, "Disable media key support");
|
|
[_mediaKeyController stopWatchingMediaKeys];
|
|
}
|
|
}
|
|
}
|
|
|
|
-(void)mediaKeyTap:(SPMediaKeyTap*)keyTap receivedMediaKeyEvent:(NSEvent*)event
|
|
{
|
|
if (b_mediaKeySupport) {
|
|
assert([event type] == NSSystemDefined && [event subtype] == SPSystemDefinedEventMediaKeys);
|
|
|
|
int keyCode = (([event data1] & 0xFFFF0000) >> 16);
|
|
int keyFlags = ([event data1] & 0x0000FFFF);
|
|
int keyState = (((keyFlags & 0xFF00) >> 8)) == 0xA;
|
|
int keyRepeat = (keyFlags & 0x1);
|
|
|
|
if (keyCode == NX_KEYTYPE_PLAY && keyState == 0)
|
|
[self playOrPause];
|
|
|
|
if ((keyCode == NX_KEYTYPE_FAST || keyCode == NX_KEYTYPE_NEXT) && !b_mediakeyJustJumped) {
|
|
if (keyState == 0 && keyRepeat == 0)
|
|
[self next];
|
|
else if (keyRepeat == 1) {
|
|
[self forwardShort];
|
|
b_mediakeyJustJumped = YES;
|
|
[self performSelector:@selector(resetMediaKeyJump)
|
|
withObject: NULL
|
|
afterDelay:0.25];
|
|
}
|
|
}
|
|
|
|
if ((keyCode == NX_KEYTYPE_REWIND || keyCode == NX_KEYTYPE_PREVIOUS) && !b_mediakeyJustJumped) {
|
|
if (keyState == 0 && keyRepeat == 0)
|
|
[self previous];
|
|
else if (keyRepeat == 1) {
|
|
[self backwardShort];
|
|
b_mediakeyJustJumped = YES;
|
|
[self performSelector:@selector(resetMediaKeyJump)
|
|
withObject: NULL
|
|
afterDelay:0.25];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#pragma mark -
|
|
#pragma mark Apple Remote Control
|
|
|
|
- (void)startListeningWithAppleRemote
|
|
{
|
|
[_remote startListening: self];
|
|
}
|
|
|
|
- (void)stopListeningWithAppleRemote
|
|
{
|
|
[_remote stopListening:self];
|
|
}
|
|
|
|
/* Helper method for the remote control interface in order to trigger forward/backward and volume
|
|
increase/decrease as long as the user holds the left/right, plus/minus button */
|
|
- (void) executeHoldActionForRemoteButton: (NSNumber*) buttonIdentifierNumber
|
|
{
|
|
intf_thread_t *p_intf = getIntf();
|
|
if (!p_intf)
|
|
return;
|
|
|
|
if (b_remote_button_hold) {
|
|
switch([buttonIdentifierNumber intValue]) {
|
|
case kRemoteButtonRight_Hold:
|
|
[self forward];
|
|
break;
|
|
case kRemoteButtonLeft_Hold:
|
|
[self backward];
|
|
break;
|
|
case kRemoteButtonVolume_Plus_Hold:
|
|
if (p_intf)
|
|
var_SetInteger(p_intf->p_libvlc, "key-action", ACTIONID_VOL_UP);
|
|
break;
|
|
case kRemoteButtonVolume_Minus_Hold:
|
|
if (p_intf)
|
|
var_SetInteger(p_intf->p_libvlc, "key-action", ACTIONID_VOL_DOWN);
|
|
break;
|
|
}
|
|
if (b_remote_button_hold) {
|
|
/* trigger event */
|
|
[self performSelector:@selector(executeHoldActionForRemoteButton:)
|
|
withObject:buttonIdentifierNumber
|
|
afterDelay:0.25];
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Apple Remote callback */
|
|
- (void) appleRemoteButton: (AppleRemoteEventIdentifier)buttonIdentifier
|
|
pressedDown: (BOOL) pressedDown
|
|
clickCount: (unsigned int) count
|
|
{
|
|
intf_thread_t *p_intf = getIntf();
|
|
if (!p_intf)
|
|
return;
|
|
|
|
switch(buttonIdentifier) {
|
|
case k2009RemoteButtonFullscreen:
|
|
[self toggleFullscreen];
|
|
break;
|
|
case k2009RemoteButtonPlay:
|
|
[self playOrPause];
|
|
break;
|
|
case kRemoteButtonPlay:
|
|
if (count >= 2)
|
|
[self toggleFullscreen];
|
|
else
|
|
[self playOrPause];
|
|
break;
|
|
case kRemoteButtonVolume_Plus:
|
|
if (config_GetInt(getIntf(), "macosx-appleremote-sysvol"))
|
|
[NSSound increaseSystemVolume];
|
|
else
|
|
if (p_intf)
|
|
var_SetInteger(p_intf->p_libvlc, "key-action", ACTIONID_VOL_UP);
|
|
break;
|
|
case kRemoteButtonVolume_Minus:
|
|
if (config_GetInt(getIntf(), "macosx-appleremote-sysvol"))
|
|
[NSSound decreaseSystemVolume];
|
|
else
|
|
if (p_intf)
|
|
var_SetInteger(p_intf->p_libvlc, "key-action", ACTIONID_VOL_DOWN);
|
|
break;
|
|
case kRemoteButtonRight:
|
|
if (config_GetInt(getIntf(), "macosx-appleremote-prevnext"))
|
|
[self forward];
|
|
else
|
|
[self next];
|
|
break;
|
|
case kRemoteButtonLeft:
|
|
if (config_GetInt(getIntf(), "macosx-appleremote-prevnext"))
|
|
[self backward];
|
|
else
|
|
[self previous];
|
|
break;
|
|
case kRemoteButtonRight_Hold:
|
|
case kRemoteButtonLeft_Hold:
|
|
case kRemoteButtonVolume_Plus_Hold:
|
|
case kRemoteButtonVolume_Minus_Hold:
|
|
/* simulate an event as long as the user holds the button */
|
|
b_remote_button_hold = pressedDown;
|
|
if (pressedDown) {
|
|
NSNumber* buttonIdentifierNumber = [NSNumber numberWithInt:buttonIdentifier];
|
|
[self performSelector:@selector(executeHoldActionForRemoteButton:)
|
|
withObject:buttonIdentifierNumber];
|
|
}
|
|
break;
|
|
case kRemoteButtonMenu:
|
|
[self showPosition];
|
|
break;
|
|
case kRemoteButtonPlay_Sleep:
|
|
{
|
|
NSAppleScript * script = [[NSAppleScript alloc] initWithSource:@"tell application \"System Events\" to sleep"];
|
|
[script executeAndReturnError:nil];
|
|
break;
|
|
}
|
|
default:
|
|
/* Add here whatever you want other buttons to do */
|
|
break;
|
|
}
|
|
}
|
|
|
|
#pragma mark -
|
|
#pragma mark Key Shortcuts
|
|
|
|
/*****************************************************************************
|
|
* hasDefinedShortcutKey: Check to see if the key press is a defined VLC
|
|
* shortcut key. If it is, pass it off to VLC for handling and return YES,
|
|
* otherwise ignore it and return NO (where it will get handled by Cocoa).
|
|
*****************************************************************************/
|
|
|
|
- (BOOL)keyEvent:(NSEvent *)o_event
|
|
{
|
|
BOOL eventHandled = NO;
|
|
NSString * characters = [o_event charactersIgnoringModifiers];
|
|
if ([characters length] > 0) {
|
|
unichar key = [characters characterAtIndex: 0];
|
|
|
|
if (key) {
|
|
input_thread_t * p_input = pl_CurrentInput(getIntf());
|
|
if (p_input != NULL) {
|
|
vout_thread_t *p_vout = input_GetVout(p_input);
|
|
|
|
if (p_vout != NULL) {
|
|
/* Escape */
|
|
if (key == (unichar) 0x1b) {
|
|
if (var_GetBool(p_vout, "fullscreen")) {
|
|
[self toggleFullscreen];
|
|
eventHandled = YES;
|
|
}
|
|
}
|
|
vlc_object_release(p_vout);
|
|
}
|
|
vlc_object_release(p_input);
|
|
}
|
|
}
|
|
}
|
|
return eventHandled;
|
|
}
|
|
|
|
- (BOOL)hasDefinedShortcutKey:(NSEvent *)o_event force:(BOOL)b_force
|
|
{
|
|
intf_thread_t *p_intf = getIntf();
|
|
if (!p_intf)
|
|
return NO;
|
|
|
|
unichar key = 0;
|
|
vlc_value_t val;
|
|
unsigned int i_pressed_modifiers = 0;
|
|
|
|
val.i_int = 0;
|
|
i_pressed_modifiers = [o_event modifierFlags];
|
|
|
|
if (i_pressed_modifiers & NSControlKeyMask)
|
|
val.i_int |= KEY_MODIFIER_CTRL;
|
|
|
|
if (i_pressed_modifiers & NSAlternateKeyMask)
|
|
val.i_int |= KEY_MODIFIER_ALT;
|
|
|
|
if (i_pressed_modifiers & NSShiftKeyMask)
|
|
val.i_int |= KEY_MODIFIER_SHIFT;
|
|
|
|
if (i_pressed_modifiers & NSCommandKeyMask)
|
|
val.i_int |= KEY_MODIFIER_COMMAND;
|
|
|
|
NSString * characters = [o_event charactersIgnoringModifiers];
|
|
if ([characters length] > 0) {
|
|
key = [[characters lowercaseString] characterAtIndex: 0];
|
|
|
|
/* handle Lion's default key combo for fullscreen-toggle in addition to our own hotkeys */
|
|
if (key == 'f' && i_pressed_modifiers & NSControlKeyMask && i_pressed_modifiers & NSCommandKeyMask) {
|
|
[self toggleFullscreen];
|
|
return YES;
|
|
}
|
|
|
|
if (!b_force) {
|
|
switch(key) {
|
|
case NSDeleteCharacter:
|
|
case NSDeleteFunctionKey:
|
|
case NSDeleteCharFunctionKey:
|
|
case NSBackspaceCharacter:
|
|
case NSUpArrowFunctionKey:
|
|
case NSDownArrowFunctionKey:
|
|
case NSEnterCharacter:
|
|
case NSCarriageReturnCharacter:
|
|
return NO;
|
|
}
|
|
}
|
|
|
|
val.i_int |= CocoaKeyToVLC(key);
|
|
|
|
BOOL b_found_key = NO;
|
|
for (NSUInteger i = 0; i < [_usedHotkeys count]; i++) {
|
|
NSString *str = [_usedHotkeys objectAtIndex:i];
|
|
unsigned int i_keyModifiers = [[VLCStringUtility sharedInstance] VLCModifiersToCocoa: str];
|
|
|
|
if ([[characters lowercaseString] isEqualToString: [[VLCStringUtility sharedInstance] VLCKeyToString: str]] &&
|
|
(i_keyModifiers & NSShiftKeyMask) == (i_pressed_modifiers & NSShiftKeyMask) &&
|
|
(i_keyModifiers & NSControlKeyMask) == (i_pressed_modifiers & NSControlKeyMask) &&
|
|
(i_keyModifiers & NSAlternateKeyMask) == (i_pressed_modifiers & NSAlternateKeyMask) &&
|
|
(i_keyModifiers & NSCommandKeyMask) == (i_pressed_modifiers & NSCommandKeyMask)) {
|
|
b_found_key = YES;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (b_found_key) {
|
|
var_SetInteger(p_intf->p_libvlc, "key-pressed", val.i_int);
|
|
return YES;
|
|
}
|
|
}
|
|
|
|
return NO;
|
|
}
|
|
|
|
- (void)updateCurrentlyUsedHotkeys
|
|
{
|
|
NSMutableArray *mutArray = [[NSMutableArray alloc] init];
|
|
/* Get the main Module */
|
|
module_t *p_main = module_get_main();
|
|
assert(p_main);
|
|
unsigned confsize;
|
|
module_config_t *p_config;
|
|
|
|
p_config = module_config_get (p_main, &confsize);
|
|
|
|
for (size_t i = 0; i < confsize; i++) {
|
|
module_config_t *p_item = p_config + i;
|
|
|
|
if (CONFIG_ITEM(p_item->i_type) && p_item->psz_name != NULL
|
|
&& !strncmp(p_item->psz_name , "key-", 4)
|
|
&& !EMPTY_STR(p_item->psz_text)) {
|
|
if (p_item->value.psz)
|
|
[mutArray addObject:toNSStr(p_item->value.psz)];
|
|
}
|
|
}
|
|
module_config_free (p_config);
|
|
|
|
_usedHotkeys = [[NSArray alloc] initWithArray:mutArray copyItems:YES];
|
|
}
|
|
|
|
@end
|
|
|