Azbuka Posted March 19, 2014 Share Posted March 19, 2014 @kharlashkin, Эх, я б вам помог, если бы знал пайтон... Но если будет необходимость в exe'шках и dll'ках, то пишите мне, я помогу. Лучше поспрашивайте на форумах по пайтону. Я уверен, что среди програмистов должны быть любители танков. 2 @ Link to comment Short link Share on other sites More sharing options...
kharlashkin Posted March 19, 2014 Author Share Posted March 19, 2014 (edited) @kharlashkin, Эх, я б вам помог, если бы знал пайтон... Но если будет необходимость в exe'шках и dll'ках, то пишите мне, я помогу. Лучше поспрашивайте на форумах по пайтону. Я уверен, что среди програмистов должны быть любители танков. Спасибо за поддержку . В принципе, по логике вещей, ответ где-то рядом. Мое видение данного мода такое - таким же образом как в "вибромоде" вызываем системный python, с помощью pygame берем данные о нажатии кнопок/перемещении стиков, переназначаем их в соответствии с управлением в игре (я довольно долго экспериментировал с удобством игры на геймпаде - моя тема на оф.форуме), и отдаем команды непосредственно в игру. Вот с последним моментом пока проблема - ищу. Edited March 19, 2014 by kharlashkin 2 1 @ Link to comment Short link Share on other sites More sharing options...
Azbuka Posted March 19, 2014 Share Posted March 19, 2014 (edited) отдаем команды непосредственно в игру. Вот с последним моментом пока проблема Быть может, что worldoftanks.exe сам обрабатывает нажатия кнопок. Edited March 19, 2014 by Azbuka_slovensko 2 @ Link to comment Short link Share on other sites More sharing options...
kharlashkin Posted March 19, 2014 Author Share Posted March 19, 2014 Быть может, что worldoftanks.exe сам обрабатывает нажатия кнопок.Да пусть обрабатывает, нужно чтобы он правильно обрабатывал - нужные нажатия, а не все подряд. 2 1 @ Link to comment Short link Share on other sites More sharing options...
kharlashkin Posted March 20, 2014 Author Share Posted March 20, 2014 Скрипт 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, говорил о добавлении отдельных методов, не трогая оригинальные скрипты. Возможно сюда стоит добавить метод который будет брать значения кнопок/стиков/триггеров и предоставлять их как кнопки клавиатуры/мыши. 1 1 @ Link to comment Short link Share on other sites More sharing options...
psix_banned Posted March 21, 2014 Share Posted March 21, 2014 (edited) На просторах интернета нашел вот такую вещь. Multiзапуск Edited March 21, 2014 by psix89 Link to comment Short link Share on other sites More sharing options...
kharlashkin Posted March 22, 2014 Author Share Posted March 22, 2014 На просторах интернета нашел вот такую вещь. Multiзапуск Если не внимательно читали, то проблем с запуском двух клиентов WoT у меня нет. Но все равно спасибо! Кстати, пришел к одному выводу - можно попробовать сделать это все "малой кровью". Относительно вывода двух окон было сообщение в самом начале (цена вопроса 35$), все управление вторым танком можно повесить на клавиатуру (без мыши), кнопок на клавиатуре больше чем в игре используется - хватит, Xpadder поддерживает одновременно много геймпадов, мод вибрации перепишу специально для второго экземпляра игры - второй геймпад. В итоге можно сказать, что проблема решена. По моему мнению, это корявое и временное решение все равно надо опробовать - по результатам отпишусь. 1 1 @ Link to comment Short link Share on other sites More sharing options...
kharlashkin Posted March 24, 2014 Author Share Posted March 24, 2014 (edited) Убил вечер, но есть некоторые результаты которыми стоит поделиться. Ниже скриншот успехов ;) Итак по порядку. 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 March 25, 2014 by kharlashkin 1 1 @ Link to comment Short link Share on other sites More sharing options...
kharlashkin Posted March 25, 2014 Author Share Posted March 25, 2014 Пока не нашел в скриптах где-то ещё изменение минимального разрешения. Выкладываю тут скрипты снова (с измененными минимальными значениями): '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 значениями. Подскажите где подчистить чтобы эта проверка не проходила. 1 1 @ Link to comment Short link Share on other sites More sharing options...
kharlashkin Posted March 27, 2014 Author Share Posted March 27, 2014 (edited) Сделал перерыв небольшой (голова пухнет от непонимания, что надо делать). Надо доставать опять книги по 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 March 27, 2014 by kharlashkin 2 1 @ Link to comment Short link Share on other sites More sharing options...
vlad_cs_sr Posted March 27, 2014 Share Posted March 27, 2014 (edited) Блин, прямо руки опускаются - неужели те, кто знает и понимает python не хочет помочь, хоть советом, хоть направлением, хоть куском кода. Не бросайте, я уверен, заинтересованные найдутся, помогут)) Edited March 27, 2014 by leecher88 1 1 @ Link to comment Short link Share on other sites More sharing options...
kharlashkin Posted March 28, 2014 Author Share Posted March 28, 2014 (edited) Оказывается WoT принимает команды от геймпада почти "по-умолчанию". Спасибо inj3ct0r (я тебе должен) - подсказал как это проверить и дал скрипт, для отлавливания нажатий клавиш в ангаре с выводом системных сообщений. Подключив геймпад к ноутбуку и жмакая кнопки увидел что игра принимает почти все нажатия, кроме крестовины и отклонения правого стика. В качестве пробы добавил кнопки в файл preferences.xml, как указано в этой теме на оф.форуме. В итоге - кнопки с геймпада действительно можно установить в качестве клавиш управления. Теперь копаю скрипты из WoWP, там же геймпад полноценно поддерживается. К сожалению, дело к ночи - к тому же для полноценной пробы нужен второй "фанатик" (типа меня). В связи с этим управление пока не настраивал - надо к этому серьезно подойти. Игра понимает только ввод данных из активного окна, разумеется когда два окна рядом одно из них будет активным, второе нет. Из-за этого и не пробовал данную теорию. Edited March 28, 2014 by kharlashkin 1 1 @ Link to comment Short link Share on other sites More sharing options...
kharlashkin Posted March 31, 2014 Author Share Posted March 31, 2014 Доброе время суток! Мне (и не только мне) кажется. что тем способом, каким работает вибрация - нормально подключить геймпад не получиться. Клиент-серверная архитектура будет не так быстро работать, на вибрацию тайм-аут стоит 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> Может кто подскажет дельное что-нибудь. Кстати, следующий месяц я буду очень занят семейными делами, соответственно могу быстро не отвечать. Но очень жду помощи и правильного направления от знающих и понимающих людей! 1 1 @ Link to comment Short link Share on other sites More sharing options...
Beliy.IV Posted March 31, 2014 Share Posted March 31, 2014 По поводу разделения игры на два окна. Я пользуюсь NoFrame для фиксации окна игры, единое что она не работает с вторым окном, ну вы поговорите с автором. Link to comment Short link Share on other sites More sharing options...
kharlashkin Posted March 31, 2014 Author Share Posted March 31, 2014 (edited) По поводу разделения игры на два окна. Я пользуюсь NoFrame для фиксации окна игры, единое что она не работает с вторым окном, ну вы поговорите с автором. Отписывался я в этой теме. Правда, не пробовал с запущенным VDM два ока без рамок, нужно попробовать как то в свободное время. В теме есть ещё ссылка на relocator - которая почти такая же утилита. Пробовал ещё и её перекомпилировать под нужные параметры - результат нет. Мне очень не понравилась эта VDM - ломает как то стандартный виндовый интерфейс. Да и не совсем мне понятно почему в полноэкранном режиме можно выставить любое разрешение, а в окошке минимум 1024х768. Так что поиск решения идет. Где то встречал что WarGaming используют какой то "прием" для ускорения вывода изображений и не используют стандартные WinAPI, поэтому уменьшение картинки работает только с VDM (мне кажется утилита использует такой же или похожий прием, но так как VDM стартует сразу в окнах - имеет больший приоритет). В той же теме автор говорил о том, что это может быть функции не WinAPI а DirectX - соответственно должна быть другая утилита. Блин я их перепробовал уже столько, что и не вспомнишь все (самая лучшая Snap - Win+стрелка вправо/стрелка влево, стандартная фича Windows 7). Edited March 31, 2014 by kharlashkin 1 1 @ Link to comment Short link Share on other sites More sharing options...
kharlashkin Posted April 3, 2014 Author Share Posted April 3, 2014 Сегодня пришла следующая идея в голову, выношу её на общее обсуждение - от этого будет зависеть стоит дальше искать решение предложенной мною модификации или нет: Есть скрипт управления курсором '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)? Может кто сделать например за эквивалент месяца премиума? 1 1 @ Link to comment Short link Share on other sites More sharing options...
kharlashkin Posted April 8, 2014 Author Share Posted April 8, 2014 Может кто сделать например за эквивалент месяца премиума? Наверное мало предложил ;) Может кто обосновать сумму необходимую? 1 1 @ Link to comment Short link Share on other sites More sharing options...
kharlashkin Posted April 21, 2014 Author Share Posted April 21, 2014 Доброе время суток всем! Давно не заходил на форум, и смотрю моей темой не интересуется никто. Наверное действительно эта тема не интересна. 1 @ Link to comment Short link Share on other sites More sharing options...
kharlashkin Posted April 29, 2014 Author Share Posted April 29, 2014 (edited) Случайно наткнулся на утилиту 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 April 29, 2014 by kharlashkin 1 1 @ Link to comment Short link Share on other sites More sharing options...
kharlashkin Posted April 30, 2014 Author Share Posted April 30, 2014 (edited) Пробовал через 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 April 30, 2014 by kharlashkin 1 @ Link to comment Short link Share on other sites More sharing options...
Recommended Posts