Jump to content
Korean Random

[Заказ] Разделенный экран или Split screen


kharlashkin

Recommended Posts

@kharlashkin, Эх, я б вам помог, если бы знал пайтон... Но если будет необходимость в exe'шках и dll'ках, то пишите мне, я помогу.

Лучше поспрашивайте на форумах по пайтону. Я уверен, что среди програмистов должны быть любители танков.

  • Upvote 2
Link to comment
Short link
Share on other sites

@kharlashkin, Эх, я б вам помог, если бы знал пайтон... Но если будет необходимость в exe'шках и dll'ках, то пишите мне, я помогу.

Лучше поспрашивайте на форумах по пайтону. Я уверен, что среди програмистов должны быть любители танков.

Спасибо за поддержку . В принципе, по логике вещей, ответ где-то рядом.

 

Мое видение данного мода такое - таким же образом как в "вибромоде" вызываем системный python, с помощью pygame берем данные о нажатии кнопок/перемещении стиков, переназначаем их в соответствии с управлением в игре (я довольно долго экспериментировал с удобством игры на геймпаде - моя тема на оф.форуме), и отдаем команды непосредственно в игру. Вот с последним моментом пока проблема - ищу.

Edited by kharlashkin
  • Upvote 2
  • Downvote 1
Link to comment
Short link
Share on other sites

отдаем команды непосредственно в игру. Вот с последним моментом пока проблема

Быть может, что worldoftanks.exe сам обрабатывает нажатия кнопок.

Edited by Azbuka_slovensko
  • Upvote 2
Link to comment
Short link
Share on other sites

Быть может, что worldoftanks.exe сам обрабатывает нажатия кнопок.

Да пусть обрабатывает, нужно чтобы он правильно обрабатывал - нужные нажатия, а не все подряд.
  • Upvote 2
  • Downvote 1
Link to comment
Short link
Share on other sites

Скрипт SettingsInterface интересный, там все есть - обработка нажатий кнопок, настройки мыши. Публикую его полностью:

'SettingsInterface'

import sys
from functools import partial
import BigWorld
import itertools
import SoundGroups
import ResMgr
import ArenaType
from gui.Scaleform.daapi.view.lobby.settings.options import APPLY_METHOD
from helpers import i18n
from gui.Scaleform.managers.windows_stored_data import g_windowsStoredData
import nations
from account_helpers import gameplay_ctx
from account_helpers.SettingsCore import g_settingsCore
from gui import GUI_SETTINGS, g_guiResetters
from gui.BattleContext import g_battleContext
from gui.GraphicsPresets import GraphicsPresets
from gui.GraphicsResolutions import g_graficsResolutions
from gui.shared.utils.key_mapping import getScaleformKey
from gui.Scaleform import VoiceChatInterface
from windows import UIInterface
from debug_utils import LOG_DEBUG, LOG_NOTE, LOG_ERROR
from account_helpers.AccountSettings import AccountSettings
from post_processing import g_postProcessing
import CommandMapping
import Settings
from adisp import process
from gui.Scaleform.Waiting import Waiting
from Vibroeffects import VibroManager
from LogitechMonitor import LogitechMonitor
from helpers import getClientOverride

class SettingsInterface(UIInterface):
    KEYBOARD_MAPPING_COMMANDS = {'movement': {'forward': 'CMD_MOVE_FORWARD',
                  'backward': 'CMD_MOVE_BACKWARD',
                  'left': 'CMD_ROTATE_LEFT',
                  'right': 'CMD_ROTATE_RIGHT',
                  'auto_rotation': 'CMD_CM_VEHICLE_SWITCH_AUTOROTATION'},
     'cruis_control': {'forward': 'CMD_INCREMENT_CRUISE_MODE',
                       'backward': 'CMD_DECREMENT_CRUISE_MODE',
                       'stop_fire': 'CMD_STOP_UNTIL_FIRE'},
     'firing': {'fire': 'CMD_CM_SHOOT',
                'lock_target': 'CMD_CM_LOCK_TARGET',
                'lock_target_off': 'CMD_CM_LOCK_TARGET_OFF',
                'alternate_mode': 'CMD_CM_ALTERNATE_MODE',
                'reloadPartialClip': 'CMD_RELOAD_PARTIAL_CLIP'},
     'vehicle_other': {'showHUD': 'CMD_TOGGLE_GUI',
                       'showRadialMenu': 'CMD_RADIAL_MENU_SHOW'},
     'equipment': {'item01': 'CMD_AMMO_CHOICE_1',
                   'item02': 'CMD_AMMO_CHOICE_2',
                   'item03': 'CMD_AMMO_CHOICE_3',
                   'item04': 'CMD_AMMO_CHOICE_4',
                   'item05': 'CMD_AMMO_CHOICE_5',
                   'item06': 'CMD_AMMO_CHOICE_6',
                   'item07': 'CMD_AMMO_CHOICE_7',
                   'item08': 'CMD_AMMO_CHOICE_8'},
     'shortcuts': {'attack': 'CMD_CHAT_SHORTCUT_ATTACK',
                   'to_base': 'CMD_CHAT_SHORTCUT_BACKTOBASE',
                   'positive': 'CMD_CHAT_SHORTCUT_POSITIVE',
                   'negative': 'CMD_CHAT_SHORTCUT_NEGATIVE',
                   'help_me': 'CMD_CHAT_SHORTCUT_HELPME',
                   'reload': 'CMD_CHAT_SHORTCUT_RELOAD'},
     'camera': {'camera_up': 'CMD_CM_CAMERA_ROTATE_UP',
                'camera_down': 'CMD_CM_CAMERA_ROTATE_DOWN',
                'camera_left': 'CMD_CM_CAMERA_ROTATE_LEFT',
                'camera_right': 'CMD_CM_CAMERA_ROTATE_RIGHT'},
     'voicechat': {'pushToTalk': 'CMD_VOICECHAT_MUTE'},
     'logitech_keyboard': {'switch_view': 'CMD_LOGITECH_SWITCH_VIEW'},
     'minimap': {'sizeUp': 'CMD_MINIMAP_SIZE_UP',
                 'sizeDown': 'CMD_MINIMAP_SIZE_DOWN',
                 'visible': 'CMD_MINIMAP_VISIBLE'}}
    KEYBOARD_MAPPING_BLOCKS = {'movement': ('forward', 'backward', 'left', 'right', 'auto_rotation'),
     'cruis_control': ('forward', 'backward', 'stop_fire'),
     'firing': ('fire', 'lock_target', 'lock_target_off', 'alternate_mode', 'reloadPartialClip'),
     'vehicle_other': ('showHUD', 'showRadialMenu'),
     'equipment': ('item01', 'item02', 'item03', 'item04', 'item05', 'item06', 'item07', 'item08'),
     'shortcuts': ('attack', 'to_base', 'positive', 'negative', 'help_me', 'reload'),
     'camera': ('camera_up', 'camera_down', 'camera_left', 'camera_right'),
     'voicechat': ('pushToTalk',),
     'logitech_keyboard': ('switch_view',),
     'minimap': ('sizeUp', 'sizeDown', 'visible')}
    KEYBOARD_MAPPING_BLOCKS_ORDER = ('movement', 'cruis_control', 'firing', 'vehicle_other', 'equipment', 'shortcuts', 'camera', 'voicechat', 'minimap', 'logitech_keyboard')
    POPULATE_UI = 'SettingsDialog.PopulateUI'
    APPLY_SETTINGS = 'SettingsDialog.ApplySettings'
    COMMIT_SETTINGS = 'SettingsDialog.CommitSettings'
    DELAY_SETTINGS = 'SettingsDialog.DelaySettings'
    AUTODETECT_QUALITY = 'SettingsDialog.AutodetectQuality'
    CURSOR_VALUES = {'mixing': 3,
     'gunTag': 15,
     'centralTag': 14,
     'net': 4,
     'reloader': 0,
     'condition': 0,
     'cassette': 0,
     'reloaderTimer': 0}
    SNIPER_VALUES = {'snpMixing': 3,
     'snpGunTag': 6,
     'snpCentralTag': 14,
     'snpNet': 4,
     'snpReloader': 0,
     'snpCondition': 0,
     'snpCassette': 0,
     'snpReloaderTimer': 0}
    MARKER_VALUES = {'Hp': 4,
     'Name': 3}
    MARKER_TYPES = ['Base', 'Alt']
    MOUSE_KEYS = {'ingame': {'arcadeSens': ('arcade', 'sensitivity'),
                'sniperSens': ('sniper', 'sensitivity'),
                'artSens': ('strategic', 'sensitivity'),
                'horInvert': ('arcade', 'horzInvert'),
                'vertInvert': ('arcade', 'vertInvert'),
                'backDraftInvert': ('arcade', 'backDraftInvert')},
     'lobby': {'arcadeSens': ('arcadeMode/camera', 'sensitivity', 'float'),
               'sniperSens': ('sniperMode/camera', 'sensitivity', 'float'),
               'artSens': ('strategicMode/camera', 'sensitivity', 'float'),
               'horInvert': ('arcadeMode/camera', 'horzInvert', 'bool'),
               'vertInvert': ('arcadeMode/camera', 'vertInvert', 'bool'),
               'backDraftInvert': ('arcadeMode/camera', 'backDraftInvert', 'bool')},
     'default': {'arcadeSens': 1,
                 'sniperSens': 1,
                 'artSens': 1,
                 'horInvert': False,
                 'vertInvert': False,
                 'backDraftInvert': False}}
    GAMEPLAY_KEY_FORMAT = 'gameplay_{0:>s}'
    GAMEPLAY_PREFIX = 'gameplay_'

    def __init__(self, enableRedefineKeysMode = True):
        UIInterface.__init__(self)
        if not GUI_SETTINGS.minimapSize and self.KEYBOARD_MAPPING_BLOCKS.has_key('minimap'):
            del self.KEYBOARD_MAPPING_BLOCKS['minimap']
        self.__enableRedefineKeysMode = enableRedefineKeysMode
        self.graphicsPresets = GraphicsPresets()
        self.resolutions = g_graficsResolutions
        self.__currentSettings = None
        self.__settingsUI = None
        self.__altVoiceSetting = g_settingsCore.options.getSetting('alternativeVoices')
        if not GUI_SETTINGS.voiceChat and self.KEYBOARD_MAPPING_COMMANDS.has_key('voicechat'):
            if self.KEYBOARD_MAPPING_COMMANDS.has_key('voicechat'):
                del self.KEYBOARD_MAPPING_COMMANDS['voicechat']
            if self.KEYBOARD_MAPPING_BLOCKS.has_key('voicechat'):
                del self.KEYBOARD_MAPPING_BLOCKS['voicechat']
            self.KEYBOARD_MAPPING_BLOCKS_ORDER = list(self.KEYBOARD_MAPPING_BLOCKS_ORDER)
            del self.KEYBOARD_MAPPING_BLOCKS_ORDER[self.KEYBOARD_MAPPING_BLOCKS_ORDER.index('voicechat')]
            self.KEYBOARD_MAPPING_BLOCKS_ORDER = tuple(self.KEYBOARD_MAPPING_BLOCKS_ORDER)
        return

    def populateUI(self, proxy):
        UIInterface.populateUI(self, proxy)
        self.uiHolder.addExternalCallbacks({SettingsInterface.POPULATE_UI: self.onPopulateUI,
         SettingsInterface.APPLY_SETTINGS: self.onApplySettings,
         SettingsInterface.COMMIT_SETTINGS: self.onCommitSettings,
         SettingsInterface.DELAY_SETTINGS: self.onDelaySettings,
         SettingsInterface.AUTODETECT_QUALITY: self.onAutodetectSettings,
         'SettingsDialog.useRedifineKeysMode': self.onUseRedifineKeyMode,
         'SettingsDialog.processVivoxTest': self.onProcessVivoxTest,
         'SettingsDialog.voiceChatEnable': self.onVoiceChatEnable,
         'SettingsDialog.updateCaptureDevices': self.onUpdateCaptureDevices,
         'SettingsDialog.setVivoxMicVolume': self.onSetVivoxMicVolume,
         'SettingsDialog.killDialog': self.onDialogClose})
        VibroManager.g_instance.onConnect += self.__vm_onConnect
        VibroManager.g_instance.onDisconnect += self.__vm_onDisconnect
        g_guiResetters.add(self.onRecreateDevice)
        BigWorld.wg_setAdapterOrdinalNotifyCallback(self.onRecreateDevice)

    def dispossessUI(self):
        if self.__settingsUI:
            self.__settingsUI.script = None
            self.__settingsUI = None
        self.__altVoiceSetting = None
        self.uiHolder.removeExternalCallbacks(SettingsInterface.POPULATE_UI, SettingsInterface.APPLY_SETTINGS, SettingsInterface.COMMIT_SETTINGS, SettingsInterface.DELAY_SETTINGS, SettingsInterface.AUTODETECT_QUALITY, 'SettingsDialog.useRedifineKeysMode', 'SettingsDialog.processVivoxTest', 'SettingsDialog.voiceChatEnable', 'SettingsDialog.updateCaptureDevices', 'SettingsDialog.setVivoxMicVolume', 'SettingsDialog.killDialog')
        VibroManager.g_instance.onConnect -= self.__vm_onConnect
        VibroManager.g_instance.onDisconnect -= self.__vm_onDisconnect
        g_guiResetters.discard(self.onRecreateDevice)
        BigWorld.wg_setAdapterOrdinalNotifyCallback(None)
        UIInterface.dispossessUI(self)
        return

    def altVoicesPreview(self, soundMode):
        if not self.__altVoiceSetting.isOptionEnabled():
            return True
        if not g_battleContext.isInBattle:
            SoundGroups.g_instance.enableVoiceSounds(True)
        self.__altVoiceSetting.preview(soundMode)
        return self.__altVoiceSetting.playPreviewSound(self.uiHolder.soundManager)

    def isSoundModeValid(self, soundMode):
        self.__altVoiceSetting.preview(soundMode)
        valid = self.__altVoiceSetting.isSoundModeValid()
        self.__altVoiceSetting.revert()
        return valid

    def onSetVivoxMicVolume(self, callbackId, value):
        import VOIP
        if round(SoundGroups.g_instance.getVolume('micVivox') * 100) != value:
            SoundGroups.g_instance.setVolume('micVivox', value / 100)
            VOIP.getVOIPManager().setMicrophoneVolume(int(value))

    def onVoiceChatEnable(self, callbackId, isEnable):
        self.__voiceChatEnable(isEnable)

    def __voiceChatEnable(self, isEnable):
        if isEnable is None:
            return
        else:
            preveVoIP = Settings.g_instance.userPrefs.readBool(Settings.KEY_ENABLE_VOIP)
            import VOIP
            if preveVoIP != isEnable:
                VOIP.getVOIPManager().enable(isEnable)
                Settings.g_instance.userPrefs.writeBool(Settings.KEY_ENABLE_VOIP, bool(isEnable))
                from gui.WindowsManager import g_windowsManager
                if g_windowsManager.battleWindow is not None and not isEnable:
                    g_windowsManager.battleWindow.speakingPlayersReset()
                LOG_NOTE('Change state of voip: %s' % str(isEnable))
            return

    def __changeCaptureDevice(self, captureDeviceIdx):
        if captureDeviceIdx is None or captureDeviceIdx == -1:
            return
        else:
            import VOIP
            rh = VOIP.getVOIPManager()
            devices = [ i18n.encodeUtf8(device.decode(sys.getfilesystemencoding())) for device in rh.captureDevices ]
            if captureDeviceIdx < len(devices):
                newCaptureDevice = devices[captureDeviceIdx]
                previousDevice = Settings.g_instance.userPrefs.readString(Settings.KEY_VOIP_DEVICE)
                if previousDevice != newCaptureDevice:
                    Settings.g_instance.userPrefs.writeString(Settings.KEY_VOIP_DEVICE, newCaptureDevice)
                    LOG_NOTE('Change device of voip: %s' % str(newCaptureDevice))
            return

    def onUseRedifineKeyMode(self, callbackId, isUse):
        if self.__enableRedefineKeysMode:
            BigWorld.wg_setRedefineKeysMode(isUse)

    def onProcessVivoxTest(self, callbackId, isStart):
        LOG_DEBUG('Vivox test: %s' % str(isStart))
        import VOIP
        rh = VOIP.getVOIPManager()
        rh.enterTestChannel() if isStart else rh.leaveTestChannel()
        self.respond([callbackId, False])

    def __vm_onConnect(self):
        self.call('SettingsDialog.VibroManager.Connect')

    def __vm_onDisconnect(self):
        self.call('SettingsDialog.VibroManager.Disconnect')

    def __getVideoSettings(self):
        settings = {}
        settings['monitor'] = {'current': self.resolutions.monitorIndex,
         'real': self.resolutions.realMonitorIndex,
         'options': self.resolutions.monitorsList}
        settings['fullScreen'] = not self.resolutions.isVideoWindowed
        settings['windowSize'] = {'current': self.resolutions.windowSizeIndex,
         'options': self.resolutions.windowSizesList}
        settings['resolution'] = {'current': self.resolutions.videoModeIndex,
         'options': self.resolutions.videoModesList}
        return settings

    def __getSettings(self):
        settings = [self.graphicsPresets.getGraphicsPresetsData()]
        import VOIP
        rh = VOIP.getVOIPManager()
        g_windowsStoredData.start()
        vManager = VibroManager.g_instance
        vEffGroups = vManager.getGroupsSettings()
        vEffDefGroup = VibroManager.VibroManager.GroupSettings()
        vEffDefGroup.enabled = False
        vEffDefGroup.gain = 0
        markers = {'enemy': g_settingsCore.getSetting('enemy'),
         'dead': g_settingsCore.getSetting('dead'),
         'ally': g_settingsCore.getSetting('ally')}
        datetimeIdx = g_settingsCore.getSetting('showDateMessage') << 0 | g_settingsCore.getSetting('showTimeMessage') << 1
        config = {'locale': getClientOverride(),
         'aspectRatio': {'current': self.resolutions.aspectRatioIndex,
                         'options': self.resolutions.aspectRatiosList},
         'vertSync': self.resolutions.isVideoVSync,
         'tripleBuffered': self.resolutions.isTripleBuffered,
         'multisampling': {'current': self.resolutions.multisamplingTypeIndex,
                           'options': self.resolutions.multisamplingTypesList},
         'customAA': {'current': self.resolutions.customAAModeIndex,
                      'options': self.resolutions.customAAModesList},
         'gamma': self.resolutions.gamma,
         'masterVolume': round(SoundGroups.g_instance.getMasterVolume() * 100),
         'musicVolume': round(SoundGroups.g_instance.getVolume('music') * 100),
         'voiceVolume': round(SoundGroups.g_instance.getVolume('voice') * 100),
         'vehiclesVolume': round(SoundGroups.g_instance.getVolume('vehicles') * 100),
         'effectsVolume': round(SoundGroups.g_instance.getVolume('effects') * 100),
         'guiVolume': round(SoundGroups.g_instance.getVolume('gui') * 100),
         'ambientVolume': round(SoundGroups.g_instance.getVolume('ambient') * 100),
         'masterVivoxVolume': round(SoundGroups.g_instance.getVolume('masterVivox') * 100),
         'micVivoxVolume': round(SoundGroups.g_instance.getVolume('micVivox') * 100),
         'masterFadeVivoxVolume': round(SoundGroups.g_instance.getVolume('masterFadeVivox') * 100),
         'captureDevice': self.__getCaptureDeviceSettings(),
         'voiceChatNotSupported': rh.vivoxDomain == '' or not VoiceChatInterface.g_instance.ready,
         'datetimeIdx': datetimeIdx,
         'enableOlFilter': g_settingsCore.getSetting('enableOlFilter'),
         'enableSpamFilter': g_settingsCore.getSetting('enableSpamFilter'),
         'enableStoreChatMws': g_settingsCore.getSetting('enableStoreMws'),
         'enableStoreChatCws': g_settingsCore.getSetting('enableStoreCws'),
         'invitesFromFriendsOnly': g_settingsCore.getSetting('invitesFromFriendsOnly'),
         'storeReceiverInBattle': g_settingsCore.getSetting('storeReceiverInBattle'),
         'disableBattleChat': g_settingsCore.getSetting('disableBattleChat'),
         'dynamicCamera': g_settingsCore.getSetting('dynamicCamera'),
         'horStabilizationSnp': g_settingsCore.getSetting('horStabilizationSnp'),
         'enableVoIP': VOIP.getVOIPManager().channelsMgr.enabled,
         'enablePostMortemEffect': g_settingsCore.getSetting('enablePostMortemEffect'),
         'enablePostMortemDelay': g_settingsCore.getSetting('enablePostMortemDelay'),
         'nationalVoices': AccountSettings.getSettings('nationalVoices'),
         'isColorBlind': AccountSettings.getSettings('isColorBlind'),
         'useServerAim': g_settingsCore.getSetting('useServerAim'),
         'showVehiclesCounter': g_settingsCore.getSetting('showVehiclesCounter'),
         'minimapAlpha': g_settingsCore.getSetting('minimapAlpha'),
         'vibroIsConnected': vManager.connect(),
         'vibroGain': vManager.getGain() * 100,
         'vibroEngine': vEffGroups.get('engine', vEffDefGroup).gain * 100,
         'vibroAcceleration': vEffGroups.get('acceleration', vEffDefGroup).gain * 100,
         'vibroShots': vEffGroups.get('shots', vEffDefGroup).gain * 100,
         'vibroHits': vEffGroups.get('hits', vEffDefGroup).gain * 100,
         'vibroCollisions': vEffGroups.get('collisions', vEffDefGroup).gain * 100,
         'vibroDamage': vEffGroups.get('damage', vEffDefGroup).gain * 100,
         'vibroGUI': vEffGroups.get('gui', vEffDefGroup).gain * 100,
         'ppShowLevels': g_settingsCore.getSetting('ppShowLevels'),
         'ppShowTypes': AccountSettings.getSettings('players_panel')['showTypes'],
         'replayEnabled': g_settingsCore.options.getSetting('replayEnabled').pack(),
         'fpsPerfomancer': g_settingsCore.getSetting('fpsPerfomancer'),
         'arcade': {'values': g_settingsCore.options.getSetting('arcade').toAccountSettings(),
                    'options': SettingsInterface.CURSOR_VALUES},
         'sniper': {'values': g_settingsCore.options.getSetting('sniper').toAccountSettings(),
                    'options': SettingsInterface.SNIPER_VALUES},
         'markers': {'values': markers,
                     'options': SettingsInterface.MARKER_VALUES,
                     'types': SettingsInterface.MARKER_TYPES}}
        if self.__altVoiceSetting.isOptionEnabled():
            altVoices = []
            for idx, desc in enumerate(self.__altVoiceSetting.getOptions()):
                altVoices.append({'data': idx,
                 'label': desc})

            config['alternativeVoices'] = {'current': self.__altVoiceSetting.get(),
             'options': altVoices}
        for name in ('ctf', 'domination', 'assault', 'nations'):
            key = self.GAMEPLAY_KEY_FORMAT.format(name)
            config[key] = g_settingsCore.getSetting(key)

        settings.append(config)
        if not LogitechMonitor.isPresentColor():
            if self.KEYBOARD_MAPPING_BLOCKS.has_key('logitech_keyboard'):
                del self.KEYBOARD_MAPPING_BLOCKS['logitech_keyboard']
        else:
            self.KEYBOARD_MAPPING_BLOCKS['logitech_keyboard'] = ('switch_view',)
        cmdMap = CommandMapping.g_instance
        defaults = cmdMap.getDefaults()
        keyboard = []
        for group_name in self.KEYBOARD_MAPPING_BLOCKS_ORDER:
            if group_name in self.KEYBOARD_MAPPING_BLOCKS.keys():
                group = {'id': group_name,
                 'commands': []}
                keyboard.append(group)
                for key_setting in self.KEYBOARD_MAPPING_BLOCKS[group_name]:
                    command = cmdMap.getCommand(self.KEYBOARD_MAPPING_COMMANDS[group_name][key_setting])
                    keyCode = cmdMap.get(self.KEYBOARD_MAPPING_COMMANDS[group_name][key_setting])
                    defaultCode = defaults[command] if defaults.has_key(command) else 0
                    key = {'id': key_setting,
                     'command': command,
                     'key': getScaleformKey(keyCode),
                     'keyDefault': getScaleformKey(defaultCode)}
                    group['commands'].append(key)

        settings.append(keyboard)
        mouse = {}
        player = BigWorld.player()
        if hasattr(player.inputHandler, 'ctrls'):
            for key, path in SettingsInterface.MOUSE_KEYS['ingame'].items():
                if key == 'horInvert':
                    value = g_settingsCore.getSetting('mouseHorzInvert')
                elif key == 'vertInvert':
                    value = g_settingsCore.getSetting('mouseVertInvert')
                elif key == 'backDraftInvert':
                    value = g_settingsCore.getSetting('backDraftInvert')
                else:
                    value = player.inputHandler.ctrls[path[0]].camera.getUserConfigValue(path[1])
                mouse[key] = {'defaultValue': SettingsInterface.MOUSE_KEYS['default'][key],
                 'value': value}

        else:
            ds = Settings.g_instance.userPrefs[Settings.KEY_CONTROL_MODE]
            for key, path in SettingsInterface.MOUSE_KEYS['lobby'].items():
                default = SettingsInterface.MOUSE_KEYS['default'][key]
                value = default
                if key == 'horInvert':
                    value = g_settingsCore.getSetting('mouseHorzInvert')
                elif key == 'vertInvert':
                    value = g_settingsCore.getSetting('mouseVertInvert')
                elif key == 'backDraftInvert':
                    value = g_settingsCore.getSetting('backDraftInvert')
                elif ds is not None:
                    if path[2] == 'float':
                        value = ds[path[0]].readFloat(path[1], default)
                    elif path[2] == 'bool':
                        value = ds[path[0]].readBool(path[1], default)
                    else:
                        LOG_DEBUG('Unknown mouse settings type %s %s' % (key, path))
                mouse[key] = {'defaultValue': default,
                 'value': value}

        settings.append(mouse)
        g_windowsStoredData.stop()
        return settings

    def __getCaptureDeviceSettings(self):
        import VOIP
        rh = VOIP.getVOIPManager()
        devices = [ i18n.encodeUtf8(device.decode(sys.getfilesystemencoding())) for device in rh.captureDevices ]
        currentDeviceName = Settings.g_instance.userPrefs.readString(Settings.KEY_VOIP_DEVICE)
        currentCaptureDeviceIdx = -1
        try:
            currentCaptureDeviceIdx = devices.index(currentDeviceName)
        except:
            try:
                currentCaptureDeviceIdx = rh.captureDevices.index(rh.currentCaptureDevice)
            except:
                pass

        settings = {'current': currentCaptureDeviceIdx,
         'options': devices}
        return settings

    def onUpdateCaptureDevices(self, callbackId):
        self.__updateCaptureDevices()

    @process
    def __updateCaptureDevices(self):
        Waiting.show('__updateCaptureDevices')
        devices = yield VoiceChatInterface.g_instance.requestCaptureDevices()
        currentDeviceName = Settings.g_instance.userPrefs.readString(Settings.KEY_VOIP_DEVICE)
        currentCaptureDeviceIdx = -1
        try:
            currentCaptureDeviceIdx = devices.index(currentDeviceName)
        except Exception:
            try:
                import VOIP
                currentCaptureDeviceIdx = devices.index(VOIP.getVOIPManager().currentCaptureDevice)
            except Exception:
                pass

        value = [currentCaptureDeviceIdx]
        value.extend([ i18n.encodeUtf8(d.decode(sys.getfilesystemencoding())) for d in devices ])
        Waiting.hide('__updateCaptureDevices')
        self.call('SettingsDialog.updateCaptureDevices', value)

    def onRecreateDevice(self):
        if self.__settingsUI:
            if self.__currentSettings and self.__currentSettings != self.__getVideoSettings():
                self.__currentSettings = self.__getVideoSettings()
                self.__settingsUI.buildGraphicsData(self.__getVideoSettings())

    def onAutodetectSettings(self, callbackID):
        presetIndex = BigWorld.autoDetectGraphicsSettings()
        self.call('SettingsDialog.setPreset', [presetIndex])

    def onPopulateUI(self, *args):
        self.graphicsPresets.checkCurrentPreset(True)
        self.__currentSettings = self.__getVideoSettings()
        VoiceChatInterface.g_instance.processFailedMessage()
        if self.__settingsUI:
            self.__settingsUI.script = None
            self.__settingsUI = None
        settingsDialogName = args[1]
        self.__settingsUI = self.uiHolder.getMember(settingsDialogName)
        if self.__settingsUI:
            settings = self.__getSettings()
            self.__settingsUI.buildData(settings[0], settings[1], settings[2], settings[3])
            self.__settingsUI.buildGraphicsData(self.__getVideoSettings())
            self.__settingsUI.script = self
        else:
            LOG_ERROR('settingsDialog is not found in flash by name {0}'.format(settingsDialogName))
        return

    def onApplySettings(self, callbackId, settings):
        monitorIndex, presetIndex, settingsList, fullscreen = settings
        if (not self.resolutions.isVideoWindowed or fullscreen) and (monitorIndex != self.resolutions.realMonitorIndex or self.resolutions.monitorChanged):
            self.call('SettingsDialog.ApplySettings', ['restartNeeded'])
            return
        applyMethod = g_settingsCore.options.getApplyMethod(settingsList)
        method = 'apply'
        if applyMethod == APPLY_METHOD.RESTART:
            method = 'restartNeeded'
        elif applyMethod == APPLY_METHOD.DELAYED:
            method = 'hasPendingSettings'
        self.call('SettingsDialog.ApplySettings', [method])

    def onDelaySettings(self, *args):
        self.apply(False, *args)

    def onCommitSettings(self, *args):
        self.apply(True, *args)

    def apply(self, restartApproved, callbackId, settings):
        restartClient = False
        import VOIP
        ppSettings = dict(AccountSettings.getSettings('players_panel'))
        ppSettings['showTypes'] = settings['ppShowTypes']
        if (not self.resolutions.isVideoWindowed or settings['fullScreen']) and (settings['monitor'] != self.resolutions.realMonitorIndex or self.resolutions.monitorChanged):
            restartClient = True
        AccountSettings.setSettings('players_panel', ppSettings)
        g_settingsCore.applySetting('ppShowLevels', settings['ppShowLevels'])
        g_settingsCore.applySetting('replayEnabled', settings['replayEnabled'])
        g_settingsCore.applySetting('fpsPerfomancer', settings['fpsPerfomancer'])
        AccountSettings.setSettings('nationalVoices', settings['nationalVoices'])
        AccountSettings.setSettings('isColorBlind', settings['isColorBlind'])
        g_settingsCore.applySetting('useServerAim', settings['useServerAim'])
        g_settingsCore.applySetting('showVehiclesCounter', settings['showVehiclesCounter'])
        g_settingsCore.applySetting('minimapAlpha', settings['minimapAlpha'])
        arcade = g_settingsCore.options.getSetting('arcade').fromAccountSettings(settings['arcade'])
        sniper = g_settingsCore.options.getSetting('sniper').fromAccountSettings(settings['sniper'])
        g_settingsCore.applySetting('arcade', arcade)
        g_settingsCore.applySetting('sniper', sniper)
        g_settingsCore.applySetting('enemy', settings['markers']['enemy'])
        g_settingsCore.applySetting('dead', settings['markers']['dead'])
        g_settingsCore.applySetting('ally', settings['markers']['ally'])
        g_settingsCore.applySetting('dynamicCamera', settings['dynamicCamera'])
        g_settingsCore.applySetting('horStabilizationSnp', settings['horStabilizationSnp'])
        if self.__altVoiceSetting.isOptionEnabled():
            altVoices = settings.get('alternativeVoices')
            if altVoices is not None:
                self.__altVoiceSetting.apply(altVoices)
        vManager = VibroManager.g_instance
        vManager.setGain(settings['vibroGain'] / 100.0)
        vEffGroups = vManager.getGroupsSettings()
        for groupName, newValue in [('engine', settings['vibroEngine']),
         ('acceleration', settings['vibroAcceleration']),
         ('shots', settings['vibroShots']),
         ('hits', settings['vibroHits']),
         ('collisions', settings['vibroCollisions']),
         ('damage', settings['vibroDamage']),
         ('gui', settings['vibroGUI'])]:
            if groupName in vEffGroups:
                vEffGroups[groupName].gain = newValue / 100.0
                vEffGroups[groupName].enabled = newValue > 0

        vManager.setGroupsSettings(vEffGroups)
        self.__voiceChatEnable(settings['enableVoIP'])
        self.__changeCaptureDevice(settings[Settings.KEY_VOIP_DEVICE])
        g_settingsCore.applySetting('enablePostMortemEffect', settings['enablePostMortemEffect'])
        g_settingsCore.applySetting('enablePostMortemDelay', settings['enablePostMortemDelay'])
        self.uiHolder.clearCommands()
        keyboard = settings['controls']['keyboard']
        keyboardMapping = {}
        keysLayout = dict(g_settingsCore.options.getSetting('keyboard').KEYS_LAYOUT)
        layout = list(itertools.chain(*keysLayout.values()))
        for i in xrange(len(self.KEYBOARD_MAPPING_BLOCKS)):
            group_name = keyboard[i]['id']
            for j in xrange(len(self.KEYBOARD_MAPPING_BLOCKS[group_name])):
                key_name = keyboard[i]['commands'][j]['id']
                value = keyboard[i]['commands'][j]['key']
                cmd = self.KEYBOARD_MAPPING_COMMANDS[group_name][key_name]
                for item in layout:
                    key, command = item[0], item[1]
                    if command == cmd:
                        keyboardMapping[key] = value
                        break

        g_settingsCore.applySetting('keyboard', keyboardMapping)
        self.uiHolder.bindCommands()
        player = BigWorld.player()
        mouse = settings['controls']['mouse']
        if hasattr(player.inputHandler, 'ctrls'):
            player.inputHandler.ctrls['arcade'].camera.setUserConfigValue('sensitivity', mouse['arcadeSens']['value'])
            player.inputHandler.ctrls['sniper'].camera.setUserConfigValue('sensitivity', mouse['sniperSens']['value'])
            player.inputHandler.ctrls['strategic'].camera.setUserConfigValue('sensitivity', mouse['artSens']['value'])
        else:
            ds = Settings.g_instance.userPrefs[Settings.KEY_CONTROL_MODE]
            if ds:
                ds['arcadeMode/camera'].writeFloat('sensitivity', mouse['arcadeSens']['value'])
                ds['sniperMode/camera'].writeFloat('sensitivity', mouse['sniperSens']['value'])
                ds['strategicMode/camera'].writeFloat('sensitivity', mouse['artSens']['value'])
        g_settingsCore.applySetting('mouseHorzInvert', bool(mouse['horInvert']['value']))
        g_settingsCore.applySetting('mouseVertInvert', bool(mouse['vertInvert']['value']))
        g_settingsCore.applySetting('backDraftInvert', bool(mouse['backDraftInvert']['value']))
        self.resolutions.applyChanges(settings['fullScreen'], settings['vertSync'], settings['tripleBuffered'], settings['windowSize'] if not settings['fullScreen'] else settings['resolution'], settings['aspectRatio'], settings['multisampling'], settings['customAA'], settings['gamma'], settings['monitor'])
        if round(SoundGroups.g_instance.getVolume('masterVivox') * 100) != settings['masterVivoxVolume']:
            VOIP.getVOIPManager().setMasterVolume(settings['masterVivoxVolume'])
        if round(SoundGroups.g_instance.getVolume('micVivox') * 100) != settings['micVivoxVolume']:
            VOIP.getVOIPManager().setMicrophoneVolume(settings['micVivoxVolume'])
        SoundGroups.g_instance.setMasterVolume(float(settings['masterVolume']) / 100)
        SoundGroups.g_instance.setVolume('music', float(settings['musicVolume']) / 100)
        SoundGroups.g_instance.setVolume('voice', float(settings['voiceVolume']) / 100)
        SoundGroups.g_instance.setVolume('vehicles', float(settings['vehiclesVolume']) / 100)
        SoundGroups.g_instance.setVolume('effects', float(settings['effectsVolume']) / 100)
        SoundGroups.g_instance.setVolume('gui', float(settings['guiVolume']) / 100)
        SoundGroups.g_instance.setVolume('ambient', float(settings['ambientVolume']) / 100)
        SoundGroups.g_instance.setVolume('masterVivox', float(settings['masterVivoxVolume']) / 100)
        SoundGroups.g_instance.setVolume('micVivox', float(settings['micVivoxVolume']) / 100)
        SoundGroups.g_instance.setVolume('masterFadeVivox', float(settings['masterFadeVivoxVolume']) / 100)
        if len(VOIP.getVOIPManager().captureDevices):
            device = VOIP.getVOIPManager().captureDevices[0]
            if len(VOIP.getVOIPManager().captureDevices) > settings['captureDevice']:
                device = VOIP.getVOIPManager().captureDevices[settings['captureDevice']]
            VOIP.getVOIPManager().setCaptureDevice(device)
        g_settingsCore.applySetting('showDateMessage', settings['datetimeIdx'] & 1)
        g_settingsCore.applySetting('showTimeMessage', settings['datetimeIdx'] & 2)
        g_settingsCore.applySetting('enableOlFilter', settings['enableOlFilter'])
        g_settingsCore.applySetting('enableSpamFilter', settings['enableSpamFilter'])
        g_windowsStoredData.start()
        g_settingsCore.applySetting('enableStoreMws', settings['enableStoreChatMws'])
        g_settingsCore.applySetting('enableStoreCws', settings['enableStoreChatCws'])
        g_windowsStoredData.stop()
        g_settingsCore.applySetting('invitesFromFriendsOnly', settings['invitesFromFriendsOnly'])
        g_settingsCore.applySetting('storeReceiverInBattle', settings['storeReceiverInBattle'])
        g_settingsCore.applySetting('disableBattleChat', settings['disableBattleChat'])
        gameplayKeys = filter(lambda item: item.startswith(self.GAMEPLAY_PREFIX), settings.keys())
        for key in gameplayKeys:
            g_settingsCore.applySetting(key, settings[key])

        qualitySettings = settings['quality']
        applyMethod = g_settingsCore.options.getApplyMethod(qualitySettings)
        for key in GraphicsPresets.GRAPHICS_QUALITY_SETTINGS:
            value = qualitySettings.get(key)
            if value is not None:
                g_settingsCore.applySetting(key, value)

        if applyMethod == APPLY_METHOD.RESTART:
            BigWorld.commitPendingGraphicsSettings()
            restartClient = True
        elif applyMethod == APPLY_METHOD.DELAYED:
            BigWorld.commitPendingGraphicsSettings()
        g_settingsCore.applyStorages()
        g_postProcessing.refresh()
        if restartClient:
            BigWorld.savePreferences()
            if restartApproved:
                from BattleReplay import g_replayCtrl
                if g_replayCtrl.isPlaying and g_replayCtrl.playbackSpeed == 0:
                    g_replayCtrl.setPlaybackSpeedIdx(5)
                BigWorld.callback(0.3, BigWorld.restartGame)
            else:
                BigWorld.callback(0.0, partial(BigWorld.changeVideoMode, -1, BigWorld.isVideoWindowed()))
        return

    def onDialogClose(self, _):
        if self.__altVoiceSetting.isOptionEnabled():
            self.__altVoiceSetting.revert()
        if not g_battleContext.isInBattle:
            SoundGroups.g_instance.enableVoiceSounds(False)
        elif hasattr(BigWorld.player(), 'vehicle'):
            SoundGroups.g_instance.soundModes.setCurrentNation(nations.NAMES[BigWorld.player().vehicle.typeDescriptor.type.id[0]])
        g_settingsCore.clearStorages()
        if self.__settingsUI:
            self.__settingsUI.script = None
            self.__settingsUI = None
        return 

