Skip to content

logitech

Classes:

Name Description
LogitechDevice

General Logitech device.

LogitechDevice

General Logitech device.

General Logitech device.

Parameters:

Name Type Description Default

parser

ProtocolParser

DCS-BIOS parser instance

required

sock

socket

multicast UDP socket

required

model

LogitechDeviceModel

device model

required

Methods:

Name Description
button_handle

Button handler.

check_buttons

Check if a button was pressed and return its enum.

clear

Clear LCD.

detecting_plane

Try to detect airplane base on value received from DCS-BIOS.

display

Display a message as an image at LCD.

gkey_callback_handler

Logitech G-Key callback handler.

load_new_plane

Dynamic load of new detected aircraft.

unload_old_plane

Unloads the previous plane by remove all callbacks and keep only one.

Attributes:

Name Type Description
messages list[str]

Get the text messages without the tittle from LCD.

text list[tuple[str, Color]]

Get the latest text from LCD.

Source code in src/dcspy/logitech.py
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
def __init__(self, parser: dcsbios.ProtocolParser, sock: socket, model: LogitechDeviceModel) -> None:
    """
    General Logitech device.

    :param parser: DCS-BIOS parser instance
    :param sock: multicast UDP socket
    :param model: device model
    """
    dcsbios.StringBuffer(parser=parser, address=0x0, max_length=0x10, callback=partial(self.detecting_plane))
    self.parser = parser
    self.socket = sock
    self.plane_name = ''
    self.bios_name = ''
    self.plane_detected = False
    self.lcd_button_pressed = False
    self._text: list[tuple[str, Color]] = []
    self.model = model
    self.lcd_sdk = lcd_sdk.LcdSdkManager(name='DCS World', lcd_type=self.model.lcd_info.type)
    self.key_sdk = key_sdk.GkeySdkManager(self.gkey_callback_handler)
    success = self.key_sdk.logi_gkey_init()
    LOG.debug(f'G-Key is connected: {success}')
    self.plane = BasicAircraft(self.model.lcd_info)

messages property

messages: list[str]

Get the text messages without the tittle from LCD.

Returns:

Type Description
list[str]

List of strings with data, row by row

text property writable

text: list[tuple[str, Color]]

Get the latest text from LCD.

Returns:

Type Description
list[tuple[str, Color]]

List of strings with data, row by row

button_handle

button_handle() -> None

Button handler.

  • Detect if a button was pressed
  • Sent action to DCS-BIOS via network socket
Source code in src/dcspy/logitech.py
183
184
185
186
187
188
189
190
191
192
193
def button_handle(self) -> None:
    """
    Button handler.

    * Detect if a button was pressed
    * Sent action to DCS-BIOS via network socket
    """
    if self.model.lcd_info.type != LcdType.NONE:
        button = self.check_buttons()
        if button.value:
            self._send_request(button=button, key_down=KEY_DOWN)

check_buttons

check_buttons() -> LcdButton

Check if a button was pressed and return its enum.

Returns:

Type Description
LcdButton

LcdButton enum of pressed button

Source code in src/dcspy/logitech.py
168
169
170
171
172
173
174
175
176
177
178
179
180
181
def check_buttons(self) -> LcdButton:
    """
    Check if a button was pressed and return its enum.

    :return: LcdButton enum of pressed button
    """
    for lcd_btn in self.model.lcd_keys:
        if self.lcd_sdk.logi_lcd_is_button_pressed(lcd_btn):
            if not self.lcd_button_pressed:
                self.lcd_button_pressed = True
                return LcdButton(lcd_btn)
            return LcdButton.NONE
    self.lcd_button_pressed = False
    return LcdButton.NONE

clear

clear(true_clear: bool = False) -> None

Clear LCD.

Parameters:

Name Type Description Default

true_clear

bool
False
Source code in src/dcspy/logitech.py
208
209
210
211
212
213
214
215
216
def clear(self, true_clear: bool = False) -> None:
    """
    Clear LCD.

    :param true_clear:
    """
    if self.model.lcd_info.type != LcdType.NONE:
        LOG.debug(f'Clear LCD type: {self.model.lcd_info.type} with: {true_clear=}')
        self.lcd_sdk.clear_display(true_clear)

detecting_plane

detecting_plane(value: str) -> None

Try to detect airplane base on value received from DCS-BIOS.

Parameters:

Name Type Description Default

value

str

Data from DCS-BIOS

