Skip to content

Commit

Permalink
First public release
Browse files Browse the repository at this point in the history
  • Loading branch information
berarma committed Feb 19, 2019
0 parents commit 956f6d5
Show file tree
Hide file tree
Showing 6 changed files with 1,434 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
__pycache__
674 changes: 674 additions & 0 deletions LICENSE

Large diffs are not rendered by default.

18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Oversteer - Steering Wheel Manager for Linux

Graphical application to configure Logitech Wheels.

This software uses the Linux driver for Logitech HID++ devices and thus it
could work on any model supported by said driver.

It's only been tested on the Logitech G29 Driving Force. It could work on other
models but it has been untested.

Please, use at your own risk. Suggestions, bugs and pull requests welcome.

## Installation

For now, it lacks a convenient installation method.

Download and run ```./oversteer.py```.

202 changes: 202 additions & 0 deletions oversteer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
#!/usr/bin/python3

import argparse
import configparser
import gi
import glob
import signal
import subprocess
import sys
from wheels import Wheels
from xdg.BaseDirectory import *

gi.require_version('Gtk', '3.0')

from gi.repository import Gtk

class OversteerUi:

def __init__(self):
signal.signal(signal.SIGINT, self.sig_int_handler)

self.config_path = save_config_path('oversteer')
self.profile_path = os.path.join(self.config_path, 'profiles')
if not os.path.isdir(self.profile_path):
os.makedirs(self.profile_path, 0o700)
self.saved_profile = None

self.builder = Gtk.Builder()
self.builder.add_from_file('ui.glade')
self.builder.connect_signals(self)
self.window = self.builder.get_object('main_window')
self.window.show_all()

self.device_combobox = self.builder.get_object('device')
self.profile_combobox = self.builder.get_object('profile')
self.save_profile_entry = self.builder.get_object('save_profile')
self.emulation_mode_combobox = self.builder.get_object('emulation_mode')
self.wheel_range = self.builder.get_object('wheel_range')
self.combine_pedals = self.builder.get_object('combine_pedals')

cell_renderer = Gtk.CellRendererText()
self.device_combobox.pack_start(cell_renderer, True)
self.device_combobox.add_attribute(cell_renderer, 'text', 1)
self.device_combobox.set_id_column(0)

cell_renderer = Gtk.CellRendererText()
self.profile_combobox.pack_start(cell_renderer, True)
self.profile_combobox.add_attribute(cell_renderer, 'text', 1)
self.profile_combobox.set_id_column(0)

cell_renderer = Gtk.CellRendererText()
self.emulation_mode_combobox.pack_start(cell_renderer, True)
self.emulation_mode_combobox.add_attribute(cell_renderer, 'text', 1)
self.emulation_mode_combobox.set_id_column(0)

self.wheels = Wheels()
self.refresh_window()

Gtk.main()

def refresh_window(self):
model = self.device_combobox.get_model()
if model == None:
model = Gtk.ListStore(str, str)
else:
self.device_combobox.set_model(None)
model.clear()
for pair in self.wheels.get_devices():
model.append(pair)
self.device_combobox.set_model(model)
self.device_combobox.set_active(0)

model = self.profile_combobox.get_model()
if model == None:
model = Gtk.ListStore(str, str)
else:
self.profile_combobox.set_model(None)
model.clear()
model.append(['', ''])
for profile_file in glob.iglob(os.path.join(self.profile_path, "*.ini")):
profile_name = os.path.splitext(os.path.basename(profile_file))[0]
model.append([profile_file, profile_name])
self.profile_combobox.set_model(model)

if self.saved_profile != None:
self.profile_combobox.set_active_id(self.saved_profile)
self.saved_profile = None

def on_destroy(self, *args):
Gtk.main_quit()

def sig_int_handler(self, signal, frame):
sys.exit(0)

def on_about_clicked(self, *args):
self.about_window = self.builder.get_object("about_window")
self.about_window.show()

def on_about_window_response(self, *args):
self.about_window.hide()

def format_wheel_range_value(self, scale, value):
return round(value * 10)

def on_device_changed(self, combobox):
device_id = combobox.get_active_id()
model = self.emulation_mode_combobox.get_model()
if model == None:
model = Gtk.ListStore(str, str)
else:
self.emulation_mode_combobox.set_model(None)
model.clear()
for key, values in enumerate(self.wheels.get_alternate_modes(device_id)):
model.append(values[:2])
if values[2]:
self.emulation_mode_combobox.set_active(key)
self.emulation_mode_combobox.set_model(model)

self.wheel_range.set_value(self.wheels.get_range(device_id) / 10)

self.combine_pedals.set_state(self.wheels.get_combine_pedals(device_id))

def on_profile_changed(self, combobox):
profile_path = combobox.get_active_id()
if profile_path != '':
config = configparser.ConfigParser()
config.read(profile_path)
self.emulation_mode_combobox.set_active_id(config['default']['mode'])
self.wheel_range.set_value(int(config['default']['range']) / 10)
self.combine_pedals.set_state(True if config['default']['combine_pedals'] == 'True' else False)
self.save_profile_entry.set_text(os.path.splitext(os.path.basename(profile_path))[0])

def on_update_clicked(self, button):
self.refresh_window()

def on_test_clicked(self, button):
subprocess.call("jstest-gtk")

def on_apply_clicked(self, button):
device_id = self.device_combobox.get_active_id()
mode = self.emulation_mode_combobox.get_active_id()
range = int(self.wheel_range.get_value() * 10)
combine_pedals = self.combine_pedals.get_state()
if self.wheels.is_read_only(device_id):
subprocess.call([
'gksudo',
'--description', 'Wheel Manager',
'--',
sys.argv[0],
'--mode', mode,
'--range', str(range),
'--combine-pedals' if combine_pedals else '--no-combine-pedals',
str(device_id)])
else:
self.wheels.set_mode(device_id, mode)
self.wheels.set_range(device_id, range)
self.wheels.set_combine_pedals(device_id, combine_pedals)

profile_name = self.save_profile_entry.get_text()
if profile_name != '':
config = configparser.ConfigParser()
config['default'] = {
'mode': mode,
'range': range,
'combine_pedals': combine_pedals
}
profile_file = os.path.join(self.profile_path, profile_name + '.ini')
with open(profile_file, 'w') as configfile:
config.write(configfile)
self.saved_profile = profile_file;

self.wheels = Wheels()
self.refresh_window()

self.device_combobox.set_active_id(device_id)

if len(sys.argv) == 1:
OversteerUi()
else:
parser = argparse.ArgumentParser(description="Oversteer - Steering Wheel Manager")
parser.add_argument('device_id', help="Device id")
parser.add_argument('--list', action='store_true', help="List devices")
parser.add_argument('--mode', help="Wheel mode")
parser.add_argument('--range', type=int, help="Rotation range")
parser.add_argument('--combine-pedals', action='store_true', help="Combine pedals")
parser.add_argument('--no-combine-pedals', action='store_false')

args = parser.parse_args()

wheels = Wheels()

device_id = args.device_id

if args.mode != None:
wheels.set_mode(device_id, args.mode)
if args.range != None:
wheels.set_range(device_id, args.range)
if args.combine_pedals != None:
wheels.set_combine_pedals(device_id, args.combine_pedals)

sys.exit(0)

Loading

0 comments on commit 956f6d5

Please sign in to comment.