В этом сообщении уважаемый sirmax, говорил о добавлении отдельных методов, не трогая оригинальные скрипты. Возможно сюда стоит добавить метод который будет брать значения кнопок/стиков/триггеров и предоставлять их как кнопки клавиатуры/мыши.

  • Upvote 1
  • Downvote 1
Link to comment
Short link
Share on other sites

На просторах интернета нашел вот такую вещь.

Multiзапуск

Если не внимательно читали, то проблем с запуском двух клиентов WoT у меня нет. Но все равно спасибо!

 

Кстати, пришел к одному выводу - можно попробовать сделать это все "малой кровью". Относительно вывода двух окон было сообщение в самом начале (цена вопроса 35$), все управление вторым танком можно повесить на клавиатуру (без мыши), кнопок на клавиатуре больше чем в игре используется - хватит, Xpadder поддерживает одновременно много геймпадов, мод вибрации перепишу специально для второго экземпляра игры - второй геймпад.

 

В итоге можно сказать, что проблема решена. По моему мнению, это корявое и временное решение все равно надо опробовать - по результатам отпишусь.

  • Upvote 1
  • Downvote 1
Link to comment
Short link
Share on other sites

Убил вечер, но есть некоторые результаты которыми стоит поделиться. Ниже скриншот успехов ;)

 

post-19155-0-56900700-1395692862_thumb.jpg

 

Итак по порядку.

1. Огромная благодарность уважаемому inj3ct0r - подсказал как разделить вибрацию от каждой копии игры на два геймпада. Сделал два мода, каждый из них висят на разных портах и отдают вибрации в 1-й и 2-й геймпад (в Xinput 0-й и 1-й).

2. С помощью Vitrual Display Manager разделил экран на два "виртуальных". Должен сказать, что решение очень кривое и при первой же возможности надо уйти от него.

3. В Sandboxie запустил второй клиент WoT и покатался в тренировочном бою сам с собой.

 

К сожалению, дело к ночи - к тому же для полноценной пробы нужен второй "фанатик" (типа меня). В связи с этим управление пока не настраивал - надо к этому серьезно подойти.

 

На правой половине сриншота видны очень интересные настройки (разрешение 800х600 и выше). При чем они высвечиваются всегда и при запущенном Vitrual Display Manager даже применяются, но при выборе их в обычном режиме разрешение сбрасывается в 1024х768.

Я так думаю что это последствия добавления прямых значений в скрипты "X:\Games\World_of_Tanks\res\scripts\client\gui\graphicsresolutions.pyc" и "X:\Games\World_of_Tanks\res\scripts\client\gui\shared\utils\graphics.pyc" путем тупого компилирования и замены констант. Соответственно копать в ту сторону буду.

Edited by kharlashkin
  • Upvote 1
  • Downvote 1
Link to comment
Short link
Share on other sites

Пока не нашел в скриптах где-то ещё изменение минимального разрешения. Выкладываю тут скрипты снова (с измененными минимальными значениями):

'X:\Games\World_of_Tanks\res\scripts\client\gui\graphicsresolutions.pyc'

import BigWorld
from debug_utils import LOG_CURRENT_EXCEPTION, LOG_ERROR, LOG_DEBUG

class GraphicsResolutions(object):
    MIN_HEIGHT = 600
    MIN_WIDTH = 800
    MIN_COLOR_DEPTH = 23

    def __gcd(self, a, b):
        while a != 0:
            a, b = b % a, a

        return b

    def __init__(self):
        self.__allVideoModes = []
        maxWidth = 0
        maxHeight = 0
        self.ASPECT_RATIO = []
        self.ASPECT_RATIO.append((4, 3))
        self.ASPECT_RATIO.append((16, 9))
        self.ASPECT_RATIO.append((16, 10))
        self.ASPECT_RATIO.append((19, 10))
        for monitorModes in BigWorld.listVideoModesAllMonitors():
            modes = []
            for mode in monitorModes:
                if self.__isVideoModeSuitable(mode):
                    modes.append(mode)
                    if mode[1] > maxWidth:
                        maxWidth = mode[1]
                    if mode[2] > maxHeight:
                        maxHeight = mode[2]

            self.__allVideoModes.append(modes)

        LOG_DEBUG('max resolution : %d / %d' % (maxWidth, maxHeight))
        if maxHeight > 0:
            _3dVisionAspectRatio = float(maxWidth) / float(maxHeight)
            LOG_DEBUG('aspect ratio : %f' % _3dVisionAspectRatio)
            if _3dVisionAspectRatio > 3.75:
                gcd = self.__gcd(maxWidth, maxHeight)
                LOG_DEBUG('aspect ratio inted: %d / %d' % (maxWidth / gcd, maxHeight / gcd))
                self.ASPECT_RATIO.append((maxWidth / gcd, maxHeight / gcd))
        self.__multisamplingTypes = BigWorld.getSupportedMultisamplingTypes()
        self.__multisamplingTypes.insert(0, 0)
        self.__customAAModes = BigWorld.getSupportedCustomAAModes()
        self.__monitors = BigWorld.wg_getMonitorNames()
        self.__curentMonitorIndex = BigWorld.wg_getActiveMonitorIndex()
        self.__monitorChanged = False
        self.__lastFullscreenSize = None
        self.__lastWindowedSize = None
        BigWorld.wg_setSavePreferencesCallback(self.onSavePreferencesXml)
        return

    @property
    def monitorChanged(self):
        return self.__monitorChanged

    @property
    def __windowSizes(self):
        __windowSizes = []
        for monitorModes in self.__allVideoModes:
            maxWindow = BigWorld.wg_getMaxWindowedResolution(len(__windowSizes))
            modes = []
            for m in monitorModes:
                if m[1] > maxWindow[0] or m[2] > maxWindow[1]:
                    continue
                modes.append((m[1], m[2]))

            if maxWindow not in modes:
                modes.append(maxWindow)
            __windowSizes.append(modes)

        return __windowSizes

    @property
    def __videoModes(self):
        return [ (m[0], m[1], m[2]) for m in self.__allVideoModes[self.monitorIndex] ]

    @property
    def __aspectRatios(self):
        return g_graficsResolutions.ASPECT_RATIO

    @property
    def __videoMode(self):
        return BigWorld.videoModeIndex()

    @property
    def __windowSize(self):
        return tuple(map(int, BigWorld.wg_getCurrentResolution(True)))

    @property
    def __aspectRatio(self):
        return round(BigWorld.getFullScreenAspectRatio(), 6)

    @property
    def __multisamplingType(self):
        return BigWorld.getMultisamplingType()

    @property
    def __customAAMode(self):
        return BigWorld.getCustomAAMode()

    @property
    def isVideoWindowed(self):
        return BigWorld.isVideoWindowed()

    @property
    def isVideoVSync(self):
        return BigWorld.isVideoVSync()

    @property
    def isTripleBuffered(self):
        return BigWorld.isTripleBuffered()

    @property
    def videoModeIndex(self):
        for index, videoModeInfo in enumerate(self.__videoModes):
            if videoModeInfo[0] == self.__videoMode:
                return index

        return -1

    @property
    def monitorIndex(self):
        return BigWorld.wg_getActiveMonitorIndex()

    @property
    def realMonitorIndex(self):
        return self.__curentMonitorIndex

    @property
    def windowSizeIndex(self):
        for index, size in enumerate(self.__windowSizes[self.__curentMonitorIndex]):
            if size == self.__windowSize:
                return index

        return len(self.__windowSizes[self.__curentMonitorIndex])

    @property
    def aspectRatioIndex(self):
        for index, size in enumerate(self.__aspectRatios):
            if round(float(size[0]) / size[1], 6) == self.__aspectRatio:
                return index

        return len(self.__aspectRatios)

    @property
    def multisamplingTypeIndex(self):
        if self.__multisamplingType in self.__multisamplingTypes:
            return self.__multisamplingTypes.index(self.__multisamplingType)
        return -1

    @property
    def customAAModeIndex(self):
        if self.__customAAMode in self.__customAAModes:
            return self.__customAAModes.index(self.__customAAMode)
        return -1

    @property
    def videoModesList(self):
        allModes = []
        for monitorModes in self.__allVideoModes:
            modes = []
            for m in monitorModes:
                modes.append('%dx%d' % (m[1], m[2]))

            allModes.append(modes)

        return allModes

    @property
    def monitorsList(self):
        return self.__monitors

    @property
    def windowSizesList(self):
        allModes = []
        for monitorModes in self.__windowSizes:
            modes = []
            for m in monitorModes:
                modes.append('%dx%d' % m)

            current = '%dx%d' % self.__windowSize
            if current not in modes:
                modes.append(current + '*')
            allModes.append(modes)

        return allModes

    @property
    def aspectRatiosList(self):
        aspectRatios = [ '%d:%d' % m for m in self.__aspectRatios ]
        if self.aspectRatioIndex == len(self.__aspectRatios):
            aspectRatios.append('%s:1*' % BigWorld.wg_getNiceNumberFormat(self.__aspectRatio))
        return aspectRatios

    @property
    def multisamplingTypesList(self):
        return [ '#settings:multisamplingType/type%s' % i for i in self.__multisamplingTypes ]

    @property
    def customAAModesList(self):
        return [ '#settings:customAAMode/mode%s' % i for i in self.__customAAModes ]

    def __isVideoModeSuitable(self, videoMode):
        return videoMode[1] >= GraphicsResolutions.MIN_WIDTH and videoMode[2] >= GraphicsResolutions.MIN_HEIGHT and videoMode[3] >= GraphicsResolutions.MIN_COLOR_DEPTH

    def getVideoModeByIndex(self, index):
        if len(self.__videoModes) > index > -1:
            return self.__videoModes[int(index)][0]
        else:
            return None
            return None

    def getWindowSizeByIndex(self, index):
        if len(self.__windowSizes[self.__curentMonitorIndex]) > index > -1:
            return self.__windowSizes[self.__curentMonitorIndex][int(index)]
        return self.__windowSize

    def getAspectRatioByIndex(self, index):
        if len(self.__aspectRatios) > index > -1:
            ars = self.__aspectRatios[int(index)]
            return round(float(ars[0]) / ars[1], 6)
        else:
            return None
            return None

    def getMultisamplingTypeByIndex(self, index):
        if len(self.__multisamplingTypes) > index > -1:
            return self.__multisamplingTypes[int(index)]
        else:
            return None
            return None

    def getCustomAAModeByIndex(self, index):
        if len(self.__customAAModes) > index > -1:
            return self.__customAAModes[int(index)]
        else:
            return None
            return None

    @property
    def gamma(self):
        return BigWorld.getGammaCorrection()

    def applyChanges(self, isFullScreen, isVideoVSync, isTripleBuffered, sizeIndex, aspectRatioIndex, multisamplingIndex, customAAIndex, gamma, monitorIndex):
        if self.__curentMonitorIndex != monitorIndex:
            self.__monitorChanged = True
        self.__curentMonitorIndex = monitorIndex
        BigWorld.wg_setActiveMonitorIndex(monitorIndex)
        if self.isVideoVSync != isVideoVSync:
            BigWorld.setVideoVSync(isVideoVSync)
        if self.isTripleBuffered != isTripleBuffered:
            BigWorld.setTripleBuffering(isTripleBuffered)
        if self.gamma != gamma:
            gamma = max(gamma, 0.5)
            gamma = min(gamma, 2.0)
            BigWorld.setGammaCorrection(gamma)
        aspectRatio = self.getAspectRatioByIndex(aspectRatioIndex)
        if aspectRatio is not None and aspectRatio != self.__aspectRatio:
            BigWorld.changeFullScreenAspectRatio(aspectRatio)
        multisamplingType = self.getMultisamplingTypeByIndex(multisamplingIndex)
        if self.__multisamplingType != multisamplingType:
            BigWorld.setMultisamplingType(multisamplingType)
        customAAMode = self.getCustomAAModeByIndex(customAAIndex)
        if self.__customAAMode != customAAMode:
            BigWorld.setCustomAAMode(customAAMode)
        if isFullScreen:
            videoMode = self.getVideoModeByIndex(sizeIndex)
            if not self.__monitorChanged and (videoMode != self.__videoMode or self.isVideoWindowed):
                BigWorld.changeVideoMode(videoMode, False)
            windowSize = self.getWindowSizeByIndex(sizeIndex)
            self.__lastIsWindowed = False
            self.__lastFullscreenSize = (windowSize[0], windowSize[1])
        else:
            if not self.__monitorChanged and not self.isVideoWindowed:
                BigWorld.changeVideoMode(self.getVideoModeByIndex(sizeIndex), True)
            windowSize = self.getWindowSizeByIndex(sizeIndex)
            oldResolution = BigWorld.wg_getCurrentResolution(True)
            if windowSize is not None and (oldResolution[0] != windowSize[0] or oldResolution[1] != windowSize[1]):
                BigWorld.resizeWindow(windowSize[0], windowSize[1])
            self.__lastIsWindowed = True
            self.__lastWindowedSize = (windowSize[0], windowSize[1])
        return

    def onSavePreferencesXml(self, root):
        if not self.__monitorChanged:
            return
        else:
            devPref = root['devicePreferences']
            devPref.writeBool('windowed', self.__lastIsWindowed)
            if self.__lastFullscreenSize is not None:
                devPref.writeInt('fullscreenWidth', self.__lastFullscreenSize[0])
                devPref.writeInt('fullscreenHeight', self.__lastFullscreenSize[1])
            if self.__lastWindowedSize is not None:
                devPref.writeInt('windowedWidth', self.__lastWindowedSize[0])
                devPref.writeInt('windowedHeight', self.__lastWindowedSize[1])
            return
            return