required
Source code in src/dcspy/logitech.py
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
def detecting_plane(self, value: str) -> None:
    """
    Try to detect airplane base on value received from DCS-BIOS.

    :param value: Data from DCS-BIOS
    """
    short_name = value.replace('-', '').replace('_', '')
    if self.plane_name != short_name:
        self.plane_name = short_name
        planes_list = get_planes_list(bios_dir=Path(get_config_yaml_item('dcsbios')))
        if self.plane_name in SUPPORTED_CRAFTS:
            LOG.info(f'Advanced supported aircraft: {value}')
            self.text = [('     DCSpy       ', Color.orange), ('Detected aircraft:', Color.white), (SUPPORTED_CRAFTS[self.plane_name]['name'], Color.green)]
            self.plane_detected = True
        elif self.plane_name not in SUPPORTED_CRAFTS and value in planes_list:
            LOG.info(f'Basic supported aircraft: {value}')
            self.bios_name = value
            self.text = [('     DCSpy       ', Color.orange), ('Detected aircraft:', Color.white), (value, Color.green)]
            self.plane_detected = True
        elif value not in planes_list:
            LOG.warning(f'Not supported aircraft: {value}')
            self.text = [('     DCSpy       ', Color.orange), ('Detected aircraft:', Color.white), (value, Color.green), ('Not supported yet!', Color.red)]

display

display() -> None

Display a message as an image at LCD.

For G13/G15/G510 takes the first four (4) or fewer elements of a list and display as four (4) rows. For G19 takes the first eight (8) or fewer elements of the list and display as eight (8) rows.

Source code in src/dcspy/logitech.py
80
81
82
83
84
85
86
87
88
def display(self) -> None:
    """
    Display a message as an image at LCD.

    For G13/G15/G510 takes the first four (4) or fewer elements of a list and display as four (4) rows.
    For G19 takes the first eight (8) or fewer elements of the list and display as eight (8) rows.
    """
    if self.model.lcd_info.type != LcdType.NONE:
        self.lcd_sdk.update_display(self._prepare_image())

gkey_callback_handler

gkey_callback_handler(
    key_idx: int, mode: int, key_down: int, mouse: int
) -> None

Logitech G-Key callback handler.

Send action to DCS-BIOS via network socket.

Parameters:

Name Type Description Default

key_idx

int

Index number of G-Key

required

mode

int

Mode of G-Key

required

key_down

int

Key state, one (1) - pressed, zero (0) - released

required

mouse

int

Indicate if the Event comes from a mouse, one (1) is yes, zro (0) is no

required
Source code in src/dcspy/logitech.py
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
def gkey_callback_handler(self, key_idx: int, mode: int, key_down: int, mouse: int) -> None:
    """
    Logitech G-Key callback handler.

    Send action to DCS-BIOS via network socket.

    :param key_idx: Index number of G-Key
    :param mode: Mode of G-Key
    :param key_down: Key state, one (1) - pressed, zero (0) - released
    :param mouse: Indicate if the Event comes from a mouse, one (1) is yes, zro (0) is no

    """
    key = Gkey(key=key_idx, mode=mode)
    if mouse:
        key = MouseButton(button=key_idx)  # type: ignore[assignment]
    LOG.debug(f'Button {key} is pressed, key down: {key_down}')
    self._send_request(button=key, key_down=key_down)

load_new_plane

load_new_plane() -> None

Dynamic load of new detected aircraft.

Set up callbacks for detected plane inside DCS-BIOS parser.

Source code in src/dcspy/logitech.py
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
def load_new_plane(self) -> None:
    """
    Dynamic load of new detected aircraft.

    Set up callbacks for detected plane inside DCS-BIOS parser.
    """
    self.plane_detected = False
    if self.plane_name in SUPPORTED_CRAFTS:
        self.clear(true_clear=True)
        lcd_update_func = self.lcd_sdk.update_display if self.model.lcd_info.type != LcdType.NONE else None
        self.plane = getattr(import_module('dcspy.aircraft'), self.plane_name)(self.model.lcd_info, update_display=lcd_update_func)
        LOG.debug(f'Dynamic load of: {self.plane_name} as AdvancedAircraft | BIOS: {self.plane.bios_name}')
        self._setup_plane_callback()
    else:
        self.plane = MetaAircraft(self.plane_name, (BasicAircraft,), {})(self.model.lcd_info)
        self.plane.bios_name = self.bios_name
        LOG.debug(f'Dynamic load of: {self.plane_name} as BasicAircraft | BIOS: {self.plane.bios_name}')
    LOG.debug(f'{repr(self)}')

unload_old_plane

unload_old_plane() -> None

Unloads the previous plane by remove all callbacks and keep only one.

Source code in src/dcspy/logitech.py
113
114
115
116
117
118
119
120
121
def unload_old_plane(self) -> None:
    """Unloads the previous plane by remove all callbacks and keep only one."""
    LOG.debug(f'Unload start: {self.plane_name} Number of callbacks: {len(self.parser.write_callbacks)}')
    for partial_obj in self.parser.write_callbacks:
        for callback in partial_obj.func.__self__.callbacks:  # type: ignore[attr-defined]
            if callback.func.__name__ == 'detecting_plane':
                self.parser.write_callbacks = {partial_obj}
        if len(self.parser.write_callbacks) == 1:
            break