g_graficsResolutions = GraphicsResolutions() 

 

'X:\Games\World_of_Tanks\res\scripts\client\gui\shared\utils\graphics.pyc'

from collections import namedtuple
import BigWorld
from debug_utils import LOG_WARNING
from gui.doc_loaders.GraphicsPresetsLoader import GraphicsPresetsLoader
from gui.shared.utils import CONST_CONTAINER
MIN_SCREEN_WIDTH = 800
MIN_SCREEN_HEIGHT = 600
MIN_COLOR_DEPTH = 23
_g_graphSettingsIndices = None
_g_graphPresets = None
GraphicSetting = namedtuple('GraphicSetting', 'label value options hint advanced needRestart delayed')
VideoMode = namedtuple('VideoMode', 'index width height colorDepth label')
WindowSize = namedtuple('WindowSize', 'width height')

class GRAPHICS_SETTINGS(CONST_CONTAINER):
    RENDER_PIPELINE = 'RENDER_PIPELINE'
    TEXTURE_QUALITY = 'TEXTURE_QUALITY'
    DECALS_QUALITY = 'DECALS_QUALITY'
    OBJECT_LOD = 'OBJECT_LOD'
    FAR_PLANE = 'FAR_PLANE'
    TERRAIN_QUALITY = 'TERRAIN_QUALITY'
    SHADOWS_QUALITY = 'SHADOWS_QUALITY'
    LIGHTING_QUALITY = 'LIGHTING_QUALITY'
    SPEEDTREE_QUALITY = 'SPEEDTREE_QUALITY'
    FLORA_QUALITY = 'FLORA_QUALITY'
    WATER_QUALITY = 'WATER_QUALITY'
    EFFECTS_QUALITY = 'EFFECTS_QUALITY'
    POST_PROCESSING_QUALITY = 'POST_PROCESSING_QUALITY'
    MOTION_BLUR_QUALITY = 'MOTION_BLUR_QUALITY'
    SNIPER_MODE_EFFECTS_QUALITY = 'SNIPER_MODE_EFFECTS_QUALITY'
    VEHICLE_DUST_ENABLED = 'VEHICLE_DUST_ENABLED'
    SNIPER_MODE_GRASS_ENABLED = 'SNIPER_MODE_GRASS_ENABLED'
    VEHICLE_TRACES_ENABLED = 'VEHICLE_TRACES_ENABLED'
    SNIPER_MODE_SWINGING_ENABLED = 'SNIPER_MODE_SWINGING_ENABLED'


def __initPresetsData():
    global _g_graphPresets
    if _g_graphPresets is None:
        _g_graphPresets = GraphicsPresetsLoader()
        _g_graphPresets.load()
    return


def __initGraphicsSettingsData():
    global _g_graphSettingsIndices
    if _g_graphSettingsIndices is None:
        _g_graphSettingsIndices = dict(((data[0], idx) for idx, data in enumerate(BigWorld.graphicsSettings())))
    return


def isVideoModeSuitable(mode):
    return mode.width >= MIN_SCREEN_WIDTH and mode.height >= MIN_SCREEN_HEIGHT and mode.colorDepth >= MIN_COLOR_DEPTH


def getSuitableVideoModes():
    result = []
    for monitorModes in BigWorld.listVideoModesAllMonitors():
        modes = []
        for mode in monitorModes:
            m = VideoMode(*mode)
            if isVideoModeSuitable(m):
                modes.append(m)

        result.append(modes)

    return tuple(result)


def getSuitableWindowSizes():
    result = []
    for idx, monitorModes in enumerate(getSuitableVideoModes()):
        maxSize = WindowSize(*BigWorld.wg_getMaxWindowedResolution(idx))
        modes = []
        for mode in monitorModes:
            if mode.width <= maxSize.width and mode.height <= maxSize.height:
                modes.append(WindowSize(mode.width, mode.height))

        if maxSize not in modes:
            modes.append(maxSize)
        result.append(modes)

    return tuple(result)


def getGraphicsSetting(settingName):
    __initGraphicsSettingsData()
    index = _g_graphSettingsIndices.get(settingName)
    if index is None:
        LOG_WARNING('Unknown graphics setting', settingName)
        return
    else:
        return GraphicSetting(*BigWorld.graphicsSettings()[index])
        return


def getGraphicsPresets(presetIdx = None):
    __initPresetsData()
    if presetIdx is not None:
        return _g_graphPresets.getPreset(presetIdx)
    else:
        return [ _g_graphPresets.getPreset(key) for key in _g_graphPresets.getPresetsKeys() ]
        return


def getGraphicsPresetsIndices():
    __initPresetsData()
    return dict(((key, idx) for idx, key in enumerate(_g_graphPresets.getPresetsKeys())))


class MonitorSettings(object):

    def __init__(self):
        self.__suitableVideoModes = getSuitableVideoModes()
        self.__suitableWindowSizes = getSuitableWindowSizes()
        self.__monitorChanged = False
        self.__currentMonitorIdx = self.activeMonitor

    @property
    def windowSizes(self):
        return self.__suitableWindowSizes[self.activeMonitor]

    @property
    def currentWindowSize(self):
        return WindowSize(*map(int, BigWorld.wg_getCurrentResolution(True)))

    @property
    def videoModes(self):
        return self.__suitableVideoModes[self.activeMonitor]

    @property
    def currentVideoMode(self):
        for videoMode in self.videoModes:
            if videoMode.index == BigWorld.videoModeIndex():
                return videoMode

        return None

    def changeMonitor(self, monitorIdx):
        if self.__currentMonitorIdx != monitorIdx:
            self.__monitorChanged = True
        self.__currentMonitorIdx = monitorIdx
        BigWorld.wg_setActiveMonitorIndex(monitorIdx)

    def setFullscreen(self, isFullscreen):
        vm = self.currentVideoMode
        if vm is not None and isFullscreen != self.isFullscreen:
            BigWorld.changeVideoMode(vm.index, not isFullscreen)
        return

    def changeVideoMode(self, videoMode):
        cvm = self.currentVideoMode
        if not self.isMonitorChanged and cvm is not None and (videoMode.index != cvm or not self.isFullscreen):
            BigWorld.changeVideoMode(videoMode.index, False)
        return

    def changeWindowSize(self, windowSize):
        if not self.isMonitorChanged and self.isFullscreen:
            self.setFullscreen(False)
        curWindowSize = self.currentWindowSize
        if curWindowSize.width != windowSize.width or curWindowSize.height != windowSize.height:
            BigWorld.resizeWindow(windowSize.width, windowSize.height)

    @property
    def activeMonitor(self):
        return BigWorld.wg_getActiveMonitorIndex()

    @property
    def currentMonitor(self):
        return self.__currentMonitorIdx

    @property
    def isMonitorChanged(self):
        return self.__monitorChanged

    @property
    def isFullscreen(self):
        return not BigWorld.isVideoWindowed()

    @property
    def maxParams(self):
        maxWidth = maxHeight = 0
        for monitorModes in self.__suitableVideoModes:
            for mode in monitorModes:
                maxWidth = max(maxWidth, mode.width)
                maxHeight = max(maxHeight, mode.height)

        return (maxWidth, maxHeight)


g_monitorSettings = MonitorSettings() 

 

Данные скрипты позволяют выбрать разрешение меньше чем стандартные 1024х768, но при нажатии кнопки применить нужное разрешение сбрасывается.

 

Насколько я понимаю, в этих скриптах так же идет проверка выставляемых значений с родными для BigWorld значениями. Подскажите где подчистить чтобы эта проверка не проходила.

  • Upvote 1
  • Downvote 1
Link to comment
Short link
Share on other sites

Сделал перерыв небольшой (голова пухнет от непонимания, что надо делать). Надо доставать опять книги по Python ;)

 

Пришла вот такая идея относительно управления. Разве надо делать эмулятор клавиатуры/мыши через геймпад? Думаю что нет. 

 

Сравнивая скрипты от WoWP и WoT, кажется нашел именно то, что нужно.

'X:\Games\World_of_Warplanes\res\scripts\client\InputMapping.pyс'

import inspect
import BigWorld
from Event import Event
import ResMgr
import Keys
import consts
from db.DBHelpers import readValue
from Helpers.i18n import makeString, localizeOptions
from MathExt import *
import math
import threading
from debug_utils import *
from input.ProfileLoader.DummyDeviceLoader import MouseDummy
from input.ProfileLoader.MouseLoader import MouseLoader
from input.ProfileLoader.JoystickLoader import JoystickSettings
from input.ProfileLoader.KeyMapingLoader import Keyboard
from input.ProfileLoader.GamepadLoader import GamepadProfileLoader
g_instance = None
g_descriptions = None
FORCE_DEFAULT_INPUT_PATH = False

def initInput(profileName, profilesPresets):
    global g_instance
    global g_descriptions
    g_descriptions = CommandDescriptions()
    g_instance = InputMapping(profileName, profilesPresets)


def translateAxisValue(axisCurve, axisValue):
    return math.copysign(axisCurve.calc(abs(axisValue)), axisValue)


SENSITIVITY_MIN = 0.05
SENSITIVITY_MAX = 2.5
HI_AXIS_BOUND = 0.5
LOW_AXIS_BOUND = 0.3

def convertToRealSensitivity(sliderValue):
    return sliderValue * (SENSITIVITY_MAX - SENSITIVITY_MIN) + SENSITIVITY_MIN


COMMANDS_TO_REFRESH = []
COMMANDS_TO_NOT_REFRESH = []
CHAT_COMMANDS = []
EQUIPMENT_COMMANDS = []

class CommandDescriptions(object):
    __DATA_PATH = 'scripts/command_mapping_description.xml'

    def __init__(self):
        self.__commands = {}
        rootSection = ResMgr.openSection(self.__DATA_PATH)
        commandIntID = 1
        for commandID, dataSection in rootSection.items():
            self.__commands[commandID] = CommandDescription(commandIntID)
            self.__commands[commandID].readFromDatasection(dataSection)
            globals()[commandID] = commandIntID
            commandIntID += 1

        if consts.IS_DEBUG_IMPORTED:
            from debug.AvatarDebug import DebugCommands
            self.loadMappingFromClass(DebugCommands, commandIntID)
        self.__fillGlobalCommandLists()
        ResMgr.purge(self.__DATA_PATH, True)

    def __fillGlobalCommandLists(self):
        global CHAT_COMMANDS
        global COMMANDS_TO_REFRESH
        global EQUIPMENT_COMMANDS
        global COMMANDS_TO_NOT_REFRESH
        COMMANDS_TO_REFRESH = [CMD_AUTOPILOT]
        COMMANDS_TO_NOT_REFRESH = [CMD_INTERMISSION_MENU,
         CMD_VISIBILITY_HUD,
         CMD_SHOW_CURSOR,
         CMD_HELP,
         CMD_SHOW_MAP]
        CHAT_COMMANDS = [CMD_F2_CHAT_COMMAND,
         CMD_F3_CHAT_COMMAND,
         CMD_F4_CHAT_COMMAND,
         CMD_F5_CHAT_COMMAND,
         CMD_F6_CHAT_COMMAND,
         CMD_F7_CHAT_COMMAND,
         CMD_F8_CHAT_COMMAND,
         CMD_F9_CHAT_COMMAND]
        EQUIPMENT_COMMANDS = [CMD_USE_EQUIPMENT_1, CMD_USE_EQUIPMENT_2, CMD_USE_EQUIPMENT_3]

    def loadMappingFromClass(self, classWithMapping, commandIntID):
        import inspect
        for commandID, value in inspect.getmembers(classWithMapping):
            if commandID.startswith('CMD_'):
                self.__commands[commandID] = CommandDescription(commandIntID, 'DEBUG')
                globals()[commandID] = commandIntID
                commandIntID += 1

    @property
    def commands(self):
        return self.__commands

    def getCommandWaitTime(self, commandName):
        if commandName in self.__commands:
            command = self.__commands[commandName]
            return command.waitTime
        return 0.0

    def getCommandGroupID(self, commandName):
        if commandName in self.__commands:
            command = self.__commands[commandName]
            return command.groupID
        return ''

    def getCommandLocalizationID(self, commandName):
        if commandName in self.__commands:
            command = self.__commands[commandName]
            return command.localizationID
        return ''

    def getLinkedAxisName(self, commandName):
        if commandName in self.__commands:
            command = self.__commands[commandName]
            return command.linkedAxisName
        else:
            return ''

    def getCommandIntID(self, commandName):
        if commandName in self.__commands:
            command = self.__commands[commandName]
            return command.commandID
        return ''

    def getCommandNameByID(self, commandID):
        for commandName, command in self.__commands.items():
            if commandID == command.commandID:
                return (commandName, command.groupName)

        return (None, None)


class CommandDescription():

    def __init__(self, commandIntID, groupName = 'MAIN', groupID = 'SETTINGS_BASIC'):
        self.commandID = commandIntID
        self.linkedAxisName = ''
        self.localizationID = ''
        self.groupName = groupName
        self.groupID = groupID
        self.waitTime = 0.0

    def readFromDatasection(self, dataSection):
        readValue(self, dataSection, 'linkedAxisName', '')
        readValue(self, dataSection, 'localizationID', '')
        readValue(self, dataSection, 'groupName', 'MAIN')
        readValue(self, dataSection, 'groupID', 'SETTINGS_BASIC')
        readValue(self, dataSection, 'waitTime', 0.0)


class InputMappingLoader(threading.Thread):

    def __init__(self, threadData, callback):
        threading.Thread.__init__(self)
        self.__threadData = threadData
        self.__callback = callback

    def run(self):
        self.__callback(self.__threadData)


class InputMapping(object):
    __DATA_PATH = 'scripts/input_mapping/'
    __DEFAULTS_PATH = __DATA_PATH + 'defaults/'
    __DEFAULT_CONFIG_FILE_NAME = 'keyboard'
    __PRIMARY_SETTINGS_LOADERS = {consts.INPUT_SYSTEM_STATE.KEYBOARD: MouseDummy,
     consts.INPUT_SYSTEM_STATE.JOYSTICK: JoystickSettings,
     consts.INPUT_SYSTEM_STATE.GAMEPAD_DIRECT_CONTROL: JoystickSettings,
     consts.INPUT_SYSTEM_STATE.MOUSE: MouseLoader}

    @property
    def descriptions(self):
        return g_descriptions

    def __init__(self, currentProfileName, profilesPresets):
        self.__profileNames = self.loadProfileNames(profilesPresets)
        if ResMgr.useDefaultDataPath() or FORCE_DEFAULT_INPUT_PATH:
            self.__dataPath = self.__DATA_PATH
        else:
            self.__dataPath = ResMgr.getInputMappingPath(self.__DEFAULTS_PATH, '.xml', self.__profileNames)
        self.__checkInputFiles(self.__DEFAULTS_PATH, self.__dataPath)
        LOG_INFO('Input mapping data path: ' + self.__dataPath)
        if currentProfileName not in self.__profileNames:
            if self.__DEFAULT_CONFIG_FILE_NAME in self.__profileNames:
                currentProfileName = self.__DEFAULT_CONFIG_FILE_NAME
            elif self.__profileNames:
                currentProfileName = self.__profileNames[0]
            else:
                LOG_ERROR('InputMapping::__init__ - can"t load current profile name:', currentProfileName)
        self.onDefaultMappingRestored = Event()
        self.onProfileLoaded = Event()
        self.__loadLock = threading.Lock()
        self.__loadInProgressProfile = None
        self.__load(currentProfileName, False, True, None)
        self.onSaveControls = Event()
        return

    def __loadLockAcquire(self):
        self.__loadLock.acquire()

    def __loadLockRelease(self):
        self.__loadLock.release()

    def __getCallbackClient(self):
        return self.__callbackClient

    def __setCallbackClient(self, val):
        self.__callbackClient = val

    callbackClient = property(__getCallbackClient, __setCallbackClient)

    def __checkInputFiles(self, defaultDataPath, actualDataPath):
        if defaultDataPath == actualDataPath:
            LOG_ERROR('defaultDataPath equals actualDataPath:', defaultDataPath)
        else:
            defaultlDataSection = ResMgr.openSection(defaultDataPath)
            if defaultlDataSection == None:
                LOG_ERROR('default data section does not exist')
            else:
                actualDataSection = ResMgr.openSection(actualDataPath)
                if actualDataSection == None:
                    LOG_ERROR('data section must already exist', actualDataPath)
                else:
                    for profile in self.__profileNames:
                        self.__checkInputFile(defaultlDataSection, actualDataSection, profile)

        return

    def __checkInputFile(self, defaultlDataSection, actualDataSection, profile):
        fileName = profile + '.xml'
        if not defaultlDataSection.has_key(fileName):
            LOG_ERROR('default data section does not contain file', fileName)
        else:
            defaultProfile = defaultlDataSection[fileName]
            if defaultProfile == None:
                LOG_ERROR('cannot open default file', fileName)
            elif actualDataSection.has_key(fileName):
                actualProfile = actualDataSection[fileName]
                if actualProfile == None:
                    LOG_ERROR('cannot open file', fileName)
                else:
                    defaultVersion = defaultProfile.readInt('FILE_VERSION', 0)
                    actualVersion = actualProfile.readInt('FILE_VERSION', 0)
                    if actualVersion < defaultVersion:
                        actualProfile.copy(defaultProfile)
                        actualProfile.save()
                        LOG_INFO('version mismatch, replaced', fileName, defaultVersion, actualVersion)
            else:
                actualProfile = actualDataSection.createSection(fileName)
                if actualProfile == None:
                    LOG_ERROR('cannot create new section', fileName)
                else:
                    actualProfile.copy(defaultProfile)
                    actualProfile.save()
                    LOG_INFO('created profile from default', fileName)
        return

    def getAllCommandsIds(self):
        commadIds = list()
        for command in g_descriptions.commands.values():
            commadIds.append(command.commandID)

        return commadIds

    def getCommandsButtonsList(self, commandIDsList):
        from input.InputController import UserKeyEvent
        keys = []
        for commandID in commandIDsList:
            keyCodes = self.keyboardSettings.getCommandKeys(commandID)
            if keyCodes and len(keyCodes) > 0:
                keyInfo = keyCodes[0]
                keys.append(UserKeyEvent(keyInfo['code'], keyInfo['device']))

        return keys

    def getAllCommandsButtonsList(self, ignoreCommandIDsList):
        from input.InputController import UserKeyEvent
        keys = []
        for command in g_descriptions.commands.values():
            keyCodes = None
            if command.commandID not in ignoreCommandIDsList:
                keyCodes = self.keyboardSettings.getCommandKeys(command.commandID)
            if keyCodes and len(keyCodes) > 0:
                keyInfo = keyCodes[0]
                keys.append(UserKeyEvent(keyInfo['code'], keyInfo['device']))

        return keys

    def getProfileNames(self):
        return self.__profileNames

    def loadProfileNames(self, profilesPresets):
        """
        @param profilesPresets: <dict> Ex.: {mouse_directional : [{name:mouse_directional, localizationID:CONTROL_PROFILE_DEFAULT}] }
        @return: <list>
        """
        profiles = []
        rootSection = ResMgr.openSection(self.__DEFAULTS_PATH)
        for fileName in rootSection.keys():
            extentionPos = fileName.find('.xml')
            if extentionPos != -1:
                profileName = fileName[0:extentionPos]
                isPreset = False
                if not isPreset:
                    profiles.append(profileName)

        ResMgr.purge(self.__DEFAULTS_PATH, True)
        return profiles

    def getLocalizedProfileNameCaps(self, profileName = None):
        if profileName is None:
            profileName = self.getCurProfileName()
        return localizeOptions('CONTROL_PROFILE_%s_CAPS' % profileName.upper())

    def getLocalizedProfileName(self, profileName = None):
        if profileName is None:
            profileName = self.getCurProfileName()
        return localizeOptions('CONTROL_PROFILE_%s' % profileName.upper())

    def getLocalizedProfileNames(self):
        locProfiles = []
        profiles = self.getProfileNames()
        for profile in profiles:
            locProfiles.append(localizeOptions('CONTROL_PROFILE_' + profile.upper()))

        return locProfiles

    def getProfileNameByIndex(self, index):
        profiles = self.getProfileNames()
        return profiles[index]

    def isCommandKey(self, command, key, keyDevice, axisIndex = -1, axisDevice = 0):
        return self.keyboardSettings.isCommandKey(command, key, keyDevice, axisIndex, axisDevice)

    def isMouseActivateEvent(self, key, event):
        if isinstance(event, BigWorld.KeyEvent):
            return event.wg_isMouseActivateEvent
        return False

    def setSwitchingStyle(self, command, switchingStyle):
        self.keyboardSettings.setSwitchingStyle(command, switchingStyle)

    def getSwitchingStyle(self, command):
        return self.keyboardSettings.getSwitchingStyle(command)

    def invertY(self):
        self.keyboardSettings.INVERT_Y = 1 - self.keyboardSettings.INVERT_Y
        self.primarySettings.INVERT_Y = 1 - self.primarySettings.INVERT_Y

    @property
    def mouseSettings(self):
        return self.primarySettings

    @property
    def joystickSettings(self):
        return self.primarySettings

    def __saveProfile(self, rootSection, profilePath):
        try:
            rootSection.save()
        except IOError:
            LOG_ERROR("Couldn't save profile: " + profilePath)
        else:
            LOG_DEBUG('Controls saved to ' + profilePath)

        ResMgr.purge(profilePath, True)

    def saveControlls(self, curProfileName, profileNameKeyBoard = None):
        if self.__loadInProgressProfile:
            LOG_INFO('::saveControlls: Save rejected. Profile %s is loading' % self.__loadInProgressProfile['profileName'])
            return
        else:
            try:
                self.__loadLockAcquire()
                profilePath = ''.join([self.__dataPath, self.__curProfileName if curProfileName is None else curProfileName, '.xml'])
                rootSection = ResMgr.openSection(profilePath)
                self.keyboardSettings.flash(rootSection['KEYBOARD'])
                self.primarySettings.flash(rootSection['PRIMARY'])
                self.__saveProfile(rootSection, profilePath)
                if profileNameKeyBoard is not None:
                    LOG_INFO('saveControlls - save KEYBOARD to %s.xml curProfileName=%s' % (profileNameKeyBoard, curProfileName))
                    keyBoardPath = ''.join([self.__dataPath, profileNameKeyBoard, '.xml'])
                    keyBoardRootSection = ResMgr.openSection(keyBoardPath)
                    self.keyboardSettings.flash(keyBoardRootSection['KEYBOARD'])
                    self.__saveProfile(keyBoardRootSection, keyBoardPath)
                self.onSaveControls()
            except:
                LOG_CURRENT_EXCEPTION()
            finally:
                self.__loadLockRelease()

            return

    def getCurProfileName(self):
        return self.__curProfileName

    def setCurProfileName(self, ProfileName):
        LOG_INFO('setCurProfileName - old=(%s), new=(%s)' % (self.__curProfileName, ProfileName))
        self.__curProfileName = ProfileName

    def getCurProfileIndex(self):
        profiles = self.getProfileNames()
        return profiles.index(self.__curProfileName)

    def changeProfile(self, profileName):
        self.__load(profileName, False, True, None)
        return

    def loadProfileFromPreset(self, profileName, loadFromDefaults, profileNameForKeyboardSettings):
        self.__load(profileName, loadFromDefaults, False, profileNameForKeyboardSettings)

    def restoreDefaultsCommandMapping(self):
        self.__load(self.__curProfileName, True, True, None)
        return

    def getCurMapping(self):
        return self.keyboardSettings.getCurMapping(self.joystickSettings)

    def applyNewMapping(self, mapping):
        self.keyboardSettings.applyNewMapping(mapping, self.joystickSettings)

    def setKeyboardLining(self, value):
        self.keyboardSettings.setLining(value)

    def getKeyboardLining(self):
        return self.keyboardSettings.getLining()

    def getLocalizedCommandKeysAndAxes(self, commandName):
        """
        Returns list with localized names of keys/axes that correspond to given command or empty list
        @param commandName: command name from command_mapping_description.xml
        @rtype: list
        """
        keysControls = []
        curMapping = self.getCurMapping()
        record = curMapping.get(g_descriptions.getCommandIntID(commandName), None)
        if record is not None:
            for key in record['keyNames']:
                if 'KEY_NONE' != key['name']:
                    keysControls.append(getKeyLocalization(key['name']))

            if not self.currentProfileType == consts.INPUT_SYSTEM_STATE.KEYBOARD:
                if not self.currentProfileType == consts.INPUT_SYSTEM_STATE.MOUSE:
                    if record['linkedAxisIndex'] != -1:
                        keysControls.append(getAxisLocalization(record['linkedAxisIndex']))
                    record['fireAxisIndex'] != -1 and keysControls.append(getAxisLocalization(record['fireAxisIndex']))
        return keysControls

    def getKeyControlsHelp(self, dataKeysControls):
        keysControls = {}
        curMapping = self.getCurMapping()
        for cmdID, record in curMapping.items():
            cmdLabel = getCommandLocalization(record['cmdName'])
            if cmdLabel is not None and cmdID in dataKeysControls:
                keysControls[cmdID] = {'keys': [],
                 'isFireAxis': [],
                 'axisSign': []}
                for key in record['keyNames']:
                    if 'KEY_NONE' != key['name']:
                        keysControls[cmdID]['keys'].append(key['name'])
                        keysControls[cmdID]['isFireAxis'].append(False)
                        keysControls[cmdID]['axisSign'].append(0)

                if record['linkedAxisIndex'] != -1:
                    keysControls[cmdID]['keys'].append('_'.join(['AXIS', str(record['linkedAxisIndex'])]))
                    keysControls[cmdID]['isFireAxis'].append(False)
                    keysControls[cmdID]['axisSign'].append(0)
                elif record['fireAxisIndex'] != -1:
                    keysControls[cmdID]['keys'].append('_'.join(['AXIS', str(record['fireAxisIndex'])]))
                    keysControls[cmdID]['isFireAxis'].append(True)
                    keysControls[cmdID]['axisSign'].append(record['fireAxisSign'])

        return keysControls

    def __load(self, profileName, loadFromDefaults, isOverrideCurProfileName, profileNameForKeyboardSettings, loadFromDefaultsKeyboardSettings = False):
        if isOverrideCurProfileName:
            self.__curProfileName = profileName
        profilePath = profileName + '.xml'
        profilePath = self.__DEFAULTS_PATH + profilePath if loadFromDefaults else self.__dataPath + profilePath
        LOG_DEBUG("Try to load config profile '%s'" % profileName)
        o = dict(profileName=self.__curProfileName, loadFromDefaults=loadFromDefaults)
        resources = (profilePath,)
        if profileNameForKeyboardSettings is not None:
            o['profileNameForKeyboardSettings'] = profileNameForKeyboardSettings
            o['loadFromDefaultsKeyboardSettings'] = loadFromDefaultsKeyboardSettings
            profilePathForKeyboardSettings = self.__DEFAULTS_PATH + profileNameForKeyboardSettings + '.xml' if loadFromDefaultsKeyboardSettings else self.__dataPath + profileNameForKeyboardSettings + '.xml'
            resources = (profilePath, profilePathForKeyboardSettings)
        self.__loadInProgressProfile = o
        BigWorld.loadResourceListBG(resources, self.__profileDataSectionLoaded, 64, o)
        return

    @property
    def currentProfileType(self):
        return self.__currentProfileType

    def __profileDataSectionLoaded(self, resourceRefs):
        profilePath = resourceRefs.resourceIDs[0]
        LOG_DEBUG("Loading config profile from '%s'" % profilePath, resourceRefs.has_key(profilePath))
        if not resourceRefs.has_key(profilePath):
            LOG_DEBUG("Can't load '%s'" % profilePath)
            if resourceRefs.extraData['loadFromDefaults']:
                if resourceRefs.extraData['profileName'] != self.__DEFAULT_CONFIG_FILE_NAME:
                    self.__load(self.__DEFAULT_CONFIG_FILE_NAME, True, True, None)
                else:
                    LOG_ERROR("Can't load system configs")
            else:
                self.__load(resourceRefs.extraData['profileName'], True, True, None)
        else:
            LOG_DEBUG('Profile successfully loaded')
            rootSection = resourceRefs[profilePath]
            if self.__loadInProgressProfile == resourceRefs.extraData:
                self.__loadLockAcquire()
                try:
                    s = rootSection.readString('TYPE')
                    try:
                        self.__currentProfileType = consts.INPUT_SYSTEM_STATE.__dict__[s]
                    except KeyError:
                        LOG_DEBUG('Bad profile type - [' + str(s) + '] in ' + profilePath)
                        raise

                    rootSectionKeyboard = rootSection
                    if len(resourceRefs.resourceIDs) > 1 and 'profileNameForKeyboardSettings' in resourceRefs.extraData:
                        keyboardPath = resourceRefs.resourceIDs[1]
                        if resourceRefs.has_key(keyboardPath):
                            rootSectionKeyboard = resourceRefs[keyboardPath]
                            LOG_INFO('__profileDataSectionLoaded - KEYBOARD loaded from %s profilePath=%s' % (keyboardPath, profilePath))
                            ResMgr.purge(keyboardPath, True)
                    self.keyboardSettings = Keyboard(rootSectionKeyboard['KEYBOARD'])
                    profileLoaderClass = self.__PRIMARY_SETTINGS_LOADERS.get(self.currentProfileType, None)
                    if profileLoaderClass is not None:
                        self.primarySettings = profileLoaderClass(rootSection['PRIMARY'])
                    else:
                        LOG_INFO('::__profileDataSectionLoaded: Profile [%s],ProfileType[%s] ignored as an obsolete loading' % (profilePath, self.currentProfileType))
                    ResMgr.purge(profilePath, True)
                    self.onProfileLoaded()
                except:
                    LOG_CURRENT_EXCEPTION()
                finally:
                    self.__loadLockRelease()
                    self.__loadInProgressProfile = None

            else:
                LOG_INFO('::__profileDataSectionLoaded: Profile [%s] ignored as an obsolete loading' % profilePath)
        return


class Command():
    MODIFIERS = {'ALT': lambda : BigWorld.isKeyDown(Keys.KEY_RALT, 0) or BigWorld.isKeyDown(Keys.KEY_LALT, 0),
     'SHIFT': lambda : BigWorld.isKeyDown(Keys.KEY_RSHIFT, 0) or BigWorld.isKeyDown(Keys.KEY_LSHIFT, 0),
     'CTRL': lambda : BigWorld.isKeyDown(Keys.KEY_RCONTROL, 0) or BigWorld.isKeyDown(Keys.KEY_LCONTROL, 0),
     'RALT': lambda : BigWorld.isKeyDown(Keys.KEY_RALT, 0),
     'LALT': lambda : BigWorld.isKeyDown(Keys.KEY_LALT, 0),
     'LCTRL': lambda : BigWorld.isKeyDown(Keys.KEY_LCONTROL, 0),
     'RCTRL': lambda : BigWorld.isKeyDown(Keys.KEY_RCONTROL, 0)}

    def __init__(self, id, linkedAxisName, fireAxisIndex, fireAxisSign, fireAxisDevice, keyNames, modifier, isBlock, isBase, switchingStyle):
        self.id = id
        self.linkedAxisName = linkedAxisName
        self.fireAxisIndex = fireAxisIndex
        self.fireAxisSign = fireAxisSign
        self.fireAxisDevice = fireAxisDevice
        self.__modifierFnc = Command.MODIFIERS.get(modifier, None)
        self.applyNewKeys(keyNames)
        self.isBlock = isBlock
        self.isBase = isBase
        self.switchingStyle = switchingStyle
        self.lastExecuteTime = 0.0
        return

    def checkKey(self, key, keyDevice):
        for keyRecord in self.__keys:
            if key == keyRecord['code'] and (keyDevice == keyRecord['device'] or keyRecord['device'] == 0):
                return keyRecord

        return False

    def checkAxis(self, axisIndex, axisDevice):
        import BWPersonality
        if axisIndex != -1 and self.fireAxisIndex != -1:
            if self.fireAxisDevice == 0 or self.fireAxisDevice == axisDevice:
                return self.fireAxisIndex == axisIndex and axisIndex in BWPersonality.axis[axisDevice]
        return False

    def isModifierActive(self):
        return self.__modifierFnc is None or self.__modifierFnc()

    def isCommandActive(self):
        import BWPersonality
        if self.fireAxisIndex != -1:
            for device, axes in BWPersonality.axis.items():
                if (device == self.fireAxisDevice or self.fireAxisDevice == 0) and self.fireAxisIndex in axes:
                    axisValue = axes[self.fireAxisIndex]
                    if sign(axisValue) == sign(self.fireAxisSign) and abs(axisValue) > HI_AXIS_BOUND:
                        return True

        for key in self.__keys:
            if BigWorld.isKeyDown(key['code'], key['device']):
                return True

        return False

    def clear(self):
        self.__keys = []

    def flash(self, rootSection):
        rootSection.deleteSection(self.id)
        section = rootSection.createSection(self.id)
        keysSection = section.createSection('FIRE_KEYS')
        for key in self.__keys:
            keySection = keysSection.createSection('FIRE_KEY')
            keySection.writeString('fireKeyName', key['name'])
            keySection.writeInt64('fireKeyDevice', key['device'])

        section.writeInt('fireAxisIndex', self.fireAxisIndex)
        section.writeInt('fireAxisSign', self.fireAxisSign)
        section.writeInt64('fireAxisDevice', self.fireAxisDevice)
        section.writeInt('isBase', self.isBase)
        section.writeInt('switchingStyle', self.switchingStyle)

    def getMappedKeyCodes(self):
        return self.__keys

    def applyNewKeys(self, keyNames):
        """
        Fill 'code'(int keyCode) for all keys in record and drop all last empty keys
        
        keyNames : {'name':str,'device':UINT}
        
        """
        self.__keys = keyNames
        keyIndex = 0
        lastValidKeyIndex = 0
        for key in self.__keys:
            key['code'] = getKeyCodeByName(key['name'])
            keyIndex += 1
            if key['name'] != 'KEY_NONE':
                lastValidKeyIndex = keyIndex

        self.__keys = self.__keys[:lastValidKeyIndex]


def getKeyNameByCode(keyCode):
    if keyCode == 0:
        return 'KEY_NONE'
    for k, v in Keys.__dict__.items():
        if v == keyCode:
            return k

    return 'KEY_NONE'


def getKeyCodeByName(keyName):
    if keyName in Keys.__dict__:
        return int(Keys.__dict__.get(keyName))
    else:
        return 0


def getKeyLocalization(keyName):
    return makeString('#keys:' + keyName)


def getAxisLocalization(axisIndex):
    if axisIndex == -1:
        return ''
    return getKeyLocalization('_'.join(['AXIS', str(axisIndex)]))


def getCommandLocalization(commandName):
    localizationID = g_descriptions.getCommandLocalizationID(commandName)
    if localizationID == '':
        return None
    else:
        return makeString('#options:KEYMAPPING/' + localizationID)
        return None 

 

'X:\Games\World_of_Tanks\res\scripts\client\CommandMapping.pyc'

import BigWorld
import ResMgr
import Keys
import Event
import Settings
from debug_utils import *
g_instance = None
CMD_MOVE_FORWARD = 1
CMD_MOVE_FORWARD_SPEC = 2
CMD_MOVE_BACKWARD = 3
CMD_ROTATE_LEFT = 4
CMD_ROTATE_RIGHT = 5
CMD_INCREMENT_CRUISE_MODE = 6
CMD_DECREMENT_CRUISE_MODE = 7
CMD_STOP_UNTIL_FIRE = 8
CMD_SWITCH_SERVER_MARKER = 9
CMD_AMMO_CHOICE_1 = 10
CMD_AMMO_CHOICE_2 = 11
CMD_AMMO_CHOICE_3 = 12
CMD_AMMO_CHOICE_4 = 13
CMD_AMMO_CHOICE_5 = 14
CMD_AMMO_CHOICE_6 = 15
CMD_AMMO_CHOICE_7 = 16
CMD_AMMO_CHOICE_8 = 17
CMD_AMMO_CHOICE_9 = 18
CMD_AMMO_CHOICE_0 = 19
CMD_CHAT_SHORTCUT_ATTACK = 21
CMD_CHAT_SHORTCUT_BACKTOBASE = 22
CMD_CHAT_SHORTCUT_FOLLOWME = 23
CMD_CHAT_SHORTCUT_POSITIVE = 24
CMD_CHAT_SHORTCUT_NEGATIVE = 25
CMD_CHAT_SHORTCUT_HELPME = 26
CMD_CM_SHOOT = 27
CMD_CM_SWITCH_TRAJECTORY = 28
CMD_CM_FREE_CAMERA = 29
CMD_CM_LOCK_TARGET = 30
CMD_CM_LOCK_TARGET_OFF = 31
CMD_CM_CAMERA_ROTATE_LEFT = 32
CMD_CM_CAMERA_ROTATE_RIGHT = 33
CMD_CM_CAMERA_ROTATE_UP = 34
CMD_CM_CAMERA_ROTATE_DOWN = 35
CMD_CM_VEHICLE_SWITCH_AUTOROTATION = 36
CMD_CM_INCREASE_ZOOM = 37
CMD_CM_DECREASE_ZOOM = 38
CMD_CM_ALTERNATE_MODE = 39
CMD_CM_CAMERA_RESTORE_DEFAULT = 40
CMD_CM_POSTMORTEM_NEXT_VEHICLE = 41
CMD_CM_POSTMORTEM_SELF_VEHICLE = 42
CMD_VEHICLE_MARKERS_SHOW_INFO = 43
CMD_AMMO_PANEL_SELECT = 44
CMD_MINIMAP_HIGHLIGHT_CELL = 45
CMD_MINIMAP_VEHICLE_SPECIFIC = 46
CMD_MINIMAP_SIZE_UP = 47
CMD_MINIMAP_SIZE_DOWN = 48
CMD_MINIMAP_VISIBLE = 49
CMD_VOICECHAT_MUTE = 50
CMD_USE_HORN = 51
CMD_LOGITECH_SWITCH_VIEW = 52
CMD_TOGGLE_GUI = 53
CMD_RELOAD_PARTIAL_CLIP = 54
CMD_RADIAL_MENU_SHOW = 55
CMD_CHAT_SHORTCUT_RELOAD = 56

class CommandMapping:
    __DEFAULT_CONFIG_FILE_NAME = 'scripts/command_mapping.xml'
    __USER_CONFIG_SECTION_NAME = 'commandMapping'
    onMappingChanged = Event.Event()

    def __init__(self):
        self.__mapping = {}
        self.__dictCommand2CommandName = {}
        self.restoreUserConfig()

    def add(self, commandName, fireKeyName, satelliteKeyNames = [], isDefault = False):
        try:
            command = int(self.getCommand(commandName))
            fireKey = int(Keys.__dict__.get(fireKeyName))
            satelliteKeys = tuple(map(lambda x: int(Keys.__dict__.get(x)), satelliteKeyNames))
            keyInfo = (command, satelliteKeys, isDefault)
        except:
            return False

        if not isDefault:
            if not self.__checkUserKey(fireKey):
                return False
            for key in satelliteKeys:
                if not self.__checkUserKey(key):
                    return False

        if fireKey not in self.__mapping:
            self.__mapping[fireKey] = []
        if keyInfo not in self.__mapping[fireKey]:
            self.__mapping[fireKey].append(keyInfo)
        self.__dictCommand2CommandName[command] = commandName
        return True

    def get(self, commandName):
        try:
            command = int(self.getCommand(commandName))
            for fireKey, listKeyInfo in self.__mapping.iteritems():
                for keyInfo in listKeyInfo:
                    if keyInfo[0] == command and len(keyInfo[1]) == 0:
                        return fireKey

        except:
            return None

        return None

    def remove(self, commandName, fireKeyName = None, satelliteKeyNames = None, isDefault = None):
        try:
            delCommand = int(self.getCommand(commandName))
            delFireKey = None if fireKeyName is None else int(Keys.__dict__.get(fireKeyName))
            delSatelliteKeys = None if satelliteKeyNames is None else tuple(map(lambda x: int(Keys.__dict__.get(x)), satelliteKeyNames))
            delIsDefault = isDefault
        except:
            return False

        delListFireKey = []
        for fireKey in self.__mapping:
            if delFireKey is not None:
                if fireKey != delFireKey:
                    continue
            delListKeyInfo = []
            for keyInfo in self.__mapping[fireKey]:
                if keyInfo[0] != delCommand:
                    continue
                if delSatelliteKeys is not None:
                    if keyInfo[1] != delSatelliteKeys:
                        continue
                if delIsDefault is not None:
                    if keyInfo[2] != delIsDefault:
                        continue
                delListKeyInfo.append(keyInfo)

            for keyInfo in delListKeyInfo:
                self.__mapping[fireKey].remove(keyInfo)

            if not len(self.__mapping[fireKey]):
                delListFireKey.append(fireKey)

        for fireKey in delListFireKey:
            del self.__mapping[fireKey]

        return True

    def clear(self):
        self.__mapping = {}

    def restoreDefault(self):
        self.clear()
        self.__loadDefault()
        self.__loadDevelopment()

    def restoreUserConfig(self):
        self.clear()
        self.__loadDefault()
        self.__loadUserConfig()
        self.__loadDevelopment()

    def isActive(self, command):
        for fireKey, listKeyInfo in self.__mapping.iteritems():
            if not BigWorld.isKeyDown(fireKey):
                continue
            for keyInfo in listKeyInfo:
                if keyInfo[0] != command:
                    continue
                bContinue = False
                satelliteKeys = keyInfo[1]
                for key in satelliteKeys:
                    if not BigWorld.isKeyDown(key):
                        bContinue = True
                        break

                if bContinue:
                    continue
                return True

        return False

    def isActiveList(self, listCommands, bAndNor = False):
        if bAndNor:
            for command in listCommands:
                if not self.isActive(command):
                    return False

        else:
            for command in listCommands:
                if self.isActive(command):
                    return True

        return bool(bAndNor)

    def isFired(self, command, key):
        listKeyInfo = self.__mapping.get(key)
        if listKeyInfo is None or key == Keys.KEY_NONE:
            return False
        else:
            for keyInfo in listKeyInfo:
                if keyInfo[0] != command:
                    continue
                bContinue = False
                satelliteKeys = keyInfo[1]
                for key in satelliteKeys:
                    if not BigWorld.isKeyDown(key):
                        bContinue = True
                        break

                if bContinue:
                    continue
                return True

            return False

    def isFiredList(self, listCommands, key, bAndNor = False):
        if bAndNor:
            for command in listCommands:
                if not self.isFired(command, key):
                    return False

        else:
            for command in listCommands:
                if self.isFired(command, key):
                    return True

        return bool(bAndNor)

    def getName(self, command):
        if command in self.__dictCommand2CommandName:
            return self.__dictCommand2CommandName[command]
        else:
            return None

    def getCommand(self, name):
        return globals().get(name)

    def save(self):
        tmpList = []
        for fireKey, listKeyInfo in self.__mapping.iteritems():
            for command, satelliteKeys, isDefault in listKeyInfo:
                if isDefault:
                    continue
                if len(satelliteKeys):
                    continue
                commandName = self.getName(command)
                listSatelliteKeyNames = []
                for key in satelliteKeys:
                    listSatelliteKeyNames.append('KEY_' + BigWorld.keyToString(key))

                strSatelliteKeyNames = ''
                for keyName in listSatelliteKeyNames:
                    strSatelliteKeyNames += keyName + ' '

                strSatelliteKeyNames = strSatelliteKeyNames.strip()
                fireKeyName = 'KEY_' + BigWorld.keyToString(fireKey)
                tmpList.append((commandName, fireKeyName, strSatelliteKeyNames))

        if len(tmpList):
            section = Settings.g_instance.userPrefs
            section.deleteSection(CommandMapping.__USER_CONFIG_SECTION_NAME)
            section = section.createSection(CommandMapping.__USER_CONFIG_SECTION_NAME)
            for commandName, fireKeyName, strSatelliteKeynames in tmpList:
                subsec = section.createSection(commandName)
                subsec.writeString('fireKey', fireKeyName)
                subsec.writeString('satelliteKeys', strSatelliteKeyNames)

            Settings.g_instance.save()

    def __checkUserKey(self, key):
        """if Keys.KEY_1 <= key <= Keys.KEY_0: return True
        if Keys.KEY_Q <= key <= Keys.KEY_P: return True
        if Keys.KEY_A <= key <= Keys.KEY_L: return True
        if Keys.KEY_Z <= key <= Keys.KEY_M: return True
        if key == Keys.KEY_SPACE: return True
        return False"""
        return True

    def __loadFromSection(self, section, bDelOldCmds = True, asDefault = False):
        needsResave = False
        tempList = []
        for commandName in section.keys():
            subsec = section[commandName]
            fireKeyName = subsec.readString('fireKey')
            satelliteKeyNames = []
            if subsec.has_key('satelliteKeys'):
                satelliteKeyNames = subsec.readString('satelliteKeys').split()
            if bDelOldCmds:
                self.remove(commandName)
            if commandName.find('_SHORTCAT_') != -1:
                commandName = commandName.replace('_SHORTCAT_', '_SHORTCUT_')
                needsResave = True
            tempList.append((commandName, fireKeyName, satelliteKeyNames))

        for commandName, fireKeyName, satelliteKeyNames in tempList:
            if not self.add(commandName, fireKeyName, satelliteKeyNames, asDefault):
                LOG_DEBUG('<__loadFromSection>: ' + ('default' if asDefault else 'user') + ' command ' + str(commandName) + ' was not loaded')

        if needsResave:
            self.save()

    def getDefaults(self):
        section = ResMgr.openSection(CommandMapping.__DEFAULT_CONFIG_FILE_NAME)
        result = {}
        for commandName in section.keys():
            subsec = section[commandName]
            fireKeyName = subsec.readString('fireKey')
            satelliteKeyNames = []
            if subsec.has_key('satelliteKeys'):
                satelliteKeyNames = subsec.readString('satelliteKeys').split()
            if len(satelliteKeyNames) == 0:
                result[self.getCommand(commandName)] = int(Keys.__dict__.get(fireKeyName, 0))

        return result

    def __loadDefault(self):
        section = ResMgr.openSection(CommandMapping.__DEFAULT_CONFIG_FILE_NAME)
        self.__loadFromSection(section, bDelOldCmds=True, asDefault=True)

    def __loadUserConfig(self):
        section = Settings.g_instance.userPrefs
        if not section.has_key(CommandMapping.__USER_CONFIG_SECTION_NAME):
            return
        section = section[CommandMapping.__USER_CONFIG_SECTION_NAME]
        self.__loadFromSection(section, bDelOldCmds=True, asDefault=False)

    def __loadDevelopment(self):
        pass 

 

А в этих файлах есть все необходимые кнопки геймпадов:

'X:\Games\World_of_Warplanes\res_bw\scripts\client\Keys.pyc'

"""
This module contains definitions of all keycodes known to the client.
They are set to the values as in the C++ files.
"""
MODIFIER_SHIFT = 1
MODIFIER_CTRL = 2
MODIFIER_ALT = 4
KEY_NOT_FOUND = 0
KEY_NONE = 0
KEY_NULL = 0
KEY_ESCAPE = 1
KEY_1 = 2
KEY_2 = 3
KEY_3 = 4
KEY_4 = 5
KEY_5 = 6
KEY_6 = 7
KEY_7 = 8
KEY_8 = 9
KEY_9 = 10
KEY_0 = 11
KEY_MINUS = 12
KEY_EQUALS = 13
KEY_BACKSPACE = 14
KEY_TAB = 15
KEY_Q = 16
KEY_W = 17
KEY_E = 18
KEY_R = 19
KEY_T = 20
KEY_Y = 21
KEY_U = 22
KEY_I = 23
KEY_O = 24
KEY_P = 25
KEY_LBRACKET = 26
KEY_RBRACKET = 27
KEY_RETURN = 28
KEY_LCONTROL = 29
KEY_A = 30
KEY_S = 31
KEY_D = 32
KEY_F = 33
KEY_G = 34
KEY_H = 35
KEY_J = 36
KEY_K = 37
KEY_L = 38
KEY_SEMICOLON = 39
KEY_APOSTROPHE = 40
KEY_GRAVE = 41
KEY_LSHIFT = 42
KEY_BACKSLASH = 43
KEY_Z = 44
KEY_X = 45
KEY_C = 46
KEY_V = 47
KEY_B = 48
KEY_N = 49
KEY_M = 50
KEY_COMMA = 51
KEY_PERIOD = 52
KEY_SLASH = 53
KEY_RSHIFT = 54
KEY_NUMPADSTAR = 55
KEY_LALT = 56
KEY_SPACE = 57
KEY_CAPSLOCK = 58
KEY_F1 = 59
KEY_F2 = 60
KEY_F3 = 61
KEY_F4 = 62
KEY_F5 = 63
KEY_F6 = 64
KEY_F7 = 65
KEY_F8 = 66
KEY_F9 = 67
KEY_F10 = 68
KEY_NUMLOCK = 69
KEY_SCROLL = 70
KEY_NUMPAD7 = 71
KEY_NUMPAD8 = 72
KEY_NUMPAD9 = 73
KEY_NUMPADMINUS = 74
KEY_NUMPAD4 = 75
KEY_NUMPAD5 = 76
KEY_NUMPAD6 = 77
KEY_ADD = 78
KEY_NUMPAD1 = 79
KEY_NUMPAD2 = 80
KEY_NUMPAD3 = 81
KEY_NUMPAD0 = 82
KEY_NUMPADPERIOD = 83
KEY_OEM_102 = 86
KEY_F11 = 87
KEY_F12 = 88
KEY_F13 = 100
KEY_F14 = 101
KEY_F15 = 102
KEY_KANA = 112
KEY_ABNT_C1 = 115
KEY_CONVERT = 121
KEY_NOCONVERT = 123
KEY_YEN = 125
KEY_ABNT_C2 = 126
KEY_NUMPADEQUALS = 141
KEY_PREVTRACK = 144
KEY_AT = 145
KEY_COLON = 146
KEY_UNDERLINE = 147
KEY_KANJI = 148
KEY_STOP = 149
KEY_AX = 150
KEY_UNLABELED = 151
KEY_NEXTTRACK = 153
KEY_NUMPADENTER = 156
KEY_RCONTROL = 157
KEY_MUTE = 160
KEY_CALCULATOR = 161
KEY_PLAYPAUSE = 162
KEY_MEDIASTOP = 164
KEY_VOLUMEDOWN = 174
KEY_VOLUMEUP = 176
KEY_WEBHOME = 178
KEY_NUMPADCOMMA = 179
KEY_NUMPADSLASH = 181
KEY_SYSRQ = 183
KEY_RALT = 184
KEY_PAUSE = 197
KEY_HOME = 199
KEY_UPARROW = 200
KEY_PGUP = 201
KEY_LEFTARROW = 203
KEY_RIGHTARROW = 205
KEY_END = 207
KEY_DOWNARROW = 208
KEY_PGDN = 209
KEY_INSERT = 210
KEY_DELETE = 211
KEY_LWIN = 219
KEY_RWIN = 220
KEY_APPS = 221
KEY_POWER = 222
KEY_SLEEP = 223
KEY_WAKE = 227
KEY_WEBSEARCH = 229
KEY_WEBFAVORITES = 230
KEY_WEBREFRESH = 231
KEY_WEBSTOP = 232
KEY_WEBFORWARD = 233
KEY_WEBBACK = 234
KEY_MYCOMPUTER = 235
KEY_MAIL = 236
KEY_MEDIASELECT = 237
KEY_IME_CHAR = 255
KEY_MOUSE0 = 256
KEY_LEFTMOUSE = 256
KEY_MOUSE1 = 257
KEY_RIGHTMOUSE = 257
KEY_MOUSE2 = 258
KEY_MIDDLEMOUSE = 258
KEY_MOUSE3 = 259
KEY_MOUSE4 = 260
KEY_MOUSE5 = 261
KEY_MOUSE6 = 262
KEY_MOUSE7 = 263
KEY_JOY0 = 272
KEY_JOY1 = 273
KEY_JOY2 = 274
KEY_JOY3 = 275
KEY_JOY4 = 276
KEY_JOY5 = 277
KEY_JOY6 = 278
KEY_JOY7 = 279
KEY_JOY8 = 280
KEY_JOY9 = 281
KEY_JOY10 = 282
KEY_JOY11 = 283
KEY_JOY12 = 284
KEY_JOY13 = 285
KEY_JOY14 = 286
KEY_JOY15 = 287
KEY_JOY16 = 288
KEY_JOY17 = 289
KEY_JOY18 = 290
KEY_JOY19 = 291
KEY_JOY20 = 292
KEY_JOY21 = 293
KEY_JOY22 = 294
KEY_JOY23 = 295
KEY_JOY24 = 296
KEY_JOY25 = 297
KEY_JOY26 = 298
KEY_JOY27 = 299
KEY_JOY28 = 300
KEY_JOY29 = 301
KEY_JOY30 = 302
KEY_JOY31 = 303
KEY_JOYDUP = 272
KEY_JOYDDOWN = 273
KEY_JOYDLEFT = 274
KEY_JOYDRIGHT = 275
KEY_JOYSTART = 276
KEY_JOYSELECT = 277
KEY_JOYBACK = 277
KEY_JOYALPUSH = 278
KEY_JOYARPUSH = 279
KEY_JOYCROSS = 280
KEY_JOYA = 280
KEY_JOYCIRCLE = 281
KEY_JOYB = 281
KEY_JOYSQUARE = 282
KEY_JOYX = 282
KEY_JOYTRIANGLE = 283
KEY_JOYY = 283
KEY_JOYL1 = 284
KEY_JOYBLACK = 284
KEY_JOYR1 = 285
KEY_JOYWHITE = 285
KEY_JOYL2 = 286
KEY_JOYLTRIGGER = 286
KEY_JOYR2 = 287
KEY_JOYRTRIGGER = 287
KEY_JOYAHARD = 288
KEY_JOYBHARD = 289
KEY_JOYXHARD = 290
KEY_JOYYHARD = 291
KEY_JOYBLACKHARD = 292
KEY_JOYWHITEHARD = 293
KEY_JOYLTRIGGERHARD = 294
KEY_JOYRTRIGGERHARD = 295
KEY_JOYALUP = 304
KEY_JOYALDOWN = 305
KEY_JOYALLEFT = 306
KEY_JOYALRIGHT = 307
KEY_JOYARUP = 308
KEY_JOYARDOWN = 309
KEY_JOYARLEFT = 310
KEY_JOYARRIGHT = 311
KEY_JOYPOVUP = 312
KEY_JOYPOVUPRIGHT = 313
KEY_JOYPOVRIGHT = 330
KEY_JOYPOVDOWNRIGHT = 331
KEY_JOYPOVDOWN = 332
KEY_JOYPOVDOWNLEFT = 333
KEY_JOYPOVLEFT = 334
KEY_JOYPOVUPLEFT = 335
KEY_DEBUG = 336
AXIS_LX = 0
AXIS_LY = 1
AXIS_LZ = 2
AXIS_RX = 3
AXIS_RY = 4
AXIS_RZ = 5
AXIS_U = 6
AXIS_V = 7 

 

'X:\Games\World_of_Tanks\res_bw\scripts\client\Keys.pyc'

"""
This module contains definitions of all keycodes known to the client.
They are set to the values as in the C++ files.
"""
MODIFIER_SHIFT = 1
MODIFIER_CTRL = 2
MODIFIER_ALT = 4
KEY_NOT_FOUND = 0
KEY_NONE = 0
KEY_NULL = 0
KEY_ESCAPE = 1
KEY_1 = 2
KEY_2 = 3
KEY_3 = 4
KEY_4 = 5
KEY_5 = 6
KEY_6 = 7
KEY_7 = 8
KEY_8 = 9
KEY_9 = 10
KEY_0 = 11
KEY_MINUS = 12
KEY_EQUALS = 13
KEY_BACKSPACE = 14
KEY_TAB = 15
KEY_Q = 16
KEY_W = 17
KEY_E = 18
KEY_R = 19
KEY_T = 20
KEY_Y = 21
KEY_U = 22
KEY_I = 23
KEY_O = 24
KEY_P = 25
KEY_LBRACKET = 26
KEY_RBRACKET = 27
KEY_RETURN = 28
KEY_LCONTROL = 29
KEY_A = 30
KEY_S = 31
KEY_D = 32
KEY_F = 33
KEY_G = 34
KEY_H = 35
KEY_J = 36
KEY_K = 37
KEY_L = 38
KEY_SEMICOLON = 39
KEY_APOSTROPHE = 40
KEY_GRAVE = 41
KEY_LSHIFT = 42
KEY_BACKSLASH = 43
KEY_Z = 44
KEY_X = 45
KEY_C = 46
KEY_V = 47
KEY_B = 48
KEY_N = 49
KEY_M = 50
KEY_COMMA = 51
KEY_PERIOD = 52
KEY_SLASH = 53
KEY_RSHIFT = 54
KEY_NUMPADSTAR = 55
KEY_LALT = 56
KEY_SPACE = 57
KEY_CAPSLOCK = 58
KEY_F1 = 59
KEY_F2 = 60
KEY_F3 = 61
KEY_F4 = 62
KEY_F5 = 63
KEY_F6 = 64
KEY_F7 = 65
KEY_F8 = 66
KEY_F9 = 67
KEY_F10 = 68
KEY_NUMLOCK = 69
KEY_SCROLL = 70
KEY_NUMPAD7 = 71
KEY_NUMPAD8 = 72
KEY_NUMPAD9 = 73
KEY_NUMPADMINUS = 74
KEY_NUMPAD4 = 75
KEY_NUMPAD5 = 76
KEY_NUMPAD6 = 77
KEY_ADD = 78
KEY_NUMPAD1 = 79
KEY_NUMPAD2 = 80
KEY_NUMPAD3 = 81
KEY_NUMPAD0 = 82
KEY_NUMPADPERIOD = 83
KEY_OEM_102 = 86
KEY_F11 = 87
KEY_F12 = 88
KEY_F13 = 100
KEY_F14 = 101
KEY_F15 = 102
KEY_KANA = 112
KEY_ABNT_C1 = 115
KEY_CONVERT = 121
KEY_NOCONVERT = 123
KEY_YEN = 125
KEY_ABNT_C2 = 126
KEY_NUMPADEQUALS = 141
KEY_PREVTRACK = 144
KEY_AT = 145
KEY_COLON = 146
KEY_UNDERLINE = 147
KEY_KANJI = 148
KEY_STOP = 149
KEY_AX = 150
KEY_UNLABELED = 151
KEY_NEXTTRACK = 153
KEY_NUMPADENTER = 156
KEY_RCONTROL = 157
KEY_MUTE = 160
KEY_CALCULATOR = 161
KEY_PLAYPAUSE = 162
KEY_MEDIASTOP = 164
KEY_VOLUMEDOWN = 174
KEY_VOLUMEUP = 176
KEY_WEBHOME = 178
KEY_NUMPADCOMMA = 179
KEY_NUMPADSLASH = 181
KEY_SYSRQ = 183
KEY_RALT = 184
KEY_PAUSE = 197
KEY_HOME = 199
KEY_UPARROW = 200
KEY_PGUP = 201
KEY_LEFTARROW = 203
KEY_RIGHTARROW = 205
KEY_END = 207
KEY_DOWNARROW = 208
KEY_PGDN = 209
KEY_INSERT = 210
KEY_DELETE = 211
KEY_LWIN = 219
KEY_RWIN = 220
KEY_APPS = 221
KEY_POWER = 222
KEY_SLEEP = 223
KEY_WAKE = 227
KEY_WEBSEARCH = 229
KEY_WEBFAVORITES = 230
KEY_WEBREFRESH = 231
KEY_WEBSTOP = 232
KEY_WEBFORWARD = 233
KEY_WEBBACK = 234
KEY_MYCOMPUTER = 235
KEY_MAIL = 236
KEY_MEDIASELECT = 237
KEY_IME_CHAR = 255
KEY_MOUSE0 = 256
KEY_LEFTMOUSE = 256
KEY_MOUSE1 = 257
KEY_RIGHTMOUSE = 257
KEY_MOUSE2 = 258
KEY_MIDDLEMOUSE = 258
KEY_MOUSE3 = 259
KEY_MOUSE4 = 260
KEY_MOUSE5 = 261
KEY_MOUSE6 = 262
KEY_MOUSE7 = 263
KEY_JOY0 = 272
KEY_JOY1 = 273
KEY_JOY2 = 274
KEY_JOY3 = 275
KEY_JOY4 = 276
KEY_JOY5 = 277
KEY_JOY6 = 278
KEY_JOY7 = 279
KEY_JOY8 = 280
KEY_JOY9 = 281
KEY_JOY10 = 282
KEY_JOY11 = 283
KEY_JOY12 = 284
KEY_JOY13 = 285
KEY_JOY14 = 286
KEY_JOY15 = 287
KEY_JOY16 = 288
KEY_JOY17 = 289
KEY_JOY18 = 290
KEY_JOY19 = 291
KEY_JOY20 = 292
KEY_JOY21 = 293
KEY_JOY22 = 294
KEY_JOY23 = 295
KEY_JOY24 = 296
KEY_JOY25 = 297
KEY_JOY26 = 298
KEY_JOY27 = 299
KEY_JOY28 = 300
KEY_JOY29 = 301
KEY_JOY30 = 302
KEY_JOY31 = 303
KEY_JOYDUP = 272
KEY_JOYDDOWN = 273
KEY_JOYDLEFT = 274
KEY_JOYDRIGHT = 275
KEY_JOYSTART = 276
KEY_JOYSELECT = 277
KEY_JOYBACK = 277
KEY_JOYALPUSH = 278
KEY_JOYARPUSH = 279
KEY_JOYCROSS = 280
KEY_JOYA = 280
KEY_JOYCIRCLE = 281
KEY_JOYB = 281
KEY_JOYSQUARE = 282
KEY_JOYX = 282
KEY_JOYTRIANGLE = 283
KEY_JOYY = 283
KEY_JOYL1 = 284
KEY_JOYBLACK = 284
KEY_JOYR1 = 285
KEY_JOYWHITE = 285
KEY_JOYL2 = 286
KEY_JOYLTRIGGER = 286
KEY_JOYR2 = 287
KEY_JOYRTRIGGER = 287
KEY_JOYAHARD = 288
KEY_JOYBHARD = 289
KEY_JOYXHARD = 290
KEY_JOYYHARD = 291
KEY_JOYBLACKHARD = 292
KEY_JOYWHITEHARD = 293
KEY_JOYLTRIGGERHARD = 294
KEY_JOYRTRIGGERHARD = 295
KEY_JOYALUP = 304
KEY_JOYALDOWN = 305
KEY_JOYALLEFT = 306
KEY_JOYALRIGHT = 307
KEY_JOYARUP = 308
KEY_JOYARDOWN = 309
KEY_JOYARLEFT = 310
KEY_JOYARRIGHT = 311
KEY_DEBUG = 312
KEY_LCDKB_LEFT = 320
KEY_LCDKB_RIGHT = 321
KEY_LCDKB_OK = 322
KEY_LCDKB_CANCEL = 323
KEY_LCDKB_UP = 324
KEY_LCDKB_DOWN = 325
KEY_LCDKB_MENU = 326
AXIS_LX = 0
AXIS_LY = 1
AXIS_RX = 2
AXIS_RY = 3 

 

Вывод - WoT (сам exe-файл) должен понимать кнопки/стики/триггеры геймпадов и джойстиков. Нужно просто сказать ему выполнять команды по нажатию кнопок не на клавиатуре/мышке.


Добавление нужных геймпадовских кнопок в файлик command_mapping.xml, ни к чему не привело. Я думаю что из-за отсутствия скрипта подключения геймпада к игре.

 

Блин, прямо руки опускаются - неужели те, кто знает и понимает python не хочет помочь, хоть советом, хоть направлением, хоть куском кода. Я сам не потяну создание этого всего, в связи с чем и предлагаю денег за реализацию.

Edited by kharlashkin
  • Upvote 2
  • Downvote 1
Link to comment
Short link
Share on other sites

  Блин, прямо руки опускаются - неужели те, кто знает и понимает python не хочет помочь, хоть советом, хоть направлением, хоть куском кода.

 

Не бросайте, я уверен, заинтересованные найдутся, помогут)) :flag:

Edited by leecher88
  • Upvote 1
  • Downvote 1
Link to comment
Short link
Share on other sites

Оказывается WoT принимает команды от геймпада почти "по-умолчанию". Спасибо inj3ct0r (я тебе должен) - подсказал как это проверить и дал скрипт, для отлавливания нажатий клавиш в ангаре с выводом системных сообщений.

post-19155-0-28963800-1396032890_thumb.jpg

Подключив геймпад к ноутбуку и жмакая кнопки увидел что игра принимает почти все нажатия, кроме крестовины и отклонения правого стика. В качестве пробы добавил кнопки в файл preferences.xml, как указано в этой теме на оф.форуме. В итоге - кнопки с геймпада действительно можно установить в качестве клавиш управления.

Теперь копаю скрипты из WoWP, там же геймпад полноценно поддерживается.


 

 

К сожалению, дело к ночи - к тому же для полноценной пробы нужен второй "фанатик" (типа меня). В связи с этим управление пока не настраивал - надо к этому серьезно подойти.

Игра понимает только ввод данных из активного окна, разумеется когда два окна рядом одно из них будет активным, второе нет. Из-за этого и не пробовал данную теорию.

Edited by kharlashkin
  • Upvote 1
  • Downvote 1
Link to comment
Short link
Share on other sites

Доброе время суток!

 

Мне (и не только мне) кажется. что тем способом, каким работает вибрация - нормально подключить геймпад не получиться. Клиент-серверная архитектура будет не так быстро работать, на вибрацию тайм-аут стоит 250мс - что будет если четверть секунды будет управление реагировать (?) - так не пойдет.

 

Соотвественно нужен как бы "подключающий" скрипт для геймпада - будем надеяться, что BigWorld одинаков в самолетах и танках. Исходя из этого предположения нужно выбрать из WoWP методы для xbox геймпада и создать этот самый подключающий скрипт, который будет использоваться BigWorld и подключать геймпад так же как и клавиатуру/мышь.

 

Взято из WoWP:

'/scripts/client/input/InputSubsystem/GamepadInput.pyс'

import Keys
import BWPersonality
from CameraStates import CameraState
from EntityHelpers import EntityStates
import GameEnvironment
from ICMultiUpdate import ICMultiUpdate
import InputMapping
import math
from MathExt import *
from consts import ROLL_AXIS, VERTICAL_AXIS, HORIZONTAL_AXIS, FORCE_AXIS, FLAPS_AXIS
from input.InputSubsystem.InputSubsystemBase import InputSubsystemBase
import wgPickle

class DummyMouseEvent:

    def __init__(self):
        self.dx = 0.0
        self.dy = 0.0
        self.dz = 0.0

    def comparison(a, b):
        return a.dx == b.dx and a.dy == b.dy

    def clone(self):
        res = DummyMouseEvent()
        res.dx = self.dx
        res.dy = self.dy
        return res


class GamepadInput(InputSubsystemBase, ICMultiUpdate):

    def __init__(self, profile):
        self.__profile = profile
        self.__holdDirection = None
        self.__lastDirection = Math.Vector3()
        self.__isExtraMode = False
        self.__data = DummyMouseEvent()
        self.__lastValue = Math.Vector2(0.0, 0.0)
        self.__notControlledByUser = False
        self.__laseCameraState = None

        class JoyEvent:

            def __init__(self):
                self.deviceId = None
                self.axis = None
                self.value = None
                return

        joyEvent = JoyEvent()
        for deviceId in BWPersonality.axis:
            for axis in BWPersonality.axis[deviceId]:
                joyEvent.deviceId = deviceId
                joyEvent.axis = axis
                joyEvent.value = BWPersonality.axis[deviceId][axis]
                self.processJoystickEvent(joyEvent)

        BigWorld.player().onStateChanged += self.__ePlayerAvatarChangeState
        ICMultiUpdate.__init__(self, (0.05, self.__sendCursor))
        return

    def notControlledByUser(self, value):
        self.__notControlledByUser = value

    def __sendCursor(self):
        if not self.__isRunning:
            return
        direction = GameEnvironment.getCamera().getStateObject().strategy.cursorDirection
        BigWorld.player().cell.sendDirection(direction)

    def __CursorToCenter(self):
        player = BigWorld.player()
        rotation = Math.Quaternion()
        rotation.fromEuler(player.roll, player.pitch, player.yaw)
        self.__targetPoint = rotation.rotateVec(Math.Vector3(0.0, 0.0, 1.0))

    @property
    def __inGame(self):
        return EntityStates.inState(BigWorld.player(), EntityStates.GAME)

    @property
    def __inCameraState(self):
        return GameEnvironment.getCamera().getState() == CameraState.GamepadCombat or GameEnvironment.getCamera().getState() == CameraState.GamepadAssault

    @property
    def __isRunning(self):
        return self.__inGame and self.__inCameraState and not self.__notControlledByUser

    def __ePlayerAvatarChangeState(self, oldState, newState):
        pass

    def restart(self):
        pass

    def dispose(self):
        ICMultiUpdate._SuspendUpdates(self)
        self.__profile = None
        return

    def processJoystickEvent(self, event):
        if not self.__isRunning:
            return
        jSet = InputMapping.g_instance.joystickSettings
        if event.axis == jSet.ROLL_AXIS and (event.deviceId == jSet.ROLL_DEVICE or 0 == jSet.ROLL_DEVICE):
            rValue = InputMapping.translateAxisValue(jSet.AXIS_X_CURVE, event.value)
            if abs(rValue) <= jSet.ROLL_DEAD_ZONE:
                self.__profile.sendPrimaryAxis(ROLL_AXIS, 0.0)
            else:
                rValue = math.copysign((abs(rValue) - jSet.ROLL_DEAD_ZONE) / (1.0 - jSet.ROLL_DEAD_ZONE), rValue)
                rValue = -rValue if jSet.INVERT_ROLL else rValue
                rValue = math.copysign(math.pow(abs(rValue), 1.0 + 3.0 * (1.0 - jSet.ROLL_SENSITIVITY)), rValue)
                self.__profile.sendPrimaryAxis(ROLL_AXIS, clamp(-1.0, -rValue, 1.0))
        elif event.axis == jSet.VERTICAL_AXIS and (event.deviceId == jSet.VERTICAL_DEVICE or 0 == jSet.VERTICAL_DEVICE):
            vValue = InputMapping.translateAxisValue(jSet.AXIS_Y_CURVE, event.value)
            if abs(vValue) <= jSet.VERTICAL_DEAD_ZONE:
                self.__profile.sendPrimaryAxis(VERTICAL_AXIS, 0.0)
            else:
                vValue = math.copysign((abs(vValue) - jSet.VERTICAL_DEAD_ZONE) / (1 - jSet.VERTICAL_DEAD_ZONE), vValue)
                vValue = vValue if jSet.INVERT_VERTICAL else -vValue
                vValue = math.copysign(math.pow(abs(vValue), 1.0 + 3.0 * (1.0 - jSet.VERTICAL_SENSITIVITY)), vValue)
            self.__lastValue.x = vValue
            GameEnvironment.getCamera().setRotationSpeed(Math.Vector2(math.radians(self.__lastValue.x * 45.0), math.radians(self.__lastValue.y * 45.0)))
        elif event.axis == jSet.HORIZONTAL_AXIS and (event.deviceId == jSet.HORIZONTAL_DEVICE or 0 == jSet.HORIZONTAL_DEVICE):
            hValue = InputMapping.translateAxisValue(jSet.AXIS_Z_CURVE, event.value)
            if abs(hValue) <= jSet.HORIZONTAL_DEAD_ZONE:
                self.__profile.sendPrimaryAxis(HORIZONTAL_AXIS, 0.0)
            else:
                hValue = math.copysign((abs(hValue) - jSet.HORIZONTAL_DEAD_ZONE) / (1 - jSet.HORIZONTAL_DEAD_ZONE), hValue)
                hValue = -hValue if jSet.INVERT_HORIZONTAL else hValue
                hValue = math.copysign(math.pow(abs(hValue), 1.0 + 3.0 * (1.0 - jSet.HORIZONTAL_SENSITIVITY)), hValue)
                self.__profile.sendPrimaryAxis(HORIZONTAL_AXIS, clamp(-1.0, hValue, 1.0))
            self.__lastValue.y = hValue
            GameEnvironment.getCamera().setRotationSpeed(Math.Vector2(math.radians(self.__lastValue.x * 45.0), math.radians(self.__lastValue.y * 45.0)))
        elif event.axis == jSet.FORCE_AXIS and (event.deviceId == jSet.FORCE_DEVICE or 0 == jSet.FORCE_DEVICE):
            fValue = event.value
            if abs(fValue) < jSet.FORCE_DEAD_ZONE:
                self.__profile.sendPrimaryAxis(FORCE_AXIS, 0.0)
            else:
                fValue = math.copysign((abs(fValue) - jSet.FORCE_DEAD_ZONE) / (1 - jSet.FORCE_DEAD_ZONE), fValue)
                fValue = -fValue if jSet.INVERT_FORCE else fValue
                self.__profile.sendPrimaryAxis(FORCE_AXIS, self.__renormalization(fValue))

    def setCursorCamera(self, isCursorCamera):
        pass

    def __renormalization(self, x):
        maxForce = InputMapping.g_instance.joystickSettings.POINT_OF_NORMAL_THRUST
        if x >= 1.0:
            return 1
        elif x > maxForce and x < 1:
            return 0
        else:
            return (x + 1) / (maxForce + 1) - 1 

'/scripts/client/InputMapping.pyс'

import inspect
import BigWorld
from Event import Event
import ResMgr
import Keys
import consts
from db.DBHelpers import readValue
from Helpers.i18n import makeString, localizeOptions
from MathExt import *
import math
import threading
from debug_utils import *
from input.ProfileLoader.DummyDeviceLoader import MouseDummy
from input.ProfileLoader.MouseLoader import MouseLoader
from input.ProfileLoader.JoystickLoader import JoystickSettings
from input.ProfileLoader.KeyMapingLoader import Keyboard
from input.ProfileLoader.GamepadLoader import GamepadProfileLoader
g_instance = None
g_descriptions = None
FORCE_DEFAULT_INPUT_PATH = False

def initInput(profileName, profilesPresets):
    global g_instance
    global g_descriptions
    g_descriptions = CommandDescriptions()
    g_instance = InputMapping(profileName, profilesPresets)


def translateAxisValue(axisCurve, axisValue):
    return math.copysign(axisCurve.calc(abs(axisValue)), axisValue)


SENSITIVITY_MIN = 0.05
SENSITIVITY_MAX = 2.5
HI_AXIS_BOUND = 0.5
LOW_AXIS_BOUND = 0.3

def convertToRealSensitivity(sliderValue):
    return sliderValue * (SENSITIVITY_MAX - SENSITIVITY_MIN) + SENSITIVITY_MIN


COMMANDS_TO_REFRESH = []
COMMANDS_TO_NOT_REFRESH = []
CHAT_COMMANDS = []
EQUIPMENT_COMMANDS = []

class CommandDescriptions(object):
    __DATA_PATH = 'scripts/command_mapping_description.xml'

    def __init__(self):
        self.__commands = {}
        rootSection = ResMgr.openSection(self.__DATA_PATH)
        commandIntID = 1
        for commandID, dataSection in rootSection.items():
            self.__commands[commandID] = CommandDescription(commandIntID)
            self.__commands[commandID].readFromDatasection(dataSection)
            globals()[commandID] = commandIntID
            commandIntID += 1

        if consts.IS_DEBUG_IMPORTED:
            from debug.AvatarDebug import DebugCommands
            self.loadMappingFromClass(DebugCommands, commandIntID)
        self.__fillGlobalCommandLists()
        ResMgr.purge(self.__DATA_PATH, True)

    def __fillGlobalCommandLists(self):
        global CHAT_COMMANDS
        global COMMANDS_TO_REFRESH
        global EQUIPMENT_COMMANDS
        global COMMANDS_TO_NOT_REFRESH
        COMMANDS_TO_REFRESH = [CMD_AUTOPILOT]
        COMMANDS_TO_NOT_REFRESH = [CMD_INTERMISSION_MENU,
         CMD_VISIBILITY_HUD,
         CMD_SHOW_CURSOR,
         CMD_HELP,
         CMD_SHOW_MAP]
        CHAT_COMMANDS = [CMD_F2_CHAT_COMMAND,
         CMD_F3_CHAT_COMMAND,
         CMD_F4_CHAT_COMMAND,
         CMD_F5_CHAT_COMMAND,
         CMD_F6_CHAT_COMMAND,
         CMD_F7_CHAT_COMMAND,
         CMD_F8_CHAT_COMMAND,
         CMD_F9_CHAT_COMMAND]
        EQUIPMENT_COMMANDS = [CMD_USE_EQUIPMENT_1, CMD_USE_EQUIPMENT_2, CMD_USE_EQUIPMENT_3]

    def loadMappingFromClass(self, classWithMapping, commandIntID):
        import inspect
        for commandID, value in inspect.getmembers(classWithMapping):
            if commandID.startswith('CMD_'):
                self.__commands[commandID] = CommandDescription(commandIntID, 'DEBUG')
                globals()[commandID] = commandIntID
                commandIntID += 1

    @property
    def commands(self):
        return self.__commands

    def getCommandWaitTime(self, commandName):
        if commandName in self.__commands:
            command = self.__commands[commandName]
            return command.waitTime
        return 0.0

    def getCommandGroupID(self, commandName):
        if commandName in self.__commands:
            command = self.__commands[commandName]
            return command.groupID
        return ''

    def getCommandLocalizationID(self, commandName):
        if commandName in self.__commands:
            command = self.__commands[commandName]
            return command.localizationID
        return ''

    def getLinkedAxisName(self, commandName):
        if commandName in self.__commands:
            command = self.__commands[commandName]
            return command.linkedAxisName
        else:
            return ''

    def getCommandIntID(self, commandName):
        if commandName in self.__commands:
            command = self.__commands[commandName]
            return command.commandID
        return ''

    def getCommandNameByID(self, commandID):
        for commandName, command in self.__commands.items():
            if commandID == command.commandID:
                return (commandName, command.groupName)

        return (None, None)


class CommandDescription():

    def __init__(self, commandIntID, groupName = 'MAIN', groupID = 'SETTINGS_BASIC'):
        self.commandID = commandIntID
        self.linkedAxisName = ''
        self.localizationID = ''
        self.groupName = groupName
        self.groupID = groupID
        self.waitTime = 0.0

    def readFromDatasection(self, dataSection):
        readValue(self, dataSection, 'linkedAxisName', '')
        readValue(self, dataSection, 'localizationID', '')
        readValue(self, dataSection, 'groupName', 'MAIN')
        readValue(self, dataSection, 'groupID', 'SETTINGS_BASIC')
        readValue(self, dataSection, 'waitTime', 0.0)


class InputMappingLoader(threading.Thread):

    def __init__(self, threadData, callback):
        threading.Thread.__init__(self)
        self.__threadData = threadData
        self.__callback = callback

    def run(self):
        self.__callback(self.__threadData)


class InputMapping(object):
    __DATA_PATH = 'scripts/input_mapping/'
    __DEFAULTS_PATH = __DATA_PATH + 'defaults/'
    __DEFAULT_CONFIG_FILE_NAME = 'keyboard'
    __PRIMARY_SETTINGS_LOADERS = {consts.INPUT_SYSTEM_STATE.KEYBOARD: MouseDummy,
     consts.INPUT_SYSTEM_STATE.JOYSTICK: JoystickSettings,
     consts.INPUT_SYSTEM_STATE.GAMEPAD_DIRECT_CONTROL: JoystickSettings,
     consts.INPUT_SYSTEM_STATE.MOUSE: MouseLoader}

    @property
    def descriptions(self):
        return g_descriptions

    def __init__(self, currentProfileName, profilesPresets):
        self.__profileNames = self.loadProfileNames(profilesPresets)
        if ResMgr.useDefaultDataPath() or FORCE_DEFAULT_INPUT_PATH:
            self.__dataPath = self.__DATA_PATH
        else:
            self.__dataPath = ResMgr.getInputMappingPath(self.__DEFAULTS_PATH, '.xml', self.__profileNames)
        self.__checkInputFiles(self.__DEFAULTS_PATH, self.__dataPath)
        LOG_INFO('Input mapping data path: ' + self.__dataPath)
        if currentProfileName not in self.__profileNames:
            if self.__DEFAULT_CONFIG_FILE_NAME in self.__profileNames:
                currentProfileName = self.__DEFAULT_CONFIG_FILE_NAME
            elif self.__profileNames:
                currentProfileName = self.__profileNames[0]
            else:
                LOG_ERROR('InputMapping::__init__ - can"t load current profile name:', currentProfileName)
        self.onDefaultMappingRestored = Event()
        self.onProfileLoaded = Event()
        self.__loadLock = threading.Lock()
        self.__loadInProgressProfile = None
        self.__load(currentProfileName, False, True, None)
        self.onSaveControls = Event()
        return

    def __loadLockAcquire(self):
        self.__loadLock.acquire()

    def __loadLockRelease(self):
        self.__loadLock.release()

    def __getCallbackClient(self):
        return self.__callbackClient

    def __setCallbackClient(self, val):
        self.__callbackClient = val

    callbackClient = property(__getCallbackClient, __setCallbackClient)

    def __checkInputFiles(self, defaultDataPath, actualDataPath):
        if defaultDataPath == actualDataPath:
            LOG_ERROR('defaultDataPath equals actualDataPath:', defaultDataPath)
        else:
            defaultlDataSection = ResMgr.openSection(defaultDataPath)
            if defaultlDataSection == None:
                LOG_ERROR('default data section does not exist')
            else:
                actualDataSection = ResMgr.openSection(actualDataPath)
                if actualDataSection == None:
                    LOG_ERROR('data section must already exist', actualDataPath)
                else:
                    for profile in self.__profileNames:
                        self.__checkInputFile(defaultlDataSection, actualDataSection, profile)

        return

    def __checkInputFile(self, defaultlDataSection, actualDataSection, profile):
        fileName = profile + '.xml'
        if not defaultlDataSection.has_key(fileName):
            LOG_ERROR('default data section does not contain file', fileName)
        else:
            defaultProfile = defaultlDataSection[fileName]
            if defaultProfile == None:
                LOG_ERROR('cannot open default file', fileName)
            elif actualDataSection.has_key(fileName):
                actualProfile = actualDataSection[fileName]
                if actualProfile == None:
                    LOG_ERROR('cannot open file', fileName)
                else:
                    defaultVersion = defaultProfile.readInt('FILE_VERSION', 0)
                    actualVersion = actualProfile.readInt('FILE_VERSION', 0)
                    if actualVersion < defaultVersion:
                        actualProfile.copy(defaultProfile)
                        actualProfile.save()
                        LOG_INFO('version mismatch, replaced', fileName, defaultVersion, actualVersion)
            else:
                actualProfile = actualDataSection.createSection(fileName)
                if actualProfile == None:
                    LOG_ERROR('cannot create new section', fileName)
                else:
                    actualProfile.copy(defaultProfile)
                    actualProfile.save()
                    LOG_INFO('created profile from default', fileName)
        return

    def getAllCommandsIds(self):
        commadIds = list()
        for command in g_descriptions.commands.values():
            commadIds.append(command.commandID)

        return commadIds

    def getCommandsButtonsList(self, commandIDsList):
        from input.InputController import UserKeyEvent
        keys = []
        for commandID in commandIDsList:
            keyCodes = self.keyboardSettings.getCommandKeys(commandID)
            if keyCodes and len(keyCodes) > 0:
                keyInfo = keyCodes[0]
                keys.append(UserKeyEvent(keyInfo['code'], keyInfo['device']))

        return keys

    def getAllCommandsButtonsList(self, ignoreCommandIDsList):
        from input.InputController import UserKeyEvent
        keys = []
        for command in g_descriptions.commands.values():
            keyCodes = None
            if command.commandID not in ignoreCommandIDsList:
                keyCodes = self.keyboardSettings.getCommandKeys(command.commandID)
            if keyCodes and len(keyCodes) > 0:
                keyInfo = keyCodes[0]
                keys.append(UserKeyEvent(keyInfo['code'], keyInfo['device']))

        return keys

    def getProfileNames(self):
        return self.__profileNames

    def loadProfileNames(self, profilesPresets):
        """
        @param profilesPresets: <dict> Ex.: {mouse_directional : [{name:mouse_directional, localizationID:CONTROL_PROFILE_DEFAULT}] }
        @return: <list>
        """
        profiles = []
        rootSection = ResMgr.openSection(self.__DEFAULTS_PATH)
        for fileName in rootSection.keys():
            extentionPos = fileName.find('.xml')
            if extentionPos != -1:
                profileName = fileName[0:extentionPos]
                isPreset = False
                if not isPreset:
                    profiles.append(profileName)

        ResMgr.purge(self.__DEFAULTS_PATH, True)
        return profiles

    def getLocalizedProfileNameCaps(self, profileName = None):
        if profileName is None:
            profileName = self.getCurProfileName()
        return localizeOptions('CONTROL_PROFILE_%s_CAPS' % profileName.upper())

    def getLocalizedProfileName(self, profileName = None):
        if profileName is None:
            profileName = self.getCurProfileName()
        return localizeOptions('CONTROL_PROFILE_%s' % profileName.upper())

    def getLocalizedProfileNames(self):
        locProfiles = []
        profiles = self.getProfileNames()
        for profile in profiles:
            locProfiles.append(localizeOptions('CONTROL_PROFILE_' + profile.upper()))

        return locProfiles

    def getProfileNameByIndex(self, index):
        profiles = self.getProfileNames()
        return profiles[index]

    def isCommandKey(self, command, key, keyDevice, axisIndex = -1, axisDevice = 0):
        return self.keyboardSettings.isCommandKey(command, key, keyDevice, axisIndex, axisDevice)

    def isMouseActivateEvent(self, key, event):
        if isinstance(event, BigWorld.KeyEvent):
            return event.wg_isMouseActivateEvent
        return False

    def setSwitchingStyle(self, command, switchingStyle):
        self.keyboardSettings.setSwitchingStyle(command, switchingStyle)

    def getSwitchingStyle(self, command):
        return self.keyboardSettings.getSwitchingStyle(command)

    def invertY(self):
        self.keyboardSettings.INVERT_Y = 1 - self.keyboardSettings.INVERT_Y
        self.primarySettings.INVERT_Y = 1 - self.primarySettings.INVERT_Y

    @property
    def mouseSettings(self):
        return self.primarySettings

    @property
    def joystickSettings(self):
        return self.primarySettings

    def __saveProfile(self, rootSection, profilePath):
        try:
            rootSection.save()
        except IOError:
            LOG_ERROR("Couldn't save profile: " + profilePath)
        else:
            LOG_DEBUG('Controls saved to ' + profilePath)

        ResMgr.purge(profilePath, True)

    def saveControlls(self, curProfileName, profileNameKeyBoard = None):
        if self.__loadInProgressProfile:
            LOG_INFO('::saveControlls: Save rejected. Profile %s is loading' % self.__loadInProgressProfile['profileName'])
            return
        else:
            try:
                self.__loadLockAcquire()
                profilePath = ''.join([self.__dataPath, self.__curProfileName if curProfileName is None else curProfileName, '.xml'])
                rootSection = ResMgr.openSection(profilePath)
                self.keyboardSettings.flash(rootSection['KEYBOARD'])
                self.primarySettings.flash(rootSection['PRIMARY'])
                self.__saveProfile(rootSection, profilePath)
                if profileNameKeyBoard is not None:
                    LOG_INFO('saveControlls - save KEYBOARD to %s.xml curProfileName=%s' % (profileNameKeyBoard, curProfileName))
                    keyBoardPath = ''.join([self.__dataPath, profileNameKeyBoard, '.xml'])
                    keyBoardRootSection = ResMgr.openSection(keyBoardPath)
                    self.keyboardSettings.flash(keyBoardRootSection['KEYBOARD'])
                    self.__saveProfile(keyBoardRootSection, keyBoardPath)
                self.onSaveControls()
            except:
                LOG_CURRENT_EXCEPTION()
            finally:
                self.__loadLockRelease()

            return

    def getCurProfileName(self):
        return self.__curProfileName

    def setCurProfileName(self, ProfileName):
        LOG_INFO('setCurProfileName - old=(%s), new=(%s)' % (self.__curProfileName, ProfileName))
        self.__curProfileName = ProfileName

    def getCurProfileIndex(self):
        profiles = self.getProfileNames()
        return profiles.index(self.__curProfileName)

    def changeProfile(self, profileName):
        self.__load(profileName, False, True, None)
        return

    def loadProfileFromPreset(self, profileName, loadFromDefaults, profileNameForKeyboardSettings):
        self.__load(profileName, loadFromDefaults, False, profileNameForKeyboardSettings)

    def restoreDefaultsCommandMapping(self):
        self.__load(self.__curProfileName, True, True, None)
        return

    def getCurMapping(self):
        return self.keyboardSettings.getCurMapping(self.joystickSettings)

    def applyNewMapping(self, mapping):
        self.keyboardSettings.applyNewMapping(mapping, self.joystickSettings)

    def setKeyboardLining(self, value):
        self.keyboardSettings.setLining(value)

    def getKeyboardLining(self):
        return self.keyboardSettings.getLining()

    def getLocalizedCommandKeysAndAxes(self, commandName):
        """
        Returns list with localized names of keys/axes that correspond to given command or empty list
        @param commandName: command name from command_mapping_description.xml
        @rtype: list
        """
        keysControls = []
        curMapping = self.getCurMapping()
        record = curMapping.get(g_descriptions.getCommandIntID(commandName), None)
        if record is not None:
            for key in record['keyNames']:
                if 'KEY_NONE' != key['name']:
                    keysControls.append(getKeyLocalization(key['name']))

            if not self.currentProfileType == consts.INPUT_SYSTEM_STATE.KEYBOARD:
                if not self.currentProfileType == consts.INPUT_SYSTEM_STATE.MOUSE:
                    if record['linkedAxisIndex'] != -1:
                        keysControls.append(getAxisLocalization(record['linkedAxisIndex']))
                    record['fireAxisIndex'] != -1 and keysControls.append(getAxisLocalization(record['fireAxisIndex']))
        return keysControls

    def getKeyControlsHelp(self, dataKeysControls):
        keysControls = {}
        curMapping = self.getCurMapping()
        for cmdID, record in curMapping.items():
            cmdLabel = getCommandLocalization(record['cmdName'])
            if cmdLabel is not None and cmdID in dataKeysControls:
                keysControls[cmdID] = {'keys': [],
                 'isFireAxis': [],
                 'axisSign': []}
                for key in record['keyNames']:
                    if 'KEY_NONE' != key['name']:
                        keysControls[cmdID]['keys'].append(key['name'])
                        keysControls[cmdID]['isFireAxis'].append(False)
                        keysControls[cmdID]['axisSign'].append(0)

                if record['linkedAxisIndex'] != -1:
                    keysControls[cmdID]['keys'].append('_'.join(['AXIS', str(record['linkedAxisIndex'])]))
                    keysControls[cmdID]['isFireAxis'].append(False)
                    keysControls[cmdID]['axisSign'].append(0)
                elif record['fireAxisIndex'] != -1:
                    keysControls[cmdID]['keys'].append('_'.join(['AXIS', str(record['fireAxisIndex'])]))
                    keysControls[cmdID]['isFireAxis'].append(True)
                    keysControls[cmdID]['axisSign'].append(record['fireAxisSign'])

        return keysControls

    def __load(self, profileName, loadFromDefaults, isOverrideCurProfileName, profileNameForKeyboardSettings, loadFromDefaultsKeyboardSettings = False):
        if isOverrideCurProfileName:
            self.__curProfileName = profileName
        profilePath = profileName + '.xml'
        profilePath = self.__DEFAULTS_PATH + profilePath if loadFromDefaults else self.__dataPath + profilePath
        LOG_DEBUG("Try to load config profile '%s'" % profileName)
        o = dict(profileName=self.__curProfileName, loadFromDefaults=loadFromDefaults)
        resources = (profilePath,)
        if profileNameForKeyboardSettings is not None:
            o['profileNameForKeyboardSettings'] = profileNameForKeyboardSettings
            o['loadFromDefaultsKeyboardSettings'] = loadFromDefaultsKeyboardSettings
            profilePathForKeyboardSettings = self.__DEFAULTS_PATH + profileNameForKeyboardSettings + '.xml' if loadFromDefaultsKeyboardSettings else self.__dataPath + profileNameForKeyboardSettings + '.xml'
            resources = (profilePath, profilePathForKeyboardSettings)
        self.__loadInProgressProfile = o
        BigWorld.loadResourceListBG(resources, self.__profileDataSectionLoaded, 64, o)
        return

    @property
    def currentProfileType(self):
        return self.__currentProfileType

    def __profileDataSectionLoaded(self, resourceRefs):
        profilePath = resourceRefs.resourceIDs[0]
        LOG_DEBUG("Loading config profile from '%s'" % profilePath, resourceRefs.has_key(profilePath))
        if not resourceRefs.has_key(profilePath):
            LOG_DEBUG("Can't load '%s'" % profilePath)
            if resourceRefs.extraData['loadFromDefaults']:
                if resourceRefs.extraData['profileName'] != self.__DEFAULT_CONFIG_FILE_NAME:
                    self.__load(self.__DEFAULT_CONFIG_FILE_NAME, True, True, None)
                else:
                    LOG_ERROR("Can't load system configs")
            else:
                self.__load(resourceRefs.extraData['profileName'], True, True, None)
        else:
            LOG_DEBUG('Profile successfully loaded')
            rootSection = resourceRefs[profilePath]
            if self.__loadInProgressProfile == resourceRefs.extraData:
                self.__loadLockAcquire()
                try:
                    s = rootSection.readString('TYPE')
                    try:
                        self.__currentProfileType = consts.INPUT_SYSTEM_STATE.__dict__[s]
                    except KeyError:
                        LOG_DEBUG('Bad profile type - [' + str(s) + '] in ' + profilePath)
                        raise

                    rootSectionKeyboard = rootSection
                    if len(resourceRefs.resourceIDs) > 1 and 'profileNameForKeyboardSettings' in resourceRefs.extraData:
                        keyboardPath = resourceRefs.resourceIDs[1]
                        if resourceRefs.has_key(keyboardPath):
                            rootSectionKeyboard = resourceRefs[keyboardPath]
                            LOG_INFO('__profileDataSectionLoaded - KEYBOARD loaded from %s profilePath=%s' % (keyboardPath, profilePath))
                            ResMgr.purge(keyboardPath, True)
                    self.keyboardSettings = Keyboard(rootSectionKeyboard['KEYBOARD'])
                    profileLoaderClass = self.__PRIMARY_SETTINGS_LOADERS.get(self.currentProfileType, None)
                    if profileLoaderClass is not None:
                        self.primarySettings = profileLoaderClass(rootSection['PRIMARY'])
                    else:
                        LOG_INFO('::__profileDataSectionLoaded: Profile [%s],ProfileType[%s] ignored as an obsolete loading' % (profilePath, self.currentProfileType))
                    ResMgr.purge(profilePath, True)
                    self.onProfileLoaded()
                except:
                    LOG_CURRENT_EXCEPTION()
                finally:
                    self.__loadLockRelease()
                    self.__loadInProgressProfile = None

            else:
                LOG_INFO('::__profileDataSectionLoaded: Profile [%s] ignored as an obsolete loading' % profilePath)
        return


class Command():
    MODIFIERS = {'ALT': lambda : BigWorld.isKeyDown(Keys.KEY_RALT, 0) or BigWorld.isKeyDown(Keys.KEY_LALT, 0),
     'SHIFT': lambda : BigWorld.isKeyDown(Keys.KEY_RSHIFT, 0) or BigWorld.isKeyDown(Keys.KEY_LSHIFT, 0),
     'CTRL': lambda : BigWorld.isKeyDown(Keys.KEY_RCONTROL, 0) or BigWorld.isKeyDown(Keys.KEY_LCONTROL, 0),
     'RALT': lambda : BigWorld.isKeyDown(Keys.KEY_RALT, 0),
     'LALT': lambda : BigWorld.isKeyDown(Keys.KEY_LALT, 0),
     'LCTRL': lambda : BigWorld.isKeyDown(Keys.KEY_LCONTROL, 0),
     'RCTRL': lambda : BigWorld.isKeyDown(Keys.KEY_RCONTROL, 0)}

    def __init__(self, id, linkedAxisName, fireAxisIndex, fireAxisSign, fireAxisDevice, keyNames, modifier, isBlock, isBase, switchingStyle):
        self.id = id
        self.linkedAxisName = linkedAxisName
        self.fireAxisIndex = fireAxisIndex
        self.fireAxisSign = fireAxisSign
        self.fireAxisDevice = fireAxisDevice
        self.__modifierFnc = Command.MODIFIERS.get(modifier, None)
        self.applyNewKeys(keyNames)
        self.isBlock = isBlock
        self.isBase = isBase
        self.switchingStyle = switchingStyle
        self.lastExecuteTime = 0.0
        return

    def checkKey(self, key, keyDevice):
        for keyRecord in self.__keys:
            if key == keyRecord['code'] and (keyDevice == keyRecord['device'] or keyRecord['device'] == 0):
                return keyRecord

        return False

    def checkAxis(self, axisIndex, axisDevice):
        import BWPersonality
        if axisIndex != -1 and self.fireAxisIndex != -1:
            if self.fireAxisDevice == 0 or self.fireAxisDevice == axisDevice:
                return self.fireAxisIndex == axisIndex and axisIndex in BWPersonality.axis[axisDevice]
        return False

    def isModifierActive(self):
        return self.__modifierFnc is None or self.__modifierFnc()

    def isCommandActive(self):
        import BWPersonality
        if self.fireAxisIndex != -1:
            for device, axes in BWPersonality.axis.items():
                if (device == self.fireAxisDevice or self.fireAxisDevice == 0) and self.fireAxisIndex in axes:
                    axisValue = axes[self.fireAxisIndex]
                    if sign(axisValue) == sign(self.fireAxisSign) and abs(axisValue) > HI_AXIS_BOUND:
                        return True

        for key in self.__keys:
            if BigWorld.isKeyDown(key['code'], key['device']):
                return True

        return False

    def clear(self):
        self.__keys = []

    def flash(self, rootSection):
        rootSection.deleteSection(self.id)
        section = rootSection.createSection(self.id)
        keysSection = section.createSection('FIRE_KEYS')
        for key in self.__keys:
            keySection = keysSection.createSection('FIRE_KEY')
            keySection.writeString('fireKeyName', key['name'])
            keySection.writeInt64('fireKeyDevice', key['device'])

        section.writeInt('fireAxisIndex', self.fireAxisIndex)
        section.writeInt('fireAxisSign', self.fireAxisSign)
        section.writeInt64('fireAxisDevice', self.fireAxisDevice)
        section.writeInt('isBase', self.isBase)
        section.writeInt('switchingStyle', self.switchingStyle)

    def getMappedKeyCodes(self):
        return self.__keys

    def applyNewKeys(self, keyNames):
        """
        Fill 'code'(int keyCode) for all keys in record and drop all last empty keys
        
        keyNames : {'name':str,'device':UINT}
        
        """
        self.__keys = keyNames
        keyIndex = 0
        lastValidKeyIndex = 0
        for key in self.__keys:
            key['code'] = getKeyCodeByName(key['name'])
            keyIndex += 1
            if key['name'] != 'KEY_NONE':
                lastValidKeyIndex = keyIndex

        self.__keys = self.__keys[:lastValidKeyIndex]


def getKeyNameByCode(keyCode):
    if keyCode == 0:
        return 'KEY_NONE'
    for k, v in Keys.__dict__.items():
        if v == keyCode:
            return k

    return 'KEY_NONE'


def getKeyCodeByName(keyName):
    if keyName in Keys.__dict__:
        return int(Keys.__dict__.get(keyName))
    else:
        return 0


def getKeyLocalization(keyName):
    return makeString('#keys:' + keyName)


def getAxisLocalization(axisIndex):
    if axisIndex == -1:
        return ''
    return getKeyLocalization('_'.join(['AXIS', str(axisIndex)]))


def getCommandLocalization(commandName):
    localizationID = g_descriptions.getCommandLocalizationID(commandName)
    if localizationID == '':
        return None
    else:
        return makeString('#options:KEYMAPPING/' + localizationID)
        return None 

'/scripts/client/input/Profile/GamepadProfile.pyс'

import BigWorld
import GameEnvironment
from ICMultiUpdate import ICMultiUpdate
import InputMapping
from MathExt import clamp, FloatToCInt16
import math
from _preparedBattleData_db import preparedBattleData
from consts import FORCE_AXIS, FLAPS_AXIS, ROLL_AXIS, VERTICAL_AXIS, HORIZONTAL_AXIS
from input.InputSubsystem.GamepadInput import GamepadInput
from input.InputSubsystem.KeyboardInput import KeyboardInput
from input.Profile.ProfileBase import IProfileBase

class GamepadProfile(IProfileBase, ICMultiUpdate):

    def __init__(self, inputAxis, notControlledByUser):
        self._notControlledByUser = notControlledByUser
        self._forciblySendAxis = False
        InputMapping.g_instance.onSaveControls += self._onSaveControls
        self.__axisKeyBoard = [0.0] * 5
        self.__axisJoy = [0.0] * 5
        self.__lastAxis = [0.0] * 5
        self.__gamepad = GamepadInput(self)
        self.__keyboard = KeyboardInput(self)
        self._onSaveControls()

    def getCurrentForce(self):
        return self.__axisJoy[FORCE_AXIS]

    def dispose(self):
        InputMapping.g_instance.onSaveControls -= self._onSaveControls
        self.__gamepad.dispose()
        self.__keyboard.dispose()
        self.__gamepad = None
        self.__keyboard = None
        return

    def restart(self):
        pass

    def _onSaveControls(self):
        pass

    def setCamDirection(self, direction):
        pass

    def __send(self, axis):
        player = BigWorld.player()
        value = self.__axisJoy[axis] * (1.0 - abs(self.__axisKeyBoard[axis])) + self.__axisKeyBoard[axis]
        if self.__lastAxis[axis] != value:
            player.cell.sendInputJoyAxis(axis, FloatToCInt16(value))
            player.applyInputAxis(axis, value)
            self.__lastAxis[axis] = value

    def sendAxis(self, axis, value):
        self.__axisKeyBoard[axis] = value
        if self._notControlledByUser:
            return
        self.__send(axis)

    def sendPrimaryAxis(self, axis, value):
        self.__axisJoy[axis] = value
        if self._notControlledByUser:
            return
        self.__send(axis)

    def notControlledByUser(self, value):
        self._notControlledByUser = value
        self.__gamepad.notControlledByUser(value)
        if not self._notControlledByUser:
            for axis in range(0, 5):
                self.__send(axis)

    def processMouseEvent(self, event):
        pass

    def processJoystickEvent(self, event):
        self.__gamepad.processJoystickEvent(event)

    def addCommandListeners(self, processor):
        self.__keyboard.addCommandListeners(processor)

    def removeCommandListeners(self, processor):
        self.__keyboard.removeCommandListeners(processor)

    def __autopilotUpdate(self):
        """successor should provide an update of this method through its own ICMultiUpdate """
        owner = BigWorld.player()
        if abs(owner.pitch) < 0.25 * math.pi:
            rollAxis = owner.roll * 0.5
            rollAxis = min(1.0, max(-1.0, rollAxis))
            owner.applyInputAxis(ROLL_AXIS, -rollAxis)
        pitchAxis = owner.pitch
        pitchAxis = min(1.0, max(-1.0, pitchAxis))
        owner.applyInputAxis(VERTICAL_AXIS, pitchAxis)
        owner.applyInputAxis(HORIZONTAL_AXIS, 0) 

'\scripts\input_mapping\defaults\gamepad_dc_1_xbox_360.xml'

<gamepad_dc_1_xbox_360.xml>
  <FILE_VERSION>	66	</FILE_VERSION>
  <TYPE>GAMEPAD_DIRECT_CONTROL</TYPE>
  <PRIMARY>
    <COMMON>
      <TOP_ROLL_BOUND>	30	</TOP_ROLL_BOUND>
      <BOTTOM_ROLL_BOUND>	25	</BOTTOM_ROLL_BOUND>
      <ROLL_LINING_ZONE>2.0</ROLL_LINING_ZONE>
      <SEALING_SPLINE>
        <p>0.0  0.8</p>
        <p>0.4  0.9</p>
        <p>0.7  0.95</p>
        <p>0.95 1.0</p>
        <pointCount>	100	</pointCount>
      </SEALING_SPLINE>
      <BOTTOM_BLOCK_ROLL>30.0</BOTTOM_BLOCK_ROLL>
      <ROLL_BASIS>0.7</ROLL_BASIS>
      <VERTICAL_POW>	1	</VERTICAL_POW>
      <HORIZONTAL_POW>	1	</HORIZONTAL_POW>
      <VERTICAL_POW_INNER>0.8</VERTICAL_POW_INNER>
      <HORIZONTAL_POW_INNER>0.8</HORIZONTAL_POW_INNER>
      <ROLL_POW>1.0</ROLL_POW>
    </COMMON>
    <INVERT_Y>	1	</INVERT_Y>
    <AUTOMATIC_FLAPS>	false	</AUTOMATIC_FLAPS>
    <ROLL_AXIS>	0	</ROLL_AXIS>
    <VERTICAL_AXIS>	1	</VERTICAL_AXIS>
    <FORCE_AXIS>	4	</FORCE_AXIS>
    <HORIZONTAL_AXIS>	3	</HORIZONTAL_AXIS>
    <INVERT_ROLL>	0	</INVERT_ROLL>
    <INVERT_VERTICAL>	0	</INVERT_VERTICAL>
    <INVERT_FORCE>	0	</INVERT_FORCE>
    <INVERT_HORIZONTAL>	0	</INVERT_HORIZONTAL>
    <AXIS_X_CURVE>
      <p>0.0 0.00</p>
      <p>0.01 0.01</p>
      <p>0.1 0.1</p>
      <p>0.2 0.2</p>
      <p>0.3 0.3</p>
      <p>0.4 0.4</p>
      <p>0.5 0.5</p>
      <p>0.6 0.6</p>
      <p>0.7 0.7</p>
      <p>0.8 0.8</p>
      <p>0.9 0.9</p>
      <p>1.0 1.0</p>
      <pointCount>	100	</pointCount>
    </AXIS_X_CURVE>
    <AXIS_Y_CURVE>
      <p>0.0 0.00</p>
      <p>0.01 0.01</p>
      <p>0.1 0.1</p>
      <p>0.2 0.2</p>
      <p>0.3 0.3</p>
      <p>0.4 0.4</p>
      <p>0.5 0.5</p>
      <p>0.6 0.6</p>
      <p>0.7 0.7</p>
      <p>0.8 0.8</p>
      <p>0.9 0.9</p>
      <p>1.0 1.0</p>
      <pointCount>	100	</pointCount>
    </AXIS_Y_CURVE>
    <AXIS_Z_CURVE>
      <p>0.0 0.00</p>
      <p>0.01 0.001</p>
      <p>0.1 0.1</p>
      <p>0.2 0.2</p>
      <p>0.3 0.3</p>
      <p>0.4 0.4</p>
      <p>0.5 0.5</p>
      <p>0.6 0.6</p>
      <p>0.7 0.7</p>
      <p>0.8 0.8</p>
      <p>0.9 0.9</p>
      <p>1.0 1.0</p>
      <pointCount>	100	</pointCount>
    </AXIS_Z_CURVE>
    <ROLL_SENSITIVITY>	1,000000	</ROLL_SENSITIVITY>
    <ROLL_DEAD_ZONE>	0,100000	</ROLL_DEAD_ZONE>
    <VERTICAL_SENSITIVITY>	1,000000	</VERTICAL_SENSITIVITY>
    <VERTICAL_DEAD_ZONE>	0,100000	</VERTICAL_DEAD_ZONE>
    <FORCE_SENSITIVITY>	1,000000	</FORCE_SENSITIVITY>
    <FORCE_DEAD_ZONE>	0,100000	</FORCE_DEAD_ZONE>
    <HORIZONTAL_SENSITIVITY>	1,000000	</HORIZONTAL_SENSITIVITY>
    <HORIZONTAL_DEAD_ZONE>	0,100000	</HORIZONTAL_DEAD_ZONE>
    <ROLL_DEVICE>	0	</ROLL_DEVICE>
    <VERTICAL_DEVICE>	0	</VERTICAL_DEVICE>
    <FORCE_DEVICE>	0	</FORCE_DEVICE>
    <HORIZONTAL_DEVICE>	0	</HORIZONTAL_DEVICE>
    <POINT_OF_NORMAL_THRUST>	0,000000	</POINT_OF_NORMAL_THRUST>
    <SLIP_COMPENSATION>	true	</SLIP_COMPENSATION>
    <SWITCHING_STYLE>	0	</SWITCHING_STYLE>
  </PRIMARY>
  <KEYBOARD>
    <INVERT_Y>	1	</INVERT_Y>
    <YAW_SPEED_CURVE>
      <p>0.0  0.0</p>
      <p>0.1  0.05</p>
      <p>0.2  0.2</p>
      <p>0.3  0.3</p>
      <p>0.5  0.6</p>
      <p>0.8  0.9</p>
      <p>1.0  1.0</p>
      <pointCount>	100	</pointCount>
    </YAW_SPEED_CURVE>
    <ROLL_SPEED_CURVE>
      <p>0.0  0.0</p>
      <p>0.1  0.05</p>
      <p>0.2  0.2</p>
      <p>0.3  0.3</p>
      <p>0.5  0.6</p>
      <p>0.8  0.9</p>
      <p>1.0  1.0</p>
      <pointCount>	100	</pointCount>
    </ROLL_SPEED_CURVE>
    <PITCH_SPEED_CURVE>
      <p>0.0  0.0</p>
      <p>0.1  0.05</p>
      <p>0.2  0.2</p>
      <p>0.3  0.3</p>
      <p>0.5  0.6</p>
      <p>0.8  0.9</p>
      <p>1.0  1.0</p>
      <pointCount>	100	</pointCount>
    </PITCH_SPEED_CURVE>
    <KEY_SENSITIVITY>	0,500000	</KEY_SENSITIVITY>
    <ENABLE_LINING>	1	</ENABLE_LINING>
    <MAPPING>
      <MAIN>
        <CMD_BATTLE_MODE>
          <FIRE_KEYS>
            <FIRE_KEY>
              <fireKeyName>KEY_LSHIFT</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
            <FIRE_KEY>
              <fireKeyName>KEY_JOYL2</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
          </FIRE_KEYS>
          <fireAxisIndex>	-1	</fireAxisIndex>
          <fireAxisSign>	0	</fireAxisSign>
          <fireAxisDevice>	0	</fireAxisDevice>
          <switchingStyle>	0	</switchingStyle>
        </CMD_BATTLE_MODE>
        <CMD_PITCH_DOWN>
          <FIRE_KEYS>
            <FIRE_KEY>
              <fireKeyName>KEY_UPARROW</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
          </FIRE_KEYS>
          <fireAxisIndex>	-1	</fireAxisIndex>
          <fireAxisSign>	1	</fireAxisSign>
          <fireAxisDevice>	0	</fireAxisDevice>
          <switchingStyle>	-1	</switchingStyle>
        </CMD_PITCH_DOWN>
        <CMD_PITCH_UP>
          <FIRE_KEYS>
            <FIRE_KEY>
              <fireKeyName>KEY_DOWNARROW</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
          </FIRE_KEYS>
          <fireAxisIndex>	-1	</fireAxisIndex>
          <fireAxisSign>	-1	</fireAxisSign>
          <fireAxisDevice>	0	</fireAxisDevice>
          <switchingStyle>	-1	</switchingStyle>
        </CMD_PITCH_UP>
        <CMD_ROLL_LEFT>
          <FIRE_KEYS>
            <FIRE_KEY>
              <fireKeyName>KEY_LEFTARROW</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
          </FIRE_KEYS>
          <fireAxisIndex>	-1	</fireAxisIndex>
          <fireAxisSign>	-1	</fireAxisSign>
          <fireAxisDevice>	0	</fireAxisDevice>
          <switchingStyle>	-1	</switchingStyle>
        </CMD_ROLL_LEFT>
        <CMD_ROLL_RIGHT>
          <FIRE_KEYS>
            <FIRE_KEY>
              <fireKeyName>KEY_RIGHTARROW</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
          </FIRE_KEYS>
          <fireAxisIndex>	-1	</fireAxisIndex>
          <fireAxisSign>	1	</fireAxisSign>
          <fireAxisDevice>	0	</fireAxisDevice>
          <switchingStyle>	-1	</switchingStyle>
        </CMD_ROLL_RIGHT>
        <CMD_USE_EQUIPMENT_1>
          <FIRE_KEYS>
            <FIRE_KEY>
              <fireKeyName>KEY_4</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
            <FIRE_KEY>
              <fireKeyName>KEY_1</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
          </FIRE_KEYS>
          <fireAxisIndex>	-1	</fireAxisIndex>
          <fireAxisSign>	0	</fireAxisSign>
          <fireAxisDevice>	0	</fireAxisDevice>
          <switchingStyle>	-1	</switchingStyle>
          <isBase>	0	</isBase>
        </CMD_USE_EQUIPMENT_1>
        <CMD_USE_EQUIPMENT_2>
          <FIRE_KEYS>
            <FIRE_KEY>
              <fireKeyName>KEY_5</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
            <FIRE_KEY>
              <fireKeyName>KEY_2</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
          </FIRE_KEYS>
          <fireAxisIndex>	-1	</fireAxisIndex>
          <fireAxisSign>	0	</fireAxisSign>
          <fireAxisDevice>	0	</fireAxisDevice>
          <switchingStyle>	-1	</switchingStyle>
          <isBase>	0	</isBase>
        </CMD_USE_EQUIPMENT_2>
        <CMD_USE_EQUIPMENT_3>
          <FIRE_KEYS>
            <FIRE_KEY>
              <fireKeyName>KEY_6</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
            <FIRE_KEY>
              <fireKeyName>KEY_3</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
          </FIRE_KEYS>
          <fireAxisIndex>	-1	</fireAxisIndex>
          <fireAxisSign>	0	</fireAxisSign>
          <fireAxisDevice>	0	</fireAxisDevice>
          <switchingStyle>	-1	</switchingStyle>
          <isBase>	0	</isBase>
        </CMD_USE_EQUIPMENT_3>
        <CMD_TURN_LEFT>
          <FIRE_KEYS>
            <FIRE_KEY>
              <fireKeyName>KEY_A</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
          </FIRE_KEYS>
          <fireAxisIndex>	-1	</fireAxisIndex>
          <fireAxisSign>	-1	</fireAxisSign>
          <fireAxisDevice>	0	</fireAxisDevice>
          <switchingStyle>	-1	</switchingStyle>
        </CMD_TURN_LEFT>
        <CMD_TURN_RIGHT>
          <FIRE_KEYS>
            <FIRE_KEY>
              <fireKeyName>KEY_D</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
          </FIRE_KEYS>
          <fireAxisIndex>	-1	</fireAxisIndex>
          <fireAxisSign>	1	</fireAxisSign>
          <fireAxisDevice>	0	</fireAxisDevice>
          <switchingStyle>	-1	</switchingStyle>
        </CMD_TURN_RIGHT>
        <CMD_PRIMARY_FIRE>
          <FIRE_KEYS>
            <FIRE_KEY>
              <fireKeyName>KEY_SPACE</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
          </FIRE_KEYS>
          <fireAxisIndex>	2	</fireAxisIndex>
          <fireAxisSign>	1	</fireAxisSign>
          <fireAxisDevice>	0	</fireAxisDevice>
          <switchingStyle>	-1	</switchingStyle>
        </CMD_PRIMARY_FIRE>
        <CMD_LAUNCH_ROCKET>
          <FIRE_KEYS>
            <FIRE_KEY>
              <fireKeyName>KEY_R</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
            <FIRE_KEY>
              <fireKeyName>KEY_JOYY</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
          </FIRE_KEYS>
          <fireAxisIndex>	-1	</fireAxisIndex>
          <fireAxisSign>	1	</fireAxisSign>
          <fireAxisDevice>	0	</fireAxisDevice>
          <switchingStyle>	-1	</switchingStyle>
        </CMD_LAUNCH_ROCKET>
        <CMD_LAUNCH_BOMB>
          <FIRE_KEYS>
            <FIRE_KEY>
              <fireKeyName>KEY_B</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
            <FIRE_KEY>
              <fireKeyName>KEY_JOY9</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
          </FIRE_KEYS>
          <fireAxisIndex>	-1	</fireAxisIndex>
          <fireAxisSign>	0	</fireAxisSign>
          <fireAxisDevice>	0	</fireAxisDevice>
          <switchingStyle>	-1	</switchingStyle>
        </CMD_LAUNCH_BOMB>
        <CMD_INCREASE_FORCE>
          <FIRE_KEYS>
            <FIRE_KEY>
              <fireKeyName>KEY_W</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
          </FIRE_KEYS>
          <fireAxisIndex>	-1	</fireAxisIndex>
          <fireAxisSign>	1	</fireAxisSign>
          <fireAxisDevice>	0	</fireAxisDevice>
          <switchingStyle>	1	</switchingStyle>
        </CMD_INCREASE_FORCE>
        <CMD_ENGINE_OFF>
          <FIRE_KEYS>
            <FIRE_KEY>
              <fireKeyName>KEY_S</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
          </FIRE_KEYS>
          <fireAxisIndex>	-1	</fireAxisIndex>
          <fireAxisSign>	-1	</fireAxisSign>
          <fireAxisDevice>	0	</fireAxisDevice>
          <switchingStyle>	-1	</switchingStyle>
        </CMD_ENGINE_OFF>
        <CMD_FLAPS_UP>
          <FIRE_KEYS>
            <FIRE_KEY>
              <fireKeyName>KEY_E</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
          </FIRE_KEYS>
          <fireAxisIndex>	2	</fireAxisIndex>
          <fireAxisSign>	-1	</fireAxisSign>
          <fireAxisDevice>	0	</fireAxisDevice>
          <isBase>	0	</isBase>
          <switchingStyle>	1	</switchingStyle>
        </CMD_FLAPS_UP>
        <CMD_SHOW_PLAYERS_INFO>
          <FIRE_KEYS>
            <FIRE_KEY>
              <fireKeyName>KEY_LALT</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
          </FIRE_KEYS>
          <fireAxisIndex>	-1	</fireAxisIndex>
          <fireAxisSign>	0	</fireAxisSign>
          <fireAxisDevice>	0	</fireAxisDevice>
          <isBase>	0	</isBase>
          <switchingStyle>	1	</switchingStyle>
        </CMD_SHOW_PLAYERS_INFO>
        <CMD_LOCK_TARGET>
          <FIRE_KEYS>
            <FIRE_KEY>
              <fireKeyName>KEY_C</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
          </FIRE_KEYS>
          <fireAxisIndex>	-1	</fireAxisIndex>
          <fireAxisSign>	0	</fireAxisSign>
          <fireAxisDevice>	0	</fireAxisDevice>
          <switchingStyle>	-1	</switchingStyle>
          <isBase>	0	</isBase>
        </CMD_LOCK_TARGET>
        <CMD_LOCK_TARGET_IN_SCREEN_CENTER>
          <FIRE_KEYS>
            <FIRE_KEY>
              <fireKeyName>KEY_NONE</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
            <FIRE_KEY>
              <fireKeyName>KEY_JOYSQUARE</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
          </FIRE_KEYS>
          <fireAxisIndex>	-1	</fireAxisIndex>
          <fireAxisSign>	0	</fireAxisSign>
          <fireAxisDevice>	0	</fireAxisDevice>
          <isBase>	0	</isBase>
          <switchingStyle>	-1	</switchingStyle>
        </CMD_LOCK_TARGET_IN_SCREEN_CENTER>
        <CMD_NEXT_TARGET>
          <FIRE_KEYS>
            <FIRE_KEY>
              <fireKeyName>KEY_X</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
            <FIRE_KEY>
              <fireKeyName>KEY_JOY8</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
          </FIRE_KEYS>
          <fireAxisIndex>	-1	</fireAxisIndex>
          <fireAxisSign>	0	</fireAxisSign>
          <fireAxisDevice>	0	</fireAxisDevice>
          <isBase>	0	</isBase>
          <switchingStyle>	-1	</switchingStyle>
        </CMD_NEXT_TARGET>
        <CMD_NEXT_TARGET_TEAM_OBJECT>
          <FIRE_KEYS>
            <FIRE_KEY>
              <fireKeyName>KEY_V</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
          </FIRE_KEYS>
          <fireAxisIndex>	-1	</fireAxisIndex>
          <fireAxisSign>	0	</fireAxisSign>
          <fireAxisDevice>	0	</fireAxisDevice>
          <isBase>	0	</isBase>
          <switchingStyle>	-1	</switchingStyle>
        </CMD_NEXT_TARGET_TEAM_OBJECT>
        <CMD_SHOW_MAP>
          <FIRE_KEYS>
            <FIRE_KEY>
              <fireKeyName>KEY_M</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
          </FIRE_KEYS>
          <fireAxisIndex>	-1	</fireAxisIndex>
          <fireAxisSign>	0	</fireAxisSign>
          <fireAxisDevice>	0	</fireAxisDevice>
          <isBase>	0	</isBase>
          <switchingStyle>	1	</switchingStyle>
        </CMD_SHOW_MAP>
        <CMD_SHOW_CURSOR>
          <FIRE_KEYS>
            <FIRE_KEY>
              <fireKeyName>KEY_LCONTROL</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
            <FIRE_KEY>
              <fireKeyName>KEY_RCONTROL</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
          </FIRE_KEYS>
          <fireAxisIndex>	-1	</fireAxisIndex>
          <fireAxisSign>	0	</fireAxisSign>
          <fireAxisDevice>	0	</fireAxisDevice>
          <isBase>	0	</isBase>
          <switchingStyle>	1	</switchingStyle>
        </CMD_SHOW_CURSOR>
        <CMD_MINIMAP_ZOOM_IN>
          <FIRE_KEYS>
            <FIRE_KEY>
              <fireKeyName>KEY_RBRACKET</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
          </FIRE_KEYS>
          <fireAxisIndex>	-1	</fireAxisIndex>
          <fireAxisSign>	0	</fireAxisSign>
          <fireAxisDevice>	0	</fireAxisDevice>
          <isBase>	0	</isBase>
          <switchingStyle>	-1	</switchingStyle>
        </CMD_MINIMAP_ZOOM_IN>
        <CMD_MINIMAP_ZOOM_OUT>
          <FIRE_KEYS>
            <FIRE_KEY>
              <fireKeyName>KEY_LBRACKET</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
          </FIRE_KEYS>
          <fireAxisIndex>	-1	</fireAxisIndex>
          <fireAxisSign>	0	</fireAxisSign>
          <fireAxisDevice>	0	</fireAxisDevice>
          <isBase>	0	</isBase>
          <switchingStyle>	-1	</switchingStyle>
        </CMD_MINIMAP_ZOOM_OUT>
        <CMD_MINIMAP_SIZE_INC>
          <FIRE_KEYS>
            <FIRE_KEY>
              <fireKeyName>KEY_EQUALS</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
            <FIRE_KEY>
              <fireKeyName>KEY_ADD</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
          </FIRE_KEYS>
          <fireAxisIndex>	-1	</fireAxisIndex>
          <fireAxisSign>	0	</fireAxisSign>
          <fireAxisDevice>	0	</fireAxisDevice>
          <isBase>	0	</isBase>
          <switchingStyle>	-1	</switchingStyle>
        </CMD_MINIMAP_SIZE_INC>
        <CMD_MINIMAP_SIZE_DEC>
          <FIRE_KEYS>
            <FIRE_KEY>
              <fireKeyName>KEY_MINUS</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
            <FIRE_KEY>
              <fireKeyName>KEY_NUMPADMINUS</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
          </FIRE_KEYS>
          <fireAxisIndex>	-1	</fireAxisIndex>
          <fireAxisSign>	0	</fireAxisSign>
          <fireAxisDevice>	0	</fireAxisDevice>
          <isBase>	0	</isBase>
          <switchingStyle>	-1	</switchingStyle>
        </CMD_MINIMAP_SIZE_DEC>
        <CMD_SNIPER_CAMERA>
          <FIRE_KEYS>
            <FIRE_KEY>
              <fireKeyName>KEY_F</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
            <FIRE_KEY>
              <fireKeyName>KEY_JOY15</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
          </FIRE_KEYS>
          <fireAxisIndex>	-1	</fireAxisIndex>
          <fireAxisSign>	0	</fireAxisSign>
          <fireAxisDevice>	0	</fireAxisDevice>
          <isBase>	0	</isBase>
          <switchingStyle>	0	</switchingStyle>
        </CMD_SNIPER_CAMERA>
        <CMD_BOMBING_SIGHT>
          <FIRE_KEYS>
            <FIRE_KEY>
              <fireKeyName>KEY_H</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
          </FIRE_KEYS>
          <fireAxisIndex>	-1	</fireAxisIndex>
          <fireAxisSign>	0	</fireAxisSign>
          <fireAxisDevice>	0	</fireAxisDevice>
          <isBase>	0	</isBase>
          <switchingStyle>	0	</switchingStyle>
        </CMD_BOMBING_SIGHT>
        <CMD_CURSOR_CAMERA>
          <FIRE_KEYS>
            <FIRE_KEY>
              <fireKeyName>KEY_MOUSE1</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
          </FIRE_KEYS>
          <fireAxisIndex>	-1	</fireAxisIndex>
          <fireAxisSign>	0	</fireAxisSign>
          <fireAxisDevice>	0	</fireAxisDevice>
          <isBase>	0	</isBase>
          <switchingStyle>	1	</switchingStyle>
        </CMD_CURSOR_CAMERA>
        <CMD_TARGET_CAMERA>
          <FIRE_KEYS>
            <FIRE_KEY>
              <fireKeyName>KEY_G</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
          </FIRE_KEYS>
          <fireAxisIndex>	-1	</fireAxisIndex>
          <fireAxisSign>	1	</fireAxisSign>
          <fireAxisDevice>	0	</fireAxisDevice>
          <isBase>	0	</isBase>
          <switchingStyle>	1	</switchingStyle>
        </CMD_TARGET_CAMERA>
        <CMD_BACK_VIEW>
          <FIRE_KEYS>
            <FIRE_KEY>
              <fireKeyName>KEY_Q</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
          </FIRE_KEYS>
          <fireAxisIndex>	-1	</fireAxisIndex>
          <fireAxisSign>	0	</fireAxisSign>
          <fireAxisDevice>	0	</fireAxisDevice>
          <isBase>	0	</isBase>
          <switchingStyle>	1	</switchingStyle>
        </CMD_BACK_VIEW>
        <CMD_SIDE_VIEW_LEFT>
          <FIRE_KEYS>
            <FIRE_KEY>
              <fireKeyName>KEY_NUMPAD4</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
            <FIRE_KEY>
              <fireKeyName>KEY_JOYPOVLEFT</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
          </FIRE_KEYS>
          <fireAxisIndex>	-1	</fireAxisIndex>
          <fireAxisSign>	0	</fireAxisSign>
          <fireAxisDevice>	0	</fireAxisDevice>
          <isBase>	0	</isBase>
          <switchingStyle>	1	</switchingStyle>
        </CMD_SIDE_VIEW_LEFT>
        <CMD_SIDE_VIEW_RIGHT>
          <FIRE_KEYS>
            <FIRE_KEY>
              <fireKeyName>KEY_NUMPAD6</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
            <FIRE_KEY>
              <fireKeyName>KEY_JOYPOVRIGHT</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
          </FIRE_KEYS>
          <fireAxisIndex>	-1	</fireAxisIndex>
          <fireAxisSign>	0	</fireAxisSign>
          <fireAxisDevice>	0	</fireAxisDevice>
          <isBase>	0	</isBase>
          <switchingStyle>	1	</switchingStyle>
        </CMD_SIDE_VIEW_RIGHT>
        <CMD_SIDE_VIEW_UP>
          <FIRE_KEYS>
            <FIRE_KEY>
              <fireKeyName>KEY_NUMPAD8</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
            <FIRE_KEY>
              <fireKeyName>KEY_JOYPOVUP</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
          </FIRE_KEYS>
          <fireAxisIndex>	-1	</fireAxisIndex>
          <fireAxisSign>	0	</fireAxisSign>
          <fireAxisDevice>	0	</fireAxisDevice>
          <isBase>	0	</isBase>
          <switchingStyle>	1	</switchingStyle>
        </CMD_SIDE_VIEW_UP>
        <CMD_SIDE_VIEW_DOWN>
          <FIRE_KEYS>
            <FIRE_KEY>
              <fireKeyName>KEY_NUMPAD2</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
            <FIRE_KEY>
              <fireKeyName>KEY_JOYPOVDOWN</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
          </FIRE_KEYS>
          <fireAxisIndex>	-1	</fireAxisIndex>
          <fireAxisSign>	0	</fireAxisSign>
          <fireAxisDevice>	0	</fireAxisDevice>
          <isBase>	0	</isBase>
          <switchingStyle>	1	</switchingStyle>
        </CMD_SIDE_VIEW_DOWN>
        <CMD_SIDE_VIEW_DOWN_LEFT>
          <FIRE_KEYS>
            <FIRE_KEY>
              <fireKeyName>KEY_NUMPAD1</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
            <FIRE_KEY>
              <fireKeyName>KEY_JOYPOVDOWNLEFT</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
          </FIRE_KEYS>
          <fireAxisIndex>	-1	</fireAxisIndex>
          <fireAxisSign>	0	</fireAxisSign>
          <fireAxisDevice>	0	</fireAxisDevice>
          <isBase>	0	</isBase>
          <switchingStyle>	1	</switchingStyle>
        </CMD_SIDE_VIEW_DOWN_LEFT>
        <CMD_SIDE_VIEW_DOWN_RIGHT>
          <FIRE_KEYS>
            <FIRE_KEY>
              <fireKeyName>KEY_NUMPAD3</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
            <FIRE_KEY>
              <fireKeyName>KEY_JOYPOVDOWNRIGHT</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
          </FIRE_KEYS>
          <fireAxisIndex>	-1	</fireAxisIndex>
          <fireAxisSign>	0	</fireAxisSign>
          <fireAxisDevice>	0	</fireAxisDevice>
          <isBase>	0	</isBase>
          <switchingStyle>	1	</switchingStyle>
        </CMD_SIDE_VIEW_DOWN_RIGHT>
        <CMD_SIDE_VIEW_UP_LEFT>
          <FIRE_KEYS>
            <FIRE_KEY>
              <fireKeyName>KEY_NUMPAD7</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
            <FIRE_KEY>
              <fireKeyName>KEY_JOYPOVUPLEFT</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
          </FIRE_KEYS>
          <fireAxisIndex>	-1	</fireAxisIndex>
          <fireAxisSign>	0	</fireAxisSign>
          <fireAxisDevice>	0	</fireAxisDevice>
          <isBase>	0	</isBase>
          <switchingStyle>	1	</switchingStyle>
        </CMD_SIDE_VIEW_UP_LEFT>
        <CMD_SIDE_VIEW_UP_RIGHT>
          <FIRE_KEYS>
            <FIRE_KEY>
              <fireKeyName>KEY_NUMPAD9</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
            <FIRE_KEY>
              <fireKeyName>KEY_JOYPOVUPRIGHT</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
          </FIRE_KEYS>
          <fireAxisIndex>	-1	</fireAxisIndex>
          <fireAxisSign>	0	</fireAxisSign>
          <fireAxisDevice>	0	</fireAxisDevice>
          <isBase>	0	</isBase>
          <switchingStyle>	1	</switchingStyle>
        </CMD_SIDE_VIEW_UP_RIGHT>
        <CMD_SIDE_CAMERA_ALT>
          <FIRE_KEYS>
            <FIRE_KEY>
              <fireKeyName>KEY_NUMPAD5</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
          </FIRE_KEYS>
          <fireAxisIndex>	-1	</fireAxisIndex>
          <fireAxisSign>	0	</fireAxisSign>
          <fireAxisDevice>	0	</fireAxisDevice>
          <isBase>	0	</isBase>
          <switchingStyle>	1	</switchingStyle>
        </CMD_SIDE_CAMERA_ALT>
        <CMD_PUSH_TO_TALK>
          <FIRE_KEYS>
            <FIRE_KEY>
              <fireKeyName>KEY_GRAVE</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
          </FIRE_KEYS>
          <fireAxisIndex>	-1	</fireAxisIndex>
          <fireAxisSign>	0	</fireAxisSign>
          <fireAxisDevice>	0	</fireAxisDevice>
          <isBase>	0	</isBase>
          <switchingStyle>	-1	</switchingStyle>
        </CMD_PUSH_TO_TALK>
        <CMD_PUSH_TO_TALK_SQUAD>
          <FIRE_KEYS>
            <FIRE_KEY>
              <fireKeyName>KEY_Z</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
          </FIRE_KEYS>
          <fireAxisIndex>	-1	</fireAxisIndex>
          <fireAxisSign>	0	</fireAxisSign>
          <fireAxisDevice>	0	</fireAxisDevice>
          <isBase>	0	</isBase>
          <switchingStyle>	0	</switchingStyle>
        </CMD_PUSH_TO_TALK_SQUAD>
        <CMD_TOGGLE_ARENA_VOICE_CHANNEL>
          <FIRE_KEYS>
            <FIRE_KEY>
              <fireKeyName>KEY_Y</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
          </FIRE_KEYS>
          <fireAxisIndex>	-1	</fireAxisIndex>
          <fireAxisSign>	0	</fireAxisSign>
          <fireAxisDevice>	0	</fireAxisDevice>
          <isBase>	0	</isBase>
          <switchingStyle>	-1	</switchingStyle>
        </CMD_TOGGLE_ARENA_VOICE_CHANNEL>
        <CMD_SHOW_TEAMS>
          <FIRE_KEYS>
            <FIRE_KEY>
              <fireKeyName>KEY_TAB</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
          </FIRE_KEYS>
          <fireAxisIndex>	-1	</fireAxisIndex>
          <fireAxisSign>	0	</fireAxisSign>
          <fireAxisDevice>	0	</fireAxisDevice>
          <isBase>	0	</isBase>
          <switchingStyle>	1	</switchingStyle>
        </CMD_SHOW_TEAMS>
        <CMD_F2_CHAT_COMMAND>
          <FIRE_KEYS>
            <FIRE_KEY>
              <fireKeyName>KEY_F5</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
          </FIRE_KEYS>
          <fireAxisIndex>	-1	</fireAxisIndex>
          <fireAxisSign>	0	</fireAxisSign>
          <fireAxisDevice>	0	</fireAxisDevice>
          <isBase>	0	</isBase>
          <switchingStyle>	-1	</switchingStyle>
        </CMD_F2_CHAT_COMMAND>
        <CMD_F3_CHAT_COMMAND>
          <FIRE_KEYS>
            <FIRE_KEY>
              <fireKeyName>KEY_F6</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
          </FIRE_KEYS>
          <fireAxisIndex>	-1	</fireAxisIndex>
          <fireAxisSign>	0	</fireAxisSign>
          <fireAxisDevice>	0	</fireAxisDevice>
          <isBase>	0	</isBase>
          <switchingStyle>	-1	</switchingStyle>
        </CMD_F3_CHAT_COMMAND>
        <CMD_F4_CHAT_COMMAND>
          <FIRE_KEYS>
            <FIRE_KEY>
              <fireKeyName>KEY_F4</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
          </FIRE_KEYS>
          <fireAxisIndex>	-1	</fireAxisIndex>
          <fireAxisSign>	0	</fireAxisSign>
          <fireAxisDevice>	0	</fireAxisDevice>
          <isBase>	0	</isBase>
          <switchingStyle>	-1	</switchingStyle>
        </CMD_F4_CHAT_COMMAND>
        <CMD_F5_CHAT_COMMAND>
          <FIRE_KEYS>
            <FIRE_KEY>
              <fireKeyName>KEY_F7</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
          </FIRE_KEYS>
          <fireAxisIndex>	-1	</fireAxisIndex>
          <fireAxisSign>	0	</fireAxisSign>
          <fireAxisDevice>	0	</fireAxisDevice>
          <isBase>	0	</isBase>
          <switchingStyle>	-1	</switchingStyle>
        </CMD_F5_CHAT_COMMAND>
        <CMD_F6_CHAT_COMMAND>
          <FIRE_KEYS>
            <FIRE_KEY>
              <fireKeyName>KEY_F8</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
          </FIRE_KEYS>
          <fireAxisIndex>	-1	</fireAxisIndex>
          <fireAxisSign>	0	</fireAxisSign>
          <fireAxisDevice>	0	</fireAxisDevice>
          <isBase>	0	</isBase>
          <switchingStyle>	-1	</switchingStyle>
        </CMD_F6_CHAT_COMMAND>
        <CMD_F7_CHAT_COMMAND>
          <FIRE_KEYS>
            <FIRE_KEY>
              <fireKeyName>KEY_F9</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
          </FIRE_KEYS>
          <fireAxisIndex>	-1	</fireAxisIndex>
          <fireAxisSign>	0	</fireAxisSign>
          <fireAxisDevice>	0	</fireAxisDevice>
          <isBase>	0	</isBase>
          <switchingStyle>	-1	</switchingStyle>
        </CMD_F7_CHAT_COMMAND>
        <CMD_F8_CHAT_COMMAND>
          <FIRE_KEYS>
            <FIRE_KEY>
              <fireKeyName>KEY_F2</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
          </FIRE_KEYS>
          <fireAxisIndex>	-1	</fireAxisIndex>
          <fireAxisSign>	0	</fireAxisSign>
          <fireAxisDevice>	0	</fireAxisDevice>
          <isBase>	0	</isBase>
          <switchingStyle>	-1	</switchingStyle>
        </CMD_F8_CHAT_COMMAND>
        <CMD_F9_CHAT_COMMAND>
          <FIRE_KEYS>
            <FIRE_KEY>
              <fireKeyName>KEY_F3</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
            <FIRE_KEY>
              <fireKeyName>KEY_T</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
          </FIRE_KEYS>
          <fireAxisIndex>	-1	</fireAxisIndex>
          <fireAxisSign>	0	</fireAxisSign>
          <fireAxisDevice>	0	</fireAxisDevice>
          <isBase>	0	</isBase>
          <switchingStyle>	-1	</switchingStyle>
        </CMD_F9_CHAT_COMMAND>
        <CMD_HELP>
          <FIRE_KEYS>
            <FIRE_KEY>
              <fireKeyName>KEY_F1</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
          </FIRE_KEYS>
          <fireAxisIndex>	-1	</fireAxisIndex>
          <fireAxisSign>	0	</fireAxisSign>
          <fireAxisDevice>	0	</fireAxisDevice>
          <isBase>	0	</isBase>
          <switchingStyle>	1	</switchingStyle>
        </CMD_HELP>
        <CMD_FIRE_GROUP_1>
          <FIRE_KEYS>
            <FIRE_KEY>
              <fireKeyName>KEY_NONE</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
          </FIRE_KEYS>
          <fireAxisIndex>	-1	</fireAxisIndex>
          <fireAxisSign>	0	</fireAxisSign>
          <fireAxisDevice>	0	</fireAxisDevice>
          <isBase>	0	</isBase>
          <switchingStyle>	-1	</switchingStyle>
        </CMD_FIRE_GROUP_1>
        <CMD_FIRE_GROUP_2>
          <FIRE_KEYS>
            <FIRE_KEY>
              <fireKeyName>KEY_NONE</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
          </FIRE_KEYS>
          <fireAxisIndex>	-1	</fireAxisIndex>
          <fireAxisSign>	0	</fireAxisSign>
          <fireAxisDevice>	0	</fireAxisDevice>
          <isBase>	0	</isBase>
          <switchingStyle>	-1	</switchingStyle>
        </CMD_FIRE_GROUP_2>
        <CMD_FIRE_GROUP_3>
          <FIRE_KEYS>
            <FIRE_KEY>
              <fireKeyName>KEY_NONE</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
          </FIRE_KEYS>
          <fireAxisIndex>	-1	</fireAxisIndex>
          <fireAxisSign>	0	</fireAxisSign>
          <fireAxisDevice>	0	</fireAxisDevice>
          <isBase>	0	</isBase>
          <switchingStyle>	-1	</switchingStyle>
        </CMD_FIRE_GROUP_3>
        <CMD_AUTOPILOT>
          <FIRE_KEYS>
          </FIRE_KEYS>
          <fireAxisIndex>	-1	</fireAxisIndex>
          <fireAxisSign>	0	</fireAxisSign>
          <fireAxisDevice>	0	</fireAxisDevice>
          <isBase>	0	</isBase>
          <switchingStyle>	-1	</switchingStyle>
        </CMD_AUTOPILOT>
        <CMD_INTERMISSION_MENU>
          <FIRE_KEYS>
            <FIRE_KEY>
              <fireKeyName>KEY_ESCAPE</fireKeyName>
              <fireKeyDevice>	0	</fireKeyDevice>
            </FIRE_KEY>
          </FIRE_KEYS>
          <fireAxisIndex>	-1	</fireAxisIndex>
          <fireAxisSign>	0	</fireAxisSign>
          <fireAxisDevice>	0	</fireAxisDevice>
          <isBase>	0	</isBase>
          <switchingStyle>	-1	</switchingStyle>
        </CMD_INTERMISSION_MENU>
      </MAIN>
    </MAPPING>
  </KEYBOARD>
</gamepad_dc_1_xbox_360.xml> 

Может кто подскажет дельное что-нибудь.


Кстати, следующий месяц я буду очень занят семейными делами, соответственно могу быстро не отвечать. Но очень жду помощи и правильного направления от знающих и понимающих людей!

  • Upvote 1
  • Downvote 1
Link to comment
Short link
Share on other sites

По поводу разделения игры на два окна.

Я пользуюсь NoFrame для фиксации окна игры, единое что она не работает с вторым окном, ну вы поговорите с автором.

Link to comment
Short link
Share on other sites

По поводу разделения игры на два окна.

Я пользуюсь NoFrame для фиксации окна игры, единое что она не работает с вторым окном, ну вы поговорите с автором.

 

Отписывался я в этой теме. Правда, не пробовал с запущенным VDM два ока без рамок, нужно попробовать как то в свободное время. В теме есть ещё ссылка на relocator - которая почти такая же утилита. Пробовал ещё и её перекомпилировать под нужные параметры - результат нет. Мне очень не понравилась эта VDM - ломает как то стандартный виндовый интерфейс. Да и не совсем мне понятно почему в полноэкранном режиме можно выставить любое разрешение, а в окошке минимум 1024х768. Так что поиск решения идет.

 

Где то встречал что WarGaming используют какой то "прием" для ускорения вывода изображений и не используют стандартные WinAPI, поэтому уменьшение картинки работает только с VDM (мне кажется утилита использует такой же или похожий прием, но так как VDM стартует сразу в окнах - имеет больший приоритет). В той же теме автор говорил о том, что это может быть функции не WinAPI а DirectX - соответственно должна быть другая утилита.

 

Блин я их перепробовал уже столько, что и не вспомнишь все (самая лучшая Snap - Win+стрелка вправо/стрелка влево, стандартная фича Windows 7).

Edited by kharlashkin
  • Upvote 1
  • Downvote 1
Link to comment
Short link
Share on other sites

Сегодня пришла следующая идея в голову, выношу её на общее обсуждение - от этого будет зависеть стоит дальше искать решение предложенной мною модификации или нет:

Есть скрипт управления курсором

'scripts/client/gui/Cursor.pyс'

import BigWorld
import GUI
import Math
from debug_utils import *
from bwdebug import WARNING_MSG
_mouseModeRefCount = 0

def showCursor(show):
    global _mouseModeRefCount
    if show:
        _mouseModeRefCount += 1
        if _mouseModeRefCount > 0:
            BigWorld.setCursor(GUI.mcursor())
            GUI.mcursor().visible = True
    else:
        _mouseModeRefCount -= 1
        if _mouseModeRefCount == 0:
            BigWorld.setCursor(BigWorld.dcursor())
            GUI.mcursor().visible = False
        if _mouseModeRefCount < 0:
            WARNING_MSG('mouseModeRefCount is negative!')


def forceShowCursor(show):
    if show:
        BigWorld.setCursor(GUI.mcursor())
        GUI.mcursor().visible = True
    else:
        BigWorld.setCursor(BigWorld.dcursor())
        GUI.mcursor().visible = False


def pixelPosition():
    screenWidth, screenHeight = GUI.screenResolution()
    mouseLeft, mouseTop = GUI.mcursor().position
    width = round((1.0 + mouseLeft) / 2.0 * screenWidth)
    height = round(-(-1.0 + mouseTop) / 2.0 * screenHeight)
    return (width, height) 

 

Так же есть скрипты от самолетиков, реально написать тестовый скрипт для назначения правого стика геймпада (самолетные Оси 3 и 4)? Может кто сделать например за эквивалент месяца премиума?

  • Upvote 1
  • Downvote 1
Link to comment
Short link
Share on other sites

 

 

Может кто сделать например за эквивалент месяца премиума?
 

Наверное мало предложил ;) Может кто обосновать сумму необходимую?

  • Upvote 1
  • Downvote 1
Link to comment
Short link
Share on other sites

  • 2 weeks later...

Доброе время суток всем! Давно не заходил на форум, и смотрю моей темой не интересуется никто. Наверное действительно эта тема не интересна.

  • Downvote 1
Link to comment
Short link
Share on other sites

  • 2 weeks later...

Случайно наткнулся на утилиту AutoHotkey, которая стала для меня небольшим открытием, но думаю что очень многим форумчанам знакома не по наслышке. Даже нашелся скрипт для геймпада:

'JoyMouse.ahk'

; Increase the following value to make the mouse cursor move faster:
JoyMultiplier = 0.30

; Decrease the following value to require less joystick displacement-from-center
; to start moving the mouse.  However, you may need to calibrate your joystick
; -- ensuring it's properly centered -- to avoid cursor drift. A perfectly tight
; and centered joystick could use a value of 1:
JoyThreshold = 3

; Change the following to true to invert the Y-axis, which causes the mouse to
; move vertically in the direction opposite the stick:
InvertYAxis := false

; Change these values to use joystick button numbers other than 1, 2, and 3 for
; the left, right, and middle mouse buttons.  Available numbers are 1 through 32.
; Use the Joystick Test Script to find out your joystick's numbers more easily.
ButtonLeft = 1
ButtonRight = 2
ButtonMiddle = 3

; If your joystick has a POV control, you can use it as a mouse wheel.  The
; following value is the number of milliseconds between turns of the wheel.
; Decrease it to have the wheel turn faster:
WheelDelay = 250

; If your system has more than one joystick, increase this value to use a joystick
; other than the first:
JoystickNumber = 1

; END OF CONFIG SECTION -- Don't change anything below this point unless you want
; to alter the basic nature of the script.

#SingleInstance

JoystickPrefix = %JoystickNumber%Joy
Hotkey, %JoystickPrefix%%ButtonLeft%, ButtonLeft
Hotkey, %JoystickPrefix%%ButtonRight%, ButtonRight
Hotkey, %JoystickPrefix%%ButtonMiddle%, ButtonMiddle

; Calculate the axis displacements that are needed to start moving the cursor:
JoyThresholdUpper := 50 + JoyThreshold
JoyThresholdLower := 50 - JoyThreshold
if InvertYAxis
    YAxisMultiplier = -1
else
    YAxisMultiplier = 1

SetTimer, WatchJoystick, 10  ; Monitor the movement of the joystick.

GetKeyState, JoyInfo, %JoystickNumber%JoyInfo
IfInString, JoyInfo, P  ; Joystick has POV control, so use it as a mouse wheel.
    SetTimer, MouseWheel, %WheelDelay%

return  ; End of auto-execute section.


; The subroutines below do not use KeyWait because that would sometimes trap the
; WatchJoystick quasi-thread beneath the wait-for-button-up thread, which would
; effectively prevent mouse-dragging with the joystick.

ButtonLeft:
SetMouseDelay, -1  ; Makes movement smoother.
MouseClick, left,,, 1, 0, D  ; Hold down the left mouse button.
SetTimer, WaitForLeftButtonUp, 10
return

ButtonRight:
SetMouseDelay, -1  ; Makes movement smoother.
MouseClick, right,,, 1, 0, D  ; Hold down the right mouse button.
SetTimer, WaitForRightButtonUp, 10
return

ButtonMiddle:
SetMouseDelay, -1  ; Makes movement smoother.
MouseClick, middle,,, 1, 0, D  ; Hold down the right mouse button.
SetTimer, WaitForMiddleButtonUp, 10
return

WaitForLeftButtonUp:
if GetKeyState(JoystickPrefix . ButtonLeft)
    return  ; The button is still, down, so keep waiting.
; Otherwise, the button has been released.
SetTimer, WaitForLeftButtonUp, off
SetMouseDelay, -1  ; Makes movement smoother.
MouseClick, left,,, 1, 0, U  ; Release the mouse button.
return

WaitForRightButtonUp:
if GetKeyState(JoystickPrefix . ButtonRight)
    return  ; The button is still, down, so keep waiting.
; Otherwise, the button has been released.
SetTimer, WaitForRightButtonUp, off
MouseClick, right,,, 1, 0, U  ; Release the mouse button.
return

WaitForMiddleButtonUp:
if GetKeyState(JoystickPrefix . ButtonMiddle)
    return  ; The button is still, down, so keep waiting.
; Otherwise, the button has been released.
SetTimer, WaitForMiddleButtonUp, off
MouseClick, middle,,, 1, 0, U  ; Release the mouse button.
return

WatchJoystick:
MouseNeedsToBeMoved := false  ; Set default.
SetFormat, float, 03
GetKeyState, joyx, %JoystickNumber%JoyX
GetKeyState, joyy, %JoystickNumber%JoyY
if joyx > %JoyThresholdUpper%
{
    MouseNeedsToBeMoved := true
    DeltaX := joyx - JoyThresholdUpper
}
else if joyx < %JoyThresholdLower%
{
    MouseNeedsToBeMoved := true
    DeltaX := joyx - JoyThresholdLower
}
else
    DeltaX = 0
if joyy > %JoyThresholdUpper%
{
    MouseNeedsToBeMoved := true
    DeltaY := joyy - JoyThresholdUpper
}
else if joyy < %JoyThresholdLower%
{
    MouseNeedsToBeMoved := true
    DeltaY := joyy - JoyThresholdLower
}
else
    DeltaY = 0
if MouseNeedsToBeMoved
{
    SetMouseDelay, -1  ; Makes movement smoother.
    MouseMove, DeltaX * JoyMultiplier, DeltaY * JoyMultiplier * YAxisMultiplier, 0, R
}
return

MouseWheel:
GetKeyState, JoyPOV, %JoystickNumber%JoyPOV
if JoyPOV = -1  ; No angle.
    return
if (JoyPOV > 31500 or JoyPOV < 4500)  ; Forward
    Send {WheelUp}
else if JoyPOV between 13500 and 22500  ; Back
    Send {WheelDown}
return 

 

Интересно вот что, сможет ли AutoHotkey принимать значения от 2-х геймпадов и отдавать разным окнам (двум клиентам WoT) значения клавиатуры/мыши? Может кто более детально использовал эту утилиту, подскажет мне...


Небольшое гугление - AutoHotkey: отправка нажатий клавиш в неактивное окно. Надо более детально изучить.


Проверил тестовым скриптом отправку нажатий клавиш в неактивное окно клиента WoT. Окошко команды принимает, но отрабатывает только тогда, когда окно становится активным. Т.е. окно не активно, я нажимаю WASD, переключаюсь в окно клиента и вижу нажатия кнопок WASD.


Необходимо заставить игру воспринимать команды из вне. Может быть даже через веб-сервис, думаю что задержки до 50 мс были бы приемлемы.

'scripts/client/gui/InputHandler.pyс'

import Event
g_instance = None

class _InputHandler:
    onKeyDown = Event.Event()
    onKeyUp = Event.Event()

    def handleKeyEvent(self, event):
        if event.isKeyDown():
            self.onKeyDown(event)
        else:
            self.onKeyUp(event)


g_instance = _InputHandler() 

 

Может это поможет понимающим людям понять как игра отрабатывает нажатия клавиш и можно будет туда добавить дополнительный обработчик.

Edited by kharlashkin
  • Upvote 1
  • Downvote 1
Link to comment
Short link
Share on other sites

Пробовал через AutoHotkey отправлять в pid процесса нажатие клавиши "W", чтобы в неактивном окне танк ехал вперед. Блин и один раз он таки поехал ;) Но при переключении между окнами перестал ;( С чем связано - не знаю... Ниже выкладываю на обсуждение скрипт.

'test.ahk'

w:: 
WinGet, wot, PID, WoT Client
ControlSend,, {sc11 Down}, ahk_pid %wot%
KeyWait, w
ControlSend,, {sc11 Up}, ahk_pid %wot%
Return 


Повторил второй раз проезд танка. Если нажать в бой и переключится в другое окно (в момент загрузки), после отсчета и прочего отправка клавиш работает. ХЗ от чего зависит.

Edited by kharlashkin
  • Downvote 1
Link to comment
Short link
Share on other sites

Guest
This topic is now closed to further replies.
